Bug 775105 - Presence information in email headers is not shown correctly when there are multiple message windows. r=mconley.
authorFlorian Quèze <florian@queze.net>
Mon, 23 Jul 2012 16:28:02 -0400
changeset 10712 02f5462203a536b553840b6599de4efdc16a0327
parent 10711 a7b28a555957c7584affee606df2ebdee58399a2
child 10713 3b29e269e62efe27e66cbf5cd5502c06769edae6
push id8076
push usermconley@mozilla.com
push dateMon, 23 Jul 2012 20:34:55 +0000
treeherdercomm-central@02f5462203a5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs775105
Bug 775105 - Presence information in email headers is not shown correctly when there are multiple message windows. r=mconley.
mail/base/content/msgHdrViewOverlay.js
mail/components/im/Makefile.in
mail/components/im/content/chat-messenger-overlay.js
mail/components/im/modules/chatHandler.jsm
--- a/mail/base/content/msgHdrViewOverlay.js
+++ b/mail/base/content/msgHdrViewOverlay.js
@@ -1269,17 +1269,21 @@ function UpdateEmailNodeDetails(aEmailAd
     let gTalk = card.getProperty("_GoogleTalk", null);
     if (gTalk)
       chatAddresses.push(gTalk);
     let jid = card.getProperty("_JabberId", null);
     if (jid)
       chatAddresses.push(jid);
   }
   let chatContact;
