Bug 1010342 - Implement MUC service discovery. r=aleth
authorAbdelrhman Ahmed <a.ahmed1026@gmail.com>
Tue, 23 Jun 2015 13:50:00 +0200
changeset 22807 b68eb761cf824d4731fd50f59d70bcaf56479776
parent 22806 3092759d5f48c2506afe4c9df50d168d10c65ced
child 22808 8b285e22024a8a7e3324a6f5c120eee6502e8d35
push id1443
push usermbanner@mozilla.com
push dateMon, 10 Aug 2015 18:31:17 +0000
treeherdercomm-beta@8fe07d686c22 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaleth
bugs1010342
Bug 1010342 - Implement MUC service discovery. r=aleth
chat/protocols/xmpp/xmpp.jsm
--- a/chat/protocols/xmpp/xmpp.jsm
+++ b/chat/protocols/xmpp/xmpp.jsm
@@ -807,16 +807,20 @@ XMPPAccountBuddy.prototype = XMPPAccount
 /* Helper class for account */
 const XMPPAccountPrototype = {
   __proto__: GenericAccountPrototype,
 
   _jid: null, // parsed Jabber ID: node, domain, resource
   _connection: null, // XMPPSession socket
   authMechanisms: null, // hook to let prpls tweak the list of auth mechanisms
 
+  // Contains the domain of MUC service which is obtained using service
+  // discovery.
+  _mucService: null,
+
   /* Generate unique id for a stanza. Using id and unique sid is defined in
    * RFC 6120 (Section 8.2.3, 4.7.3).
    */
   generateId: function() UuidGenerator.generateUUID().toString().slice(1, -1),
 
   _init: function(aProtoInstance, aImAccount) {
     GenericAccountPrototype._init.call(this, aProtoInstance, aImAccount);
 
@@ -848,16 +852,18 @@ const XMPPAccountPrototype = {
       chatFields.password = params[1];
     return chatFields;
   },
   getChatRoomDefaultFieldValues: function(aDefaultChatName) {
     let rv = GenericAccountPrototype.getChatRoomDefaultFieldValues
                                     .call(this, aDefaultChatName);
     if (!rv.values.nick)
       rv.values.nick = this._jid.node;
+    if (!rv.values.server && this._mucService)
+      rv.values.server = this._mucService;
 
     return rv;
   },
 
   // XEP-0045: Requests joining room if it exists or
   // creating room if it does not exist.
   joinChat: function(aComponents) {
     let jid =
@@ -1109,21 +1115,27 @@ const XMPPAccountPrototype = {
       aStanza.attributes.from, error));
   },
 
 
   /* XMPPSession events */
 
   /* Called when the XMPP session is started */
   onConnection: function() {
+    // Request the roster. The account will be marked as connected when this is
+    // complete.
     this.reportConnecting(_("connection.downloadingRoster"));
     let s = Stanza.iq("get", null, null, Stanza.node("query", Stanza.NS.roster));
+    this.sendStanza(s, this.onRoster, this);
 
-    /* Set the call back onRoster */
-    this.sendStanza(s, this.onRoster, this);
+    // XEP-0030 and XEP-0045 (6): Service Discovery.
+    // Queries Server for Associated Services.
+    let iq = Stanza.iq("get", null, this._jid.domain,
+                       Stanza.node("query", Stanza.NS.disco_items));
+    this.sendStanza(iq, this.onServiceDiscovery, this);
   },
 
   /* Called whenever a stanza is received */
   onXmppStanza: function(aStanza) {
   },
 
   /* Called when a iq stanza is received */
   onIQStanza: function(aStanza) {
@@ -1175,16 +1187,55 @@ const XMPPAccountPrototype = {
     else if (this._mucs.has(jid))
       this._mucs.get(jid).onPresenceStanza(aStanza);
     else if (jid != this.normalize(this._connection._jid.jid))
       this.WARN("received presence stanza for unknown buddy " + from);
     else
       this.WARN("Unhandled presence stanza.");
   },
 
+  // XEP-0030: Discovering services and their features that are supported by
+  // the server.
+  onServiceDiscovery: function(aStanza) {
+    let query = aStanza.getElement(["query"]);
+    if (aStanza.attributes["type"] != "result" || !query ||
+        query.uri != Stanza.NS.disco_items) {
+      this.WARN("Could not get services for this server: " + this._jid.domain);
+      return true;
+    }
+
+    // Discovering the Features that are Supported by each service.
+    query.getElements(["item"]).forEach(item => {
+      let jid = item.attributes["jid"];
+      if (!jid)
+        return;
+      let iq = Stanza.iq("get", null, jid,
+                         Stanza.node("query", Stanza.NS.disco_info));
+      this.sendStanza(iq, receivedStanza => {
+        let query = receivedStanza.getElement(["query"]);
+        let from = receivedStanza.attributes["from"];
+        if (aStanza.attributes["type"] != "result" || !query ||
+            query.uri != Stanza.NS.disco_info) {
+          this.WARN("Could not get features for this service: " + from);
+          return true;
+        }
+        let features = query.getElements(["feature"])
+                            .map(elt => elt.attributes["var"]);
+        if (features.indexOf(Stanza.NS.muc) != -1) {
+          // XEP-0045 (6.2): this feature is for a MUC Service.
+          this._mucService = from;
+        }
+        // TODO: Handle other services that are supported by XMPP through
+        // their features.
+
+        return true;
+      });
+    });
+  },
+
   // Returns null if not an invitation stanza, and an object
   // describing the invitation otherwise.
   parseInvitation: function(aStanza) {
       let x = aStanza.getElement(["x"]);
       if (!x)
         return null;
       let retVal = {};