Bug 813929 - Make account manager handle broken accounts more robustly. r=IanN, r=Neil
authoraceman <acelists@atlas.sk>
Tue, 21 Jan 2014 15:28:45 -0500
changeset 19325 b4cb7f82793b245aa300d62abf97d7071bc4c2a1
parent 19324 67785d81fb610c86209c00ff34213bc785aff8d0
child 19326 f28b79f5b46f3a31e704f3d308fd9a2cbb37c2bf
push id1103
push usermbanner@mozilla.com
push dateTue, 18 Mar 2014 07:44:06 +0000
treeherdercomm-beta@50c6279a0af0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersIanN, Neil
bugs813929
Bug 813929 - Make account manager handle broken accounts more robustly. r=IanN, r=Neil
mailnews/base/prefs/content/AccountManager.js
--- a/mailnews/base/prefs/content/AccountManager.js
+++ b/mailnews/base/prefs/content/AccountManager.js
@@ -1081,39 +1081,42 @@ function onAccountTreeSelect(pageId, acc
     updateButtons(tree, account);
 
   return true;
 }
 
 // page has loaded
 function onPanelLoaded(pageId) {
   if (pageId != pendingPageId) {
-
     // if we're reloading the current page, we'll assume the
     // page has asked itself to be completely reloaded from
     // the prefs. to do this, clear out the the old entry in
     // the account data, and then restore theh page
     if (pageId == currentPageId) {
       var serverId = currentAccount ?
                      currentAccount.incomingServer.serverURI : "global"
       delete accountArray[serverId];
       restorePage(currentPageId, currentAccount);
     }
   } else {
-
     restorePage(pendingPageId, pendingAccount);
   }
 
   // probably unnecessary, but useful for debugging
   pendingAccount = null;
   pendingPageId = null;
 }
 
 function pageURL(pageId)
 {
+  // If we have a special non account manager pane (e.g. about:blank),
+  // do not translate it into ChromePackageName URL.
+  if (!pageId.startsWith("am-"))
+    return pageId;
+
   let chromePackageName;
   try {
     // we could compare against "main","server","copies","offline","addressing",
     // "smtp" and "advanced" first to save the work, but don't,
     // as some of these might be turned into extensions (for thunderbird)
     let packageName = pageId.split("am-")[1].split(".xul")[0];
     chromePackageName = MailServices.accounts.getChromePackageName(packageName);
   }
@@ -1475,120 +1478,138 @@ var gAccountTree = {
 
     // If there was no value stored, use opened state.
     return "true";
   },
 
   _build: function at_build() {
     const Ci = Components.interfaces;
     var bundle = document.getElementById("bundle_prefs");
-    function get(aString) { return bundle.getString(aString); }
-    var panels = [{string: get("prefPanel-server"), src: "am-server.xul"},
-                  {string: get("prefPanel-copies"), src: "am-copies.xul"},
-                  {string: get("prefPanel-synchronization"), src: "am-offline.xul"},
-                  {string: get("prefPanel-diskspace"), src: "am-offline.xul"},
-                  {string: get("prefPanel-addressing"), src: "am-addressing.xul"},
-                  {string: get("prefPanel-junk"), src: "am-junk.xul"}];
+    function getString(aString) { return bundle.getString(aString); }
+    var panels = [{string: getString("prefPanel-server"), src: "am-server.xul"},
+                  {string: getString("prefPanel-copies"), src: "am-copies.xul"},
+                  {string: getString("prefPanel-synchronization"), src: "am-offline.xul"},
+                  {string: getString("prefPanel-diskspace"), src: "am-offline.xul"},
+                  {string: getString("prefPanel-addressing"), src: "am-addressing.xul"},
+                  {string: getString("prefPanel-junk"), src: "am-junk.xul"}];
 
     let accounts = allAccountsSorted(false);
 
     let mainTree = document.getElementById("account-tree-children");
     // Clear off all children...
     while (mainTree.firstChild)
       mainTree.removeChild(mainTree.firstChild);
 
-    for each (let account in accounts) {
-      let server = account.incomingServer;
+    for (let account of accounts) {
+      let accountName = null;
+      let accountKey = account.key;
+      let amChrome = "about:blank";
+      let panelsToKeep = [];
+
+      // This "try {} catch {}" block is intentionally very long to catch
+      // unknown exceptions and confine them to this single account.
+      // This may happen from broken accounts. See e.g. bug 813929.
+      // Other accounts can still be shown properly if they are valid.
+      try {
+        let server = account.incomingServer;
+
+        if (server.type == "im" && !Services.prefs.getBoolPref("mail.chat.enabled"))
+          continue;
+
+        accountName = server.prettyName;
+
+        // Now add our panels.
+        let idents = MailServices.accounts.getIdentitiesForServer(server);
+        if (idents.length) {
+          panelsToKeep.push(panels[0]); // The server panel is valid
+          panelsToKeep.push(panels[1]); // also the copies panel
+          panelsToKeep.push(panels[4]); // and addresssing
+        }
+
+        // Everyone except News, RSS and IM has a junk panel
+        // XXX: unextensible!
+        // The existence of server.spamSettings can't currently be used for this.
+        if (server.type != "nntp" && server.type != "rss" && server.type != "im")
+          panelsToKeep.push(panels[5]);
 
-      if (server.type == "im" && !Services.prefs.getBoolPref("mail.chat.enabled"))
-        continue;
+        // Check offline/diskspace support level.
+        let diskspace = server.supportsDiskSpace;
+        if (server.offlineSupportLevel >= 10 && diskspace)
+          panelsToKeep.push(panels[2]);
+        else if (diskspace)
+          panelsToKeep.push(panels[3]);
 
-      // Create the top level tree-item
+        // extensions
+        let catMan = Components.classes["@mozilla.org/categorymanager;1"]
+                               .getService(Ci.nsICategoryManager);
+        const CATEGORY = "mailnews-accountmanager-extensions";
+        let catEnum = catMan.enumerateCategory(CATEGORY);
+        while (catEnum.hasMoreElements()) {
+          var string = Components.interfaces.nsISupportsCString;
+          var entryName = catEnum.getNext().QueryInterface(string).data;
+          var svc = Components.classes[catMan.getCategoryEntry(CATEGORY, entryName)]
+                              .getService(Ci.nsIMsgAccountManagerExtension);
+          if (svc.showPanel(server)) {
+            let bundleName = "chrome://" + svc.chromePackageName +
+                             "/locale/am-" + svc.name + ".properties";
+            let bundle = Services.strings.createBundle(bundleName);
+            let title = bundle.GetStringFromName("prefPanel-" + svc.name);
+            panelsToKeep.push({string: title, src: "am-" + svc.name + ".xul"});
+          }
+        }
+        amChrome = server.accountManagerChrome;
+      } catch(e) {
+        // Show only a placeholder in the account list saying this account
+        // is broken, with no child panels.
+        let accountID = (accountName || accountKey);
+        Components.utils.reportError("Error accessing account " + accountID + ": " + e);
+        accountName = "Invalid account " + accountID;
+        panelsToKeep.length = 0;
+      }
+
+      // Create the top level tree-item.
       var treeitem = document.createElement("treeitem");
       mainTree.appendChild(treeitem);
       var treerow = document.createElement("treerow");
       treeitem.appendChild(treerow);
       var treecell = document.createElement("treecell");
       treerow.appendChild(treecell);
-      treecell.setAttribute("label", server.rootFolder.prettyName);
-
-      // Now add our panels
-      var panelsToKeep = [];
-      let idents = MailServices.accounts.getIdentitiesForServer(server);
-      if (idents.length) {
-        panelsToKeep.push(panels[0]); // The server panel is valid
-        panelsToKeep.push(panels[1]); // also the copies panel
-        panelsToKeep.push(panels[4]); // and addresssing
-      }
-
-      // Everyone except News, RSS and IM has a junk panel
-      // XXX: unextensible!
-      // The existence of server.spamSettings can't currently be used for this.
-      if (server.type != "nntp" && server.type != "rss" && server.type != "im")
-        panelsToKeep.push(panels[5]);
-
-      // Check offline/diskspace support level
-      var offline = server.offlineSupportLevel;
-      var diskspace = server.supportsDiskSpace;
-      if (offline >= 10 && diskspace)
-        panelsToKeep.push(panels[2]);
-      else if (diskspace)
-        panelsToKeep.push(panels[3]);
-
-      // extensions
-      var catMan = Components.classes["@mozilla.org/categorymanager;1"]
-                             .getService(Ci.nsICategoryManager);
-      const CATEGORY = "mailnews-accountmanager-extensions";
-      var catEnum = catMan.enumerateCategory(CATEGORY);
-      while (catEnum.hasMoreElements()) {
-        var string = Components.interfaces.nsISupportsCString;
-        var entryName = catEnum.getNext().QueryInterface(string).data;
-        var svc = Components.classes[catMan.getCategoryEntry(CATEGORY, entryName)]
-                            .getService(Ci.nsIMsgAccountManagerExtension);
-        if (svc.showPanel(server)) {
-          let bundleName = "chrome://" + svc.chromePackageName +
-                           "/locale/am-" + svc.name + ".properties";
-          let bundle = Services.strings.createBundle(bundleName);
-          let title = bundle.GetStringFromName("prefPanel-" + svc.name);
-          panelsToKeep.push({string: title, src: "am-" + svc.name + ".xul"});
-        }
-      }
+      treecell.setAttribute("label", accountName);
+      treeitem.setAttribute("PageTag", amChrome);
 
       if (panelsToKeep.length > 0) {
         var treekids = document.createElement("treechildren");
         treeitem.appendChild(treekids);
-        for each (let panel in panelsToKeep) {
+        for (let panel of panelsToKeep) {
           var kidtreeitem = document.createElement("treeitem");
           treekids.appendChild(kidtreeitem);
           var kidtreerow = document.createElement("treerow");
           kidtreeitem.appendChild(kidtreerow);
           var kidtreecell = document.createElement("treecell");
           kidtreerow.appendChild(kidtreecell);
           kidtreecell.setAttribute("label", panel.string);
           kidtreeitem.setAttribute("PageTag", panel.src);
           kidtreeitem._account = account;
         }
         treeitem.setAttribute("container", "true");
-        treeitem.id = account.key;
+        treeitem.id = accountKey;
         // Load the 'open' state of the account from localstore.rdf.
-        treeitem.setAttribute("open", this._getAccountOpenState(account.key));
+        treeitem.setAttribute("open", this._getAccountOpenState(accountKey));
         // Let the localstore.rdf automatically save the 'open' state of the
         // account when it is changed.
         treeitem.setAttribute("persist", "open");
       }
-      treeitem.setAttribute("PageTag", server ? server.accountManagerChrome
-                                              : "am-main.xul");
       treeitem._account = account;
     }
 
     markDefaultServer(MailServices.accounts.defaultAccount, null);
 
-    // Now add the outgoing server node
+    // Now add the outgoing server node.
     var treeitem = document.createElement("treeitem");
     mainTree.appendChild(treeitem);
     var treerow = document.createElement("treerow");
     treeitem.appendChild(treerow);
     var treecell = document.createElement("treecell");
     treerow.appendChild(treecell);
-    treecell.setAttribute("label", bundle.getString("prefPanel-smtp"));
+    treecell.setAttribute("label", getString("prefPanel-smtp"));
     treeitem.setAttribute("PageTag", "am-smtp.xul");
   }
 };