-  let onlineContacts = "chatHandler" in window ? chatHandler.onlineContacts : {};
+  if (!("chatHandler" in window)) {
+    window.chatHandler = {};
+    Components.utils.import("resource:///modules/chatHandler.jsm", chatHandler);
+  }
+  let onlineContacts = chatHandler.onlineContacts;
   for each (let chatAddress in chatAddresses) {
     if (Object.prototype.hasOwnProperty.call(onlineContacts, chatAddresses)) {
       chatContact = onlineContacts[chatAddress];
       break;
     }
   }
   if (aDocumentNode.chatContact) {
     aDocumentNode.chatContact.removeObserver(aDocumentNode.chatContactObserver);
@@ -1505,20 +1509,35 @@ function onClickEmailStar(event, emailAd
 }
 
 function onClickEmailPresence(event, emailAddressNode)
 {
   // Only care about left-click events
   if (event.button != 0)
     return;
 
-  showChatTab();
   let prplConv = emailAddressNode.chatContact.createConversation();
   let uiConv = Services.conversations.getUIConversation(prplConv);
-  chatHandler.focusConversation(uiConv);
+
+  let win = window;
+  if (!("focusConversation" in chatHandler)) {
+    win = Services.wm.getMostRecentWindow("mail:3pane");
+    if (win)
+      win.focus();
+    else {
+      window.openDialog("chrome://messenger/content/", "_blank",
+                        "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar", null,
+                        {tabType: "chat",
+                         tabParams: {convType: "focus", conv: uiConv}});
+      return;
+    }
+  }
+
+  win.showChatTab();
+  win.chatHandler.focusConversation(uiConv);
 }
 
 /**
  * Takes the email address node, adds a new contact from the node's
  * displayName and emailAddress attributes to the personal address book.
  *
  * @param emailAddressNode  a node with displayName and emailAddress attributes
  */
--- a/mail/components/im/Makefile.in
+++ b/mail/components/im/Makefile.in
@@ -11,15 +11,16 @@ include $(DEPTH)/config/autoconf.mk
 
 EXTRA_COMPONENTS = \
 		imIncomingServer.js \
 		imProtocolInfo.js \
 		im.manifest \
 		$(NULL)
 
 EXTRA_JS_MODULES = \
+		modules/chatHandler.jsm \
 		modules/index_im.js \
 		modules/search_im.js \
 		$(NULL)
 
 PREF_JS_EXPORTS = $(srcdir)/all-im.js
 
 include $(topsrcdir)/config/rules.mk
--- a/mail/components/im/content/chat-messenger-overlay.js
+++ b/mail/components/im/content/chat-messenger-overlay.js
@@ -78,19 +78,25 @@ var chatTabType = {
   panelId: "chatTabPanel",
   modes: {
     chat: {
       type: "chat"
     }
   },
 
   _handleArgs: function(aArgs) {
-    if (!aArgs || !("convType" in aArgs) || aArgs.convType != "log")
+    if (!aArgs || !("convType" in aArgs) ||
+        (aArgs.convType != "log" && aArgs.convType != "focus"))
       return;
 
+    if (aArgs.convType == "focus") {
+      chatHandler.focusConversation(aArgs.conv);
+      return;
+    }
+
     let item = document.getElementById("searchResultConv");
     item.log = aArgs.conv;
     if (aArgs.searchTerm)
       item.searchTerm = aArgs.searchTerm;
     else
       delete item.searchTerm;
     item.hidden = false;
     item.shouldDisplayConversation = true;
@@ -644,17 +650,16 @@ var chatHandler = {
   },
   addBuddy: function() {
      this._openDialog("addbuddy");
   },
   joinChat: function() {
     this._openDialog("joinchat");
   },
 
-  onlineContacts: {},
   _colorCache: {},
   // Duplicated code from imconversation.xml :-(
   _computeColor: function(aName) {
     if (Object.prototype.hasOwnProperty.call(this._colorCache, aName))
       return this._colorCache[aName];
 
     // Compute the color based on the nick
     var nick = aName.match(/[a-zA-Z0-9]+/);
@@ -776,23 +781,16 @@ var chatHandler = {
       return;
     }
   },
   _updateFocus: function() {
     let focusId = this._placeHolderButtonId || "contactlistbox";
     document.getElementById(focusId).focus();
   },
   observe: function(aSubject, aTopic, aData) {
-    if (aTopic == "browser-request") {
-      imServices.ww.openWindow(null,
-                               "chrome://chat/content/browserRequest.xul",
-                               null, "chrome", aSubject);
-      return;
-    }
-
     if (aTopic == "conversation-loaded") {
       let browser = document.getElementById("conv-log-browser");
       if (aSubject != browser)
         return;
 
       for each (let msg in browser._conv.getMessages()) {
         if (!msg.system)
           msg.color = "color: hsl(" + this._computeColor(msg.who) + ", 100%, 40%);";
@@ -825,25 +823,23 @@ var chatHandler = {
       return;
     }
 
     if (aTopic == "contact-signed-on") {
       if (!this._hasConversationForContact(aSubject)) {
         document.getElementById("onlinecontactsGroup").addContact(aSubject);
         document.getElementById("offlinecontactsGroup").removeContact(aSubject);
       }
-      this.onlineContacts[aSubject.preferredBuddy.normalizedName] = aSubject;
       return;
     }
     if (aTopic == "contact-signed-off") {
       if (!this._hasConversationForContact(aSubject)) {
         document.getElementById("offlinecontactsGroup").addContact(aSubject);
         document.getElementById("onlinecontactsGroup").removeContact(aSubject);
       }
-      delete this.onlineContacts[aSubject.preferredBuddy.normalizedName];
       return;
     }
     if (aTopic == "contact-added") {
       let groupName = (aSubject.online ? "on" : "off") + "linecontactsGroup";
       document.getElementById(groupName).addContact(aSubject);
       return;
     }
     if (aTopic == "contact-removed") {
@@ -915,17 +911,17 @@ var chatHandler = {
       let notification =
         document.getElementById("chatTabPanel")
                 .getNotificationWithValue(value);
       if (notification)
         notification.close();
       return;
     }
   },
-  initContactList: function() {
+  initAfterChatCore: function() {
     let onGroup = document.getElementById("onlinecontactsGroup");
     let offGroup = document.getElementById("offlinecontactsGroup");
 
     imServices.tags.getTags().forEach(function (aTag) {
       aTag.getContacts().forEach(function(aContact) {
         let group = aContact.online ? onGroup : offGroup;
         group.addContact(aContact);
       });
@@ -941,41 +937,41 @@ var chatHandler = {
     imServices.obs.addObserver(this, "contact-signed-off", false);
     imServices.obs.addObserver(this, "contact-added", false);
     imServices.obs.addObserver(this, "contact-removed", false);
     imServices.obs.addObserver(this, "contact-no-longer-dummy", false);
     imServices.obs.addObserver(this, "account-connected", false);
     imServices.obs.addObserver(this, "account-disconnected", false);
     imServices.obs.addObserver(this, "account-added", false);
     imServices.obs.addObserver(this, "account-removed", false);
+
+    chatHandler._updateNoConvPlaceHolder();
+    statusSelector.init();
   },
   init: function() {
     if (!Services.prefs.getBoolPref("mail.chat.enabled")) {
       ["button-chat", "menu_goChat", "goChatSeparator",
        "imAccountsStatus", "joinChatMenuItem",
        "newIMAccountMenuItem", "newIMContactMenuItem"].forEach(function(aId) {
          let elt = document.getElementById(aId);
          if (elt)
            elt.hidden = true;
        });
       document.getElementById("key_goChat").disabled = true;
       return;
     }
 
-    Components.utils.import("resource:///modules/index_im.js");
-
     // initialize the customizeDone method on the customizeable toolbar
     var toolbox = document.getElementById("chat-view-toolbox");
     toolbox.customizeDone = function(aEvent) {
       MailToolboxCustomizeDone(aEvent, "CustomizeChatToolbar");
     };
 
     let tabmail = document.getElementById("tabmail");
     tabmail.registerTabType(chatTabType);
-    imServices.obs.addObserver(this, "browser-request", false);
     imServices.obs.addObserver(this, "buddy-authorization-request", false);
     imServices.obs.addObserver(this, "buddy-authorization-request-canceled", false);
     let listbox = document.getElementById("contactlistbox");
     listbox.addEventListener("keypress", function(aEvent) {
       let item = listbox.selectedItem;
       if (!item || !item.parentNode) // empty list or item no longer in the list
         return;
       item.keyPress(aEvent);
@@ -995,56 +991,19 @@ var chatHandler = {
         item.convView.focus();
       else
         listbox.focus();
     });
     window.addEventListener("resize", this.onConvResize.bind(this));
     document.getElementById("conversationsGroup").sortComparator =
       function(a, b) a.title.toLowerCase().localeCompare(b.title.toLowerCase());
 
-    // The initialization of the im core may trigger a master password prompt,
-    // so wrap it with the async prompter service.
-    Components.classes["@mozilla.org/messenger/msgAsyncPrompter;1"]
-              .getService(Components.interfaces.nsIMsgAsyncPrompter)
-              .queueAsyncAuthPrompt("im", false, {
-      onPromptStart: function() {
-        imServices.core.init();
-
-        // Find the accounts that exist in the im account service but
-        // not in nsMsgAccountManager. They have probably been lost if
-        // the user has used an older version of Thunderbird on a
-        // profile with IM accounts. See bug 736035.
-        let accountsById = {};
-        for each (let account in fixIterator(imServices.accounts.getAccounts()))
-          accountsById[account.numericId] = account;
-        let mgr = Components.classes["@mozilla.org/messenger/account-manager;1"]
-                            .getService(Ci.nsIMsgAccountManager);
-        for each (let account in fixIterator(mgr.accounts, Ci.nsIMsgAccount)) {
-          let incomingServer = account.incomingServer;
-          if (!incomingServer || incomingServer.type != "im")
-            continue;
-          delete accountsById[incomingServer.wrappedJSObject.imAccount.numericId];
-        }
-        // Let's recreate each of them...
-        for each (let account in accountsById) {
-          let inServer = mgr.createIncomingServer(account.name,
-                                                  account.protocol.id, // hostname
-                                                  "im");
-          inServer.wrappedJSObject.imAccount = account;
-          let acc = mgr.createAccount();
-          // Avoid new folder notifications.
-          inServer.valid = false;
-          acc.incomingServer = inServer;
-          inServer.valid = true;
-          mgr.notifyServerLoaded(inServer);
-        }
-        chatHandler.initContactList();
-        chatHandler._updateNoConvPlaceHolder();
-        statusSelector.init();
-        return true;
-      },
-      onPromptAuthAvailable : function() { },
-      onPromptCanceled : function() { }
-    });
+    Components.utils.import("resource:///modules/chatHandler.jsm", this);
+    if (this.ChatCore.initialized)
+      this.initAfterChatCore();
+    else {
+      this.ChatCore.init();
+      imServices.obs.addObserver(this.initAfterChatCore.bind(this), "chat-core-initialized", false);
+    }
   }
 };
 
 window.addEventListener("load", chatHandler.init.bind(chatHandler));
new file mode 100644
--- /dev/null
+++ b/mail/components/im/modules/chatHandler.jsm
@@ -0,0 +1,89 @@
+/* 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/. */
+
+const EXPORTED_SYMBOLS = ["onlineContacts", "ChatCore"];
+
+Components.utils.import("resource:///modules/imServices.jsm");
+Components.utils.import("resource:///modules/iteratorUtils.jsm");
+
+var onlineContacts = {};
+
+var ChatCore = {
+  initialized: false,
+  _initializing: false,
+  init: function() {
+    if (this._initializing)
+      return;
+    this._initializing = true;
+
+    Components.utils.import("resource:///modules/index_im.js");
+
+    Services.obs.addObserver(this, "browser-request", false);
+    Services.obs.addObserver(this, "contact-signed-on", false);
+    Services.obs.addObserver(this, "contact-signed-off", false);
+
+    // The initialization of the im core may trigger a master password prompt,
+    // so wrap it with the async prompter service.
+    Components.classes["@mozilla.org/messenger/msgAsyncPrompter;1"]
+              .getService(Components.interfaces.nsIMsgAsyncPrompter)
+              .queueAsyncAuthPrompt("im", false, {
+      onPromptStart: function() {
+        Services.core.init();
+
+        // Find the accounts that exist in the im account service but
+        // not in nsMsgAccountManager. They have probably been lost if
+        // the user has used an older version of Thunderbird on a
+        // profile with IM accounts. See bug 736035.
+        let accountsById = {};
+        for each (let account in fixIterator(Services.accounts.getAccounts()))
+          accountsById[account.numericId] = account;
+        let mgr = Components.classes["@mozilla.org/messenger/account-manager;1"]
+                            .getService(Components.interfaces.nsIMsgAccountManager);
+        for each (let account in fixIterator(mgr.accounts, Components.interfaces.nsIMsgAccount)) {
+          let incomingServer = account.incomingServer;
+          if (!incomingServer || incomingServer.type != "im")
+            continue;
+          delete accountsById[incomingServer.wrappedJSObject.imAccount.numericId];
+        }
+        // Let's recreate each of them...
+        for each (let account in accountsById) {
+          let inServer = mgr.createIncomingServer(account.name,
+                                                  account.protocol.id, // hostname
+                                                  "im");
+          inServer.wrappedJSObject.imAccount = account;
+          let acc = mgr.createAccount();
+          // Avoid new folder notifications.
+          inServer.valid = false;
+          acc.incomingServer = inServer;
+          inServer.valid = true;
+          mgr.notifyServerLoaded(inServer);
+        }
+        ChatCore.initialized = true;
+        Services.obs.notifyObservers(null, "chat-core-initialized", null);
+        ChatCore._initializing = false;
+        return true;
+      },
+      onPromptAuthAvailable: function() { },
+      onPromptCanceled: function() { }
+    });
+  },
+  observe: function(aSubject, aTopic, aData) {
+    if (aTopic == "browser-request") {
+      Services.ww.openWindow(null,
+                             "chrome://chat/content/browserRequest.xul",
+                             null, "chrome", aSubject);
+      return;
+    }
+
+    if (aTopic == "contact-signed-on") {
+      onlineContacts[aSubject.preferredBuddy.normalizedName] = aSubject;
+      return;
+    }
+
+    if (aTopic == "contact-signed-off") {
+      delete onlineContacts[aSubject.preferredBuddy.normalizedName];
+      return;
+    }
+  }
+};