|
@@ -22,19 +22,90 @@
|
|
*/
|
|
*/
|
|
const { _converse } = this;
|
|
const { _converse } = this;
|
|
|
|
|
|
|
|
+ function onDiscoItems (stanza) {
|
|
|
|
+ _.each(stanza.querySelectorAll('query item'), (item) => {
|
|
|
|
+ if (item.getAttribute("node")) {
|
|
|
|
+ // XXX: ignore nodes for now.
|
|
|
|
+ // See: https://xmpp.org/extensions/xep-0030.html#items-nodes
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ const jid = item.getAttribute('jid');
|
|
|
|
+ const entities = _converse.disco_entities;
|
|
|
|
+ if (_.isUndefined(entities.get(jid))) {
|
|
|
|
+ entities.create({'jid': jid});
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
// Promises exposed by this plugin
|
|
// Promises exposed by this plugin
|
|
_converse.api.promises.add('discoInitialized');
|
|
_converse.api.promises.add('discoInitialized');
|
|
|
|
|
|
_converse.DiscoEntity = Backbone.Model.extend({
|
|
_converse.DiscoEntity = Backbone.Model.extend({
|
|
/* A Disco Entity is a JID addressable entity that can be queried
|
|
/* A Disco Entity is a JID addressable entity that can be queried
|
|
* for features.
|
|
* for features.
|
|
|
|
+ *
|
|
* See XEP-0030: https://xmpp.org/extensions/xep-0030.html
|
|
* See XEP-0030: https://xmpp.org/extensions/xep-0030.html
|
|
*/
|
|
*/
|
|
- initialize (settings) {
|
|
|
|
- if (_.isNil(settings.jid)) {
|
|
|
|
- throw new Error('DiscoEntity must be instantiated with a JID');
|
|
|
|
|
|
+ idAttribute: 'jid',
|
|
|
|
+
|
|
|
|
+ initialize () {
|
|
|
|
+ this.features = new Backbone.Collection();
|
|
|
|
+ this.features.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
|
|
|
+ b64_sha1(`converse.features-${this.get('jid')}`)
|
|
|
|
+ );
|
|
|
|
+ this.features.on('add', this.onFeatureAdded);
|
|
|
|
+
|
|
|
|
+ this.identities = new Backbone.Collection();
|
|
|
|
+ this.identities.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
|
|
|
+ b64_sha1(`converse.identities-${this.get('jid')}`)
|
|
|
|
+ );
|
|
|
|
+ this.fetchFeatures();
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ onFeatureAdded (feature) {
|
|
|
|
+ _converse.emit('serviceDiscovered', feature);
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ fetchFeatures () {
|
|
|
|
+ if (this.features.browserStorage.records.length === 0) {
|
|
|
|
+ this.queryInfo();
|
|
|
|
+ } else {
|
|
|
|
+ this.features.fetch({add: true});
|
|
|
|
+ this.identities.fetch({add: true});
|
|
}
|
|
}
|
|
- this.features = new _converse.Features({'jid': settings.jid});
|
|
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ queryInfo () {
|
|
|
|
+ _converse.connection.disco.info(this.get('jid'), null, this.onInfo.bind(this));
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ queryForItems () {
|
|
|
|
+ if (_.isEmpty(this.identities.where({'category': 'server'})) &&
|
|
|
|
+ _.isEmpty(this.identities.where({'category': 'conference'}))) {
|
|
|
|
+ // Don't fetch features and items if this is not a
|
|
|
|
+ // server or a conference component.
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ _converse.connection.disco.items(this.get('jid'), null, onDiscoItems);
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ onInfo (stanza) {
|
|
|
|
+ _.forEach(stanza.querySelectorAll('identity'), (identity) => {
|
|
|
|
+ this.identities.create({
|
|
|
|
+ 'category': identity.getAttribute('category'),
|
|
|
|
+ 'type': stanza.getAttribute('type'),
|
|
|
|
+ 'name': stanza.getAttribute('name')
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ if (stanza.querySelector('feature[var="'+Strophe.NS.DISCO_ITEMS+'"]')) {
|
|
|
|
+ this.queryForItems();
|
|
|
|
+ }
|
|
|
|
+ _.forEach(stanza.querySelectorAll('feature'), (feature) => {
|
|
|
|
+ this.features.create({
|
|
|
|
+ 'var': feature.getAttribute('var'),
|
|
|
|
+ 'from': stanza.getAttribute('from')
|
|
|
|
+ });
|
|
|
|
+ });
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
@@ -56,14 +127,8 @@
|
|
this.fetch({
|
|
this.fetch({
|
|
add: true,
|
|
add: true,
|
|
success: function (collection) {
|
|
success: function (collection) {
|
|
- if (collection.length === 0) {
|
|
|
|
- /* The sessionStorage is empty */
|
|
|
|
- // TODO: check for domain in collection even if
|
|
|
|
- // not empty
|
|
|
|
- this.create({
|
|
|
|
- 'id': _converse.domain,
|
|
|
|
- 'jid': _converse.domain
|
|
|
|
- });
|
|
|
|
|
|
+ if (collection.length === 0 || !collection.get(_converse.domain)) {
|
|
|
|
+ this.create({'jid': _converse.domain});
|
|
}
|
|
}
|
|
resolve();
|
|
resolve();
|
|
}.bind(this),
|
|
}.bind(this),
|
|
@@ -75,95 +140,29 @@
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
- _converse.Features = Backbone.Collection.extend({
|
|
|
|
- /* Service Discovery
|
|
|
|
- * -----------------
|
|
|
|
- * This collection stores Feature Models, representing features
|
|
|
|
- * provided by available XMPP entities (e.g. servers)
|
|
|
|
- * See XEP-0030 for more details: http://xmpp.org/extensions/xep-0030.html
|
|
|
|
- * All features are shown here: http://xmpp.org/registrar/disco-features.html
|
|
|
|
- */
|
|
|
|
- model: Backbone.Model,
|
|
|
|
-
|
|
|
|
- initialize (settings) {
|
|
|
|
- const jid = settings.jid;
|
|
|
|
- if (_.isNil(jid)) {
|
|
|
|
- throw new Error('DiscoEntity must be instantiated with a JID');
|
|
|
|
- }
|
|
|
|
- this.addClientIdentities().addClientFeatures();
|
|
|
|
- this.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
|
|
|
- b64_sha1(`converse.features-${jid}`)
|
|
|
|
- );
|
|
|
|
- this.on('add', this.onFeatureAdded, this);
|
|
|
|
- this.fetchFeatures(jid);
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- fetchFeatures (jid) {
|
|
|
|
- if (this.browserStorage.records.length === 0) {
|
|
|
|
- // browserStorage is empty, so we've likely never queried this
|
|
|
|
- // domain for features yet
|
|
|
|
- _converse.connection.disco.info(jid, null, this.onInfo.bind(this));
|
|
|
|
- _converse.connection.disco.items(jid, null, this.onItems.bind(this));
|
|
|
|
- } else {
|
|
|
|
- this.fetch({add:true});
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- onFeatureAdded (feature) {
|
|
|
|
- _converse.emit('serviceDiscovered', feature);
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- addClientIdentities () {
|
|
|
|
- /* See http://xmpp.org/registrar/disco-categories.html
|
|
|
|
- */
|
|
|
|
- _converse.connection.disco.addIdentity('client', 'web', 'Converse.js');
|
|
|
|
- return this;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- addClientFeatures () {
|
|
|
|
- /* The strophe.disco.js plugin keeps a list of features which
|
|
|
|
- * it will advertise to any #info queries made to it.
|
|
|
|
- *
|
|
|
|
- * See: http://xmpp.org/extensions/xep-0030.html#info
|
|
|
|
- */
|
|
|
|
- _converse.connection.disco.addFeature(Strophe.NS.BOSH);
|
|
|
|
- _converse.connection.disco.addFeature(Strophe.NS.CHATSTATES);
|
|
|
|
- _converse.connection.disco.addFeature(Strophe.NS.DISCO_INFO);
|
|
|
|
- _converse.connection.disco.addFeature(Strophe.NS.ROSTERX); // Limited support
|
|
|
|
- if (_converse.message_carbons) {
|
|
|
|
- _converse.connection.disco.addFeature(Strophe.NS.CARBONS);
|
|
|
|
- }
|
|
|
|
- _converse.emit('addClientFeatures');
|
|
|
|
- return this;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- onItems (stanza) {
|
|
|
|
- _.each(stanza.querySelectorAll('query item'), (item) => {
|
|
|
|
- _converse.connection.disco.info(
|
|
|
|
- item.getAttribute('jid'),
|
|
|
|
- null,
|
|
|
|
- this.onInfo.bind(this));
|
|
|
|
- });
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- onInfo (stanza) {
|
|
|
|
- if ((sizzle('identity[category=server][type=im]', stanza).length === 0) &&
|
|
|
|
- (sizzle('identity[category=conference][type=text]', stanza).length === 0)) {
|
|
|
|
- // This isn't an IM server component
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- _.forEach(stanza.querySelectorAll('feature'), (feature) => {
|
|
|
|
- const namespace = feature.getAttribute('var');
|
|
|
|
- this[namespace] = true;
|
|
|
|
- this.create({
|
|
|
|
- 'var': namespace,
|
|
|
|
- 'from': stanza.getAttribute('from')
|
|
|
|
- });
|
|
|
|
- });
|
|
|
|
|
|
+ function addClientFeatures () {
|
|
|
|
+ /* The strophe.disco.js plugin keeps a list of features which
|
|
|
|
+ * it will advertise to any #info queries made to it.
|
|
|
|
+ *
|
|
|
|
+ * See: http://xmpp.org/extensions/xep-0030.html#info
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ // See http://xmpp.org/registrar/disco-categories.html
|
|
|
|
+ _converse.connection.disco.addIdentity('client', 'web', 'Converse.js');
|
|
|
|
+
|
|
|
|
+ _converse.connection.disco.addFeature(Strophe.NS.BOSH);
|
|
|
|
+ _converse.connection.disco.addFeature(Strophe.NS.CHATSTATES);
|
|
|
|
+ _converse.connection.disco.addFeature(Strophe.NS.DISCO_INFO);
|
|
|
|
+ _converse.connection.disco.addFeature(Strophe.NS.ROSTERX); // Limited support
|
|
|
|
+ if (_converse.message_carbons) {
|
|
|
|
+ _converse.connection.disco.addFeature(Strophe.NS.CARBONS);
|
|
}
|
|
}
|
|
- });
|
|
|
|
|
|
+ _converse.emit('addClientFeatures');
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
|
|
function initializeDisco () {
|
|
function initializeDisco () {
|
|
|
|
+ addClientFeatures();
|
|
_converse.disco_entities = new _converse.DiscoEntities();
|
|
_converse.disco_entities = new _converse.DiscoEntities();
|
|
}
|
|
}
|
|
_converse.api.listen.on('reconnected', initializeDisco);
|
|
_converse.api.listen.on('reconnected', initializeDisco);
|