chat/protocols/gtalk/gtalk.jsm
author Khushil Mistry <khushil324@gmail.com>
Fri, 08 May 2020 15:42:48 +1200
changeset 39025 f25512b597325260e72b0f45e06d2f6ac9f6dc7b
parent 37697 8d558f7fb2cc3088b6c797354ae164c0012b4ce2
permissions -rw-r--r--
Bug 1635734 - Fix Chat broken in Thunderbird for macOS. r=clokep a=wsmwk

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var EXPORTED_SYMBOLS = ["GTalkProtocol"];

var { XPCOMUtils, l10nHelper } = ChromeUtils.import(
  "resource:///modules/imXPCOMUtils.jsm"
);
var { GenericProtocolPrototype } = ChromeUtils.import(
  "resource:///modules/jsProtoHelper.jsm"
);
var { XMPPAccountPrototype } = ChromeUtils.import(
  "resource:///modules/xmpp-base.jsm"
);
var { XMPPSession } = ChromeUtils.import(
  "resource:///modules/xmpp-session.jsm"
);
var { Stanza } = ChromeUtils.import("resource:///modules/xmpp-xml.jsm");

XPCOMUtils.defineLazyGetter(this, "_", () =>
  l10nHelper("chrome://chat/locale/xmpp.properties")
);

// PlainFullBindAuth is an authentication mechanism that works like
// the standard PLAIN mechanism but adds a client-uses-full-bind-result
// attribute to the auth stanza to tell the Google Talk servers that we
// support their JID Domain Discovery extension.
// See https://developers.google.com/talk/jep_extensions/jid_domain_change
function* PlainFullBindAuth(aUsername, aPassword, aDomain) {
  let key = btoa("\0" + aUsername + "\0" + aPassword);
  let attrs = {
    mechanism: "PLAIN",
    "xmlns:ga": "http://www.google.com/talk/protocol/auth",
    "ga:client-uses-full-bind-result": "true",
  };
  let stanza = yield {
    send: Stanza.node("auth", Stanza.NS.sasl, attrs, key),
    log:
      "<auth.../> (PlainFullBindAuth base64 encoded username and password not logged)",
  };

  if (stanza.localName != "success") {
    throw new Error("Didn't receive the expected auth success stanza.");
  }
}

function GTalkAccount(aProtoInstance, aImAccount) {
  this._init(aProtoInstance, aImAccount);
}
GTalkAccount.prototype = {
  __proto__: XMPPAccountPrototype,
  connect() {
    this._jid = this._parseJID(this.name);
    // The XMPP spec says that the node part of a JID is optional, but
    // in the case of Google Talk if the username typed by the user
    // doesn't contain an @, we prefer assuming that it's the domain
    // part that's been omitted.
    if (!this._jid.node) {
      // If the domain part was omitted, swap the node and domain parts,
      // use 'gmail.com' as the default domain, and tell the Google
      // Talk server that we will use the full bind result.
      this._jid.node = this._jid.domain;
      this._jid.domain = "gmail.com";
      this.authMechanisms = { PLAIN: PlainFullBindAuth };
    }

    // For the resource, if the user has edited the option, always use that.
    if (this.prefs.prefHasUserValue("resource")) {
      let resource = this.getString("resource");
      this._jid = this._setJID(this._jid.domain, this._jid.node, resource);
    }

    this._connection = new XMPPSession(
      "talk.google.com",
      443,
      "require_tls",
      this._jid,
      this.imAccount.password,
      this
    );
  },
};

function GTalkProtocol() {
  ChromeUtils.import("resource:///modules/xmpp-commands.jsm", this);
  this.registerCommands();
}
GTalkProtocol.prototype = {
  __proto__: GenericProtocolPrototype,
  get normalizedName() {
    return "gtalk";
  },
  get name() {
    return _("gtalk.protocolName");
  },
  get iconBaseURI() {
    return "chrome://prpl-gtalk/skin/";
  },
  get usernameEmptyText() {
    return _("gtalk.usernameHint");
  },
  getAccount(aImAccount) {
    return new GTalkAccount(this, aImAccount);
  },
  options: {
    resource: {
      get label() {
        return _("options.resource");
      },
      default: "",
    },
  },
  get chatHasTopic() {
    return true;
  },
};