patches-derdf/folder-lookup-service
author Joshua Cranmer <Pidgeot18@gmail.com>
Thu, 01 Oct 2020 07:35:25 -0400
changeset 566 d136235445cfce3b754bf089237c603818ae0ead
parent 1 cd19874b48f8160913286552448157472622d98e
permissions -rw-r--r--
Update for 2020-10-01

# HG changeset patch
# Parent 8e502ee509afd6ba6c7cb5dea67807f4a85988ef

diff --git a/mail/installer/package-manifest.in b/mail/installer/package-manifest.in
--- a/mail/installer/package-manifest.in
+++ b/mail/installer/package-manifest.in
@@ -147,16 +147,17 @@
 @BINPATH@/components/components.manifest
 @BINPATH@/components/aboutRedirector.js
 @BINPATH@/components/activity.xpt
 @BINPATH@/components/activityComponents.manifest
 @BINPATH@/components/cloudFileComponents.manifest
 @BINPATH@/components/cloudfile.xpt
 @BINPATH@/components/addrbook.xpt
 @BINPATH@/components/fts3tok.xpt
+@BINPATH@/components/folderLookupService.js
 ; interfaces.manifest doesn't get packaged because it is dynamically
 ; re-created at packaging time when linking the xpts that will actually
 ; go into the package, so the test related interfaces aren't included.
 @BINPATH@/components/jetpack.xpt
 @BINPATH@/components/mime.xpt
 @BINPATH@/components/steel.xpt
 @BINPATH@/components/msgAsyncPrompter.js
 @BINPATH@/components/msgbase.xpt
diff --git a/mailnews/base/public/nsIFolderLookupService.idl b/mailnews/base/public/nsIFolderLookupService.idl
--- a/mailnews/base/public/nsIFolderLookupService.idl
+++ b/mailnews/base/public/nsIFolderLookupService.idl
@@ -1,22 +1,32 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 
 interface nsIMsgFolder;
 
+/**
+ * This service provides a way to lookup any nsIMsgFolder.
+ *
+ * When looking up folders by URL, note that the URL must be encoded to be a
+ * valid URL. Escaping can be done via nsINetUtil::escapeString(name,
+ * nsINetUtil::ESCAPE_URL_PATH).
+ *
+ * The contractid for this service is "@mozilla.org/mail/folder-lookup;1".
+ */
 [scriptable,uuid(a1aaa404-9be7-461f-a715-e92512729923)]
 interface nsIFolderLookupService : nsISupports
 {
   /**
-   * Returns a folder with the given id. If the folder does not exist, but an
+   * Returns a folder with the given URL. If the folder does not exist, but an
    * identifiable parent does, we'll create it and then return that folder. If
    * no parent exists, this will return null.
    *
-   * @note For the moment, the id is the URI property of the folder.  This may
-   *       change
+   * @param aUrl      The URL of the folder to create.
+   * @param mayCreate If specified and true, then the folder will be created if
+   *                  it doesn't exist.
    */
-  nsIMsgFolder getFolderById(in ACString id);
+  nsIMsgFolder getFolderByUrl(in ACString aUrl, [optional] in boolean mayCreate);
 };
 
diff --git a/mailnews/base/src/Makefile.in b/mailnews/base/src/Makefile.in
--- a/mailnews/base/src/Makefile.in
+++ b/mailnews/base/src/Makefile.in
@@ -93,16 +93,20 @@ EXPORTS = \
 
 EXTRA_COMPONENTS = \
 		nsMailNewsCommandLineHandler.js \
 		msgAsyncPrompter.js \
 		newMailNotificationService.js \
 		msgBase.manifest \
 		$(NULL)
 
+EXTRA_PP_COMPONENTS = \
+		folderLookupService.js \
+		$(NULL)
+
 EXTRA_JS_MODULES = \
 		virtualFolderWrapper.js \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
diff --git a/mailnews/base/src/folderLookupService.js b/mailnews/base/src/folderLookupService.js
new file mode 100644
--- /dev/null
+++ b/mailnews/base/src/folderLookupService.js
@@ -0,0 +1,156 @@
+/* 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/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+#ifndef MOZ_THUNDERBIRD
+var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
+                            .getService(Components.interfaces.nsIRDFService);
+#endif
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/mailServices.js");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function folderLookupService() {
+}
+
+folderLookupService.prototype = {
+  // XPCOM registration stuff
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFolderLookupService,
+                                         Ci.nsIFolderListener]),
+  classDescription: "Folder Lookup Service",
+  contractID: "@mozilla.org/mail/folder-lookup;1",
+  classID: Components.ID("{a30be08c-afc8-4fed-9af7-79778a23db23}"),
+
+  // nsIFolderLookupService impl
+  getFolderByUrl: function fls_getFolderByUrl(aId, mayCreate) {
+#ifndef MOZ_THUNDERBIRD
+    return RDF.GetResource(aId);
+#endif
+    if (!this._map)
+      this._buildMap();
+
+    if (aId in this._map) {
+      try {
+        return this._map[aId].QueryReferent(Ci.nsIMsgFolder);
+      } catch (e) {
+        // The object was deleted, so clear it from the map.
+        delete this._map[aId];
+      }
+    }
+
+    // No folder, so if we can't create, give up.
+    if (!mayCreate)
+      return null;
+
+    // We were asked to try to create this folder. First find the parent folder,
+    // and then add the subfolder.
+    let parentURL = aId.substr(0, aId.lastIndexOf('/'));
+    let childName = aId.substr(parentURL.length + 1);
+
+    // If there isn't even a parent, just bail
+    if (!(parentURL in this._map)) {
+      Components.utils.reportError("Asking for subfolder with no parent! " + aId);
+      throw Components.results.NS_ERROR_FAILURE;
+    }
+
+    // Make the folder and add to the map.
+    let parent = this._map[parentURL].QueryReferent(Ci.nsIMsgFolder);
+    // nsIMsgFolder::AddSubfolder escapes the child's name. The URL we have here
+    // uses the escaped version, so unescape the string so that we don't get
+    // double-escaped strings.
+    let nu = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
+    let folder = parent.addSubfolder(nu.unescapeString(childName, 0));
+    this._addFolder(aId, folder);
+    return folder;
+  },
+
+  _map: null,
+  _sessionAdded: false,
+
+  _buildMap: function fls_buildmap() {
+    this._map = {};
+    var lookupService = this;
+    // Adds a folder and any subfolders it might have to the map
+    function addFolder(aFolder) {
+      lookupService._addFolder(aFolder.URI, aFolder);
+
+      var childEnum = aFolder.subFolders;
+      while (childEnum.hasMoreElements()) {
+        addFolder(childEnum.getNext().QueryInterface(Ci.nsIMsgFolder));
+      }
+    }
+
+    let acctMgrAccounts = MailServices.accounts.accounts;
+    var count = acctMgrAccounts.Count();
+    for (var i = 0; i < count; i++) {
+      var acct = acctMgrAccounts.QueryElementAt(i, Ci.nsIMsgAccount);
+
+      // This is a HACK to work around bug 41133. If we have one of the
+      // dummy "news" accounts there, that account won't have an
+      // incomingServer attached to it, and everything will blow up.
+      if (acct.incomingServer)
+        addFolder(acct.incomingServer.rootMsgFolder);
+    }
+
+    if (!this._sessionAdded) {
+      MailServices.mailSession.AddFolderListener(this,
+        Ci.nsIFolderListener.added | Ci.nsIFolderListener.removed);
+
+      // See the notes below on the observe method
+      Services.prefs.addObserver("mail.accountmanager.", this, false);
+      Services.obs.addObserver(this, "xpcom-shutdown", false);
+      this._sessionAdded = true;
+    }
+  },
+  _addFolder: function fls_addFolder(aURI, aFolder) {
+    this._map[aURI] = aFolder.QueryInterface(Ci.nsISupportsWeakReference)
+                             .GetWeakReference();
+  },
+  _cleanup: function fls_cleanup() {
+    if (this._sessionAdded) {
+      MailServices.mailSession.RemoveFolderListener(this);
+      Services.prefs.removeObserver("mail.accountmanager.", this);
+      Services.obs.removeObserver(this, "xpcom-shutdown");
+    }
+  },
+  OnItemAdded: function fls_onItemAdded(aParent, aItem) {
+    if (aItem instanceof Ci.nsIMsgFolder)
+      this._addFolder(aItem.URI, aItem);
+  },
+  OnItemRemoved: function fls_onItemRemoved(aParent, aItem) {
+    if (aItem instanceof Ci.nsIMsgFolder && aItem.URI in this._map)
+      delete this._map[aItem.URI];
+  },
+  OnItemPropertyChanged: function fls_onItemPropertyChanged() {},
+  OnItemIntPropertyChanged: function fls_onItemIntPropertyChanged() {},
+  OnItemBoolPropertyChanged: function fls_onItemBoolPropertyChanged() {},
+  OnItemUnicharPropertyChanged: function fls_onItemUnicharPropertyChanged() {},
+  OnItemPropertyFlagChanged: function fls_onItemPropertyFlagChanged() {},
+  OnItemEvent: function fls_onItemEvent(folder, event) {},
+
+  // Eww, we also have to watch for account creations, because they have a
+  // "root folder" that doesn't trigger any of the above notifications on
+  // creation.
+  //
+  // XXX Believe it or not, the simplest way to watch for new accounts is to
+  // throw an observer on the pref-system. I wish STEEL existed so I could just
+  // watch that
+  observe: function act_observe(aSubject, aTopic, aData) {
+    if (aTopic == "xpcom-shutdown")
+      this._cleanup();
+    else if (aTopic != "nsPref:changed" || aData != "mail.accountmanager.accounts")
+      return;
+
+    // We could do a bunch of work to figure out who was added/removed, but
+    // since account creation is a rare enough event, let's just reset.
+    this._map = null;
+  }
+};
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([folderLookupService]);
diff --git a/mailnews/base/src/msgBase.manifest b/mailnews/base/src/msgBase.manifest
--- a/mailnews/base/src/msgBase.manifest
+++ b/mailnews/base/src/msgBase.manifest
@@ -1,8 +1,10 @@
 component {49b04761-23dd-45d7-903d-619418a4d319} msgAsyncPrompter.js
 contract @mozilla.org/messenger/msgAsyncPrompter;1 {49b04761-23dd-45d7-903d-619418a4d319}
 component {2f86d554-f9d9-4e76-8eb7-243f047333ee} nsMailNewsCommandLineHandler.js
 contract @mozilla.org/commandlinehandler/general-startup;1?type=mail {2f86d554-f9d9-4e76-8eb7-243f047333ee}
 category command-line-handler m-mail @mozilla.org/commandlinehandler/general-startup;1?type=mail
+component {a30be08c-afc8-4fed-9af7-79778a23db23} folderLookupService.js
+contract @mozilla.org/mail/folder-lookup;1 {a30be08c-afc8-4fed-9af7-79778a23db23}
 component {740880E6-E299-4165-B82F-DF1DCAB3AE22} newMailNotificationService.js
 contract @mozilla.org/newMailNotificationService;1 {740880E6-E299-4165-B82F-DF1DCAB3AE22}
 category profile-after-change NewMailNotificationService @mozilla.org/newMailNotificationService;1 
diff --git a/suite/installer/package-manifest.in b/suite/installer/package-manifest.in
--- a/suite/installer/package-manifest.in
+++ b/suite/installer/package-manifest.in
@@ -731,16 +731,17 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/components/msgdb.xpt
 @BINPATH@/components/msgimap.xpt
 @BINPATH@/components/msglocal.xpt
 @BINPATH@/components/msgnews.xpt
 @BINPATH@/components/msgsearch.xpt
 @BINPATH@/components/msgsmime.xpt
 
 ; MailNews JS components
+@BINPATH@/components/folderLookupService.js
 @BINPATH@/components/mdn-service.js
 @BINPATH@/components/mdn-service.manifest
 @BINPATH@/components/msgAsyncPrompter.js
 @BINPATH@/components/newsblog.js
 @BINPATH@/components/newsblog.manifest
 @BINPATH@/components/nsAbAutoCompleteMyDomain.js
 @BINPATH@/components/nsAbAutoCompleteSearch.js
 @BINPATH@/components/nsAbLDAPAttributeMap.js