Bug 832034 - Add foldersCreatedAsync attribute to nsIMsgProtocolInfo to indicate servers using async folder creation and make the protocol info easily accessible from nsIMsgIncomingServer. r=rkent, r=Neil, sr=standard8
authoraceman <acelists@atlas.sk>
Sun, 14 Apr 2013 21:20:40 -0400
changeset 15759 d3b26176b0dfa932aee0156c84a218d362b424ba
parent 15758 96d7f4197146df55ce79c971e1ab28573d9f66b4
child 15760 feb408f0b984cffb99cb3cff83d242e60b466df2
push id165
push userCallek@gmail.com
push dateSun, 04 Aug 2013 02:17:16 +0000
reviewersrkent, Neil, standard8
bugs832034
Bug 832034 - Add foldersCreatedAsync attribute to nsIMsgProtocolInfo to indicate servers using async folder creation and make the protocol info easily accessible from nsIMsgIncomingServer. r=rkent, r=Neil, sr=standard8
mail/base/content/mailCommands.js
mail/base/content/mailWindowOverlay.js
mail/components/im/imProtocolInfo.js
mailnews/base/public/nsIMsgIncomingServer.idl
mailnews/base/public/nsIMsgProtocolInfo.idl
mailnews/base/util/nsMsgIncomingServer.cpp
mailnews/base/util/nsMsgIncomingServer.h
mailnews/base/util/nsMsgUtils.cpp
mailnews/compose/src/nsMsgCopy.cpp
mailnews/imap/src/nsImapService.cpp
mailnews/local/src/nsMovemailService.cpp
mailnews/local/src/nsNoneService.cpp
mailnews/local/src/nsPop3Service.cpp
mailnews/local/src/nsRssService.cpp
mailnews/news/src/nsNntpService.cpp
suite/mailnews/mailCommands.js
suite/mailnews/mailWindowOverlay.js
--- a/mail/base/content/mailCommands.js
+++ b/mail/base/content/mailCommands.js
@@ -395,19 +395,19 @@ saveAsUrlListener.prototype = {
 function SaveAsTemplate(uri) {
   if (uri) {
     const Ci = Components.interfaces;
     let hdr = messenger.msgHdrFromURI(uri);
     let identity = getIdentityForHeader(hdr, Ci.nsIMsgCompType.Template);
     let templates = MailUtils.getFolderForURI(identity.stationeryFolder, false);
     if (!templates.parent) {
       templates.setFlag(Ci.nsMsgFolderFlags.Templates);
-      let isImap = templates.server.type == "imap";
+      let isAsync = templates.server.protocolInfo.foldersCreatedAsync;
       templates.createStorageIfMissing(new saveAsUrlListener(uri, identity));
-      if (isImap)
+      if (isAsync)
         return;
     }
     messenger.saveAs(uri, false, identity, null);
   }
 }
 
 function MarkSelectedMessagesRead(markRead)
 {
--- a/mail/base/content/mailWindowOverlay.js
+++ b/mail/base/content/mailWindowOverlay.js
@@ -1648,56 +1648,56 @@ BatchMessageMover.prototype = {
     {
       this._currentKey = key;
       let batch = this._batches[key];
       let [srcFolder, archiveFolderUri, granularity, keepFolderStructure, msgYear, msgMonth] = batch;
       let msgs = batch.slice(6);
 
       let archiveFolder = GetMsgFolderFromUri(archiveFolderUri, false);
       let dstFolder = archiveFolder;
-      // For imap folders, we need to create the sub-folders asynchronously,
-      // so we chain the urls using the listener called back from
-      // createStorageIfMissing. For local, createStorageIfMissing is
-      // synchronous.
-      let isImap = archiveFolder.server.type == "imap";
+      // For folders on some servers (e.g. IMAP), we need to create the
+      // sub-folders asynchronously, so we chain the urls using the listener
+      // called back from createStorageIfMissing. For local,
+      // createStorageIfMissing is synchronous.
+      let isAsync = archiveFolder.server.protocolInfo.foldersCreatedAsync;
       if (!archiveFolder.parent)
       {
         archiveFolder.setFlag(Components.interfaces.nsMsgFolderFlags.Archive);
         archiveFolder.createStorageIfMissing(this);
-        if (isImap)
+        if (isAsync)
           return;
       }
 
       let forceSingle = !archiveFolder.canCreateSubfolders;
-      if (!forceSingle && isImap)
-        forceSingle = archiveFolder.server.QueryInterface(
-          Components.interfaces.nsIImapIncomingServer).isGMailServer;
+      if (!forceSingle && (archiveFolder.server instanceof
+          Components.interfaces.nsIImapIncomingServer))
+        forceSingle = archiveFolder.server.isGMailServer;
       if (forceSingle)
          granularity = Components.interfaces.nsIMsgIncomingServer
                                  .singleArchiveFolder;
 
       if (granularity >= Components.interfaces.nsIMsgIdentity.perYearArchiveFolders)
       {
         archiveFolderUri += "/" + msgYear;
         dstFolder = GetMsgFolderFromUri(archiveFolderUri, false);
         if (!dstFolder.parent)
         {
           dstFolder.createStorageIfMissing(this);
-          if (isImap)
+          if (isAsync)
             return;
         }
       }
       if (granularity >= Components.interfaces.nsIMsgIdentity.perMonthArchiveFolders)
       {
         archiveFolderUri += "/" + msgMonth;
         dstFolder = GetMsgFolderFromUri(archiveFolderUri, false);
         if (!dstFolder.parent)
         {
           dstFolder.createStorageIfMissing(this);
-          if (isImap)
+          if (isAsync)
             return;
         }
       }
 
       // Create the folder structure in Archives
       // For imap folders, we need to create the sub-folders asynchronously,
       // so we chain the actions using the listener called back from
       // createSubfolder. For local, createSubfolder is synchronous.
@@ -1716,23 +1716,23 @@ BatchMessageMover.prototype = {
         }
         // Determine Archive folder structure
         for (let i = 0; i < folderNames.length; ++i)
         {
           let folderName = folderNames[i];
           if (!dstFolder.containsChildNamed(folderName))
           {
             // Create Archive sub-folder (IMAP: async)
-            if (isImap)
+            if (isAsync)
             {
               this._dstFolderParent = dstFolder;
               this._dstFolderName = folderName;
             }
             dstFolder.createSubfolder(folderName, msgWindow);
-            if (isImap)
+            if (isAsync)
               return;
           }
           dstFolder = dstFolder.getChildNamed(folderName);
         }
       }
 
       if (dstFolder != srcFolder)
       {
--- a/mail/components/im/imProtocolInfo.js
+++ b/mail/components/im/imProtocolInfo.js
@@ -20,16 +20,17 @@ imProtocolInfo.prototype = {
   // IM accounts.
   get canLoginAtStartUp() false,
   get canDuplicate() false,
   getDefaultServerPort: function() 0,
   get canGetMessages() false,
   get canGetIncomingMessages() false,
   get defaultDoBiff() false,
   get showComposeMsgLink() false,
+  get foldersCreatedAsync() false,
 
   classDescription: "IM Msg Protocol Info implementation",
   classID: Components.ID("{13118758-dad2-418c-a03d-1acbfed0cd01}"),
   contractID: "@mozilla.org/messenger/protocol/info;1?type=im",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMsgProtocolInfo])
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([imProtocolInfo]);
--- a/mailnews/base/public/nsIMsgIncomingServer.idl
+++ b/mailnews/base/public/nsIMsgIncomingServer.idl
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "MailNewsTypes2.idl"
 
 interface nsIMsgFolder;
 interface nsIMsgFolderCache;
 interface nsIMsgWindow;
+interface nsIMsgProtocolInfo;
 interface nsIMsgFilterList;
 interface nsIMsgRetentionSettings;
 interface nsIMsgDownloadSettings;
 interface nsISpamSettings;
 interface nsIMsgFilterPlugin;
 interface nsIUrlListener;
 interface nsIMsgDBHdr;
 interface nsIFile;
@@ -21,17 +22,17 @@ interface nsIURI;
 interface nsIMsgPluggableStore;
 
 /*
  * Interface for incoming mail/news host
  * this is the base interface for all mail server types (imap, pop, nntp, etc)
  * often you will want to add extra interfaces that give you server-specific
  * attributes and methods.
  */
-[scriptable, uuid(92f4ee31-a14d-48dc-8676-22417caefa83)]
+[scriptable, uuid(92f4ee31-a14d-48dc-8676-22417caefa84)]
 interface nsIMsgIncomingServer : nsISupports {
 
   /**
    * internal pref key - guaranteed to be unique across all servers
    */
   attribute ACString key;
 
   /**
@@ -70,16 +71,21 @@ interface nsIMsgIncomingServer : nsISupp
   attribute ACString realUsername;
 
   /**
    * protocol type, i.e. "pop3", "imap", "nntp", "none", etc
    * used to construct URLs
    */
   attribute ACString type;
 
+  /**
+   * The proper instance of nsIMsgProtocolInfo corresponding to this server type.
+   */
+  readonly attribute nsIMsgProtocolInfo protocolInfo;
+
   readonly attribute AString accountManagerChrome;
 
   /**
    * the schema for the local mail store, such
    * as "mailbox", "imap", or "news"
    * used to construct URIs
    */
   readonly attribute ACString localStoreType;
--- a/mailnews/base/public/nsIMsgProtocolInfo.idl
+++ b/mailnews/base/public/nsIMsgProtocolInfo.idl
@@ -8,17 +8,17 @@
 interface nsIFile;
 
 %{C++
 #define NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX \
   "@mozilla.org/messenger/protocol/info;1?type="
 %}
 
 
-[scriptable, uuid(9428b5f5-8b12-493c-aae2-18296c2877b0)]
+[scriptable, uuid(9428b5f5-8b12-493c-aae2-18296c2877b1)]
 interface nsIMsgProtocolInfo : nsISupports
 {
     /**
      * the default path to store local data for this type of
      * server. Each server is usually in a subdirectory below this
      */
     attribute nsIFile defaultLocalPath;
 
@@ -85,10 +85,15 @@ interface nsIMsgProtocolInfo : nsISuppor
      * do biff by default?
      */
     readonly attribute boolean defaultDoBiff;
 
     /**
      * do we need to show compose message link in the AccountCentral page ? 
      */
     readonly attribute boolean showComposeMsgLink;
+
+    /**
+     * Will new folders be created asynchronously?
+     */
+    readonly attribute boolean foldersCreatedAsync;
 };
 
--- a/mailnews/base/util/nsMsgIncomingServer.cpp
+++ b/mailnews/base/util/nsMsgIncomingServer.cpp
@@ -880,17 +880,17 @@ nsMsgIncomingServer::ForgetSessionPasswo
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMsgIncomingServer::SetDefaultLocalPath(nsIFile *aDefaultLocalPath)
 {
   nsresult rv;
   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
-  rv = getProtocolInfo(getter_AddRefs(protocolInfo));
+  rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
   NS_ENSURE_SUCCESS(rv, rv);
   return protocolInfo->SetDefaultLocalPath(aDefaultLocalPath);
 }
 
 NS_IMETHODIMP
 nsMsgIncomingServer::GetLocalPath(nsIFile **aLocalPath)
 {
   nsresult rv;
@@ -900,17 +900,17 @@ nsMsgIncomingServer::GetLocalPath(nsIFil
   if (NS_SUCCEEDED(rv) && *aLocalPath)
     return rv;
 
   // otherwise, create the path using the protocol info.
   // note we are using the
   // hostname, unless that directory exists.
 // this should prevent all collisions.
   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
-  rv = getProtocolInfo(getter_AddRefs(protocolInfo));
+  rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFile> localPath;
   rv = protocolInfo->GetDefaultLocalPath(getter_AddRefs(localPath));
   NS_ENSURE_SUCCESS(rv, rv);
   localPath->Create(nsIFile::DIRECTORY_TYPE, 0755);
 
   nsCString hostname;
@@ -1352,17 +1352,17 @@ nsMsgIncomingServer::GetDoBiff(bool *aDo
 
   rv = mPrefBranch->GetBoolPref(BIFF_PREF_NAME, aDoBiff);
   if (NS_SUCCEEDED(rv))
     return rv;
 
   // if the pref isn't set, use the default
   // value based on the protocol
   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
-  rv = getProtocolInfo(getter_AddRefs(protocolInfo));
+  rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = protocolInfo->GetDefaultDoBiff(aDoBiff);
   // note, don't call SetDoBiff()
   // since we keep changing our minds on
   // if biff should be on or off, let's keep the ability
   // to change the default in future builds.
   // if we call SetDoBiff() here, it will be in the users prefs.
@@ -1388,61 +1388,61 @@ nsMsgIncomingServer::GetPort(int32_t *aP
   rv = GetIntValue("port", aPort);
   // We can't use a port of 0, because the URI parsing code fails.
   if (*aPort != PORT_NOT_SET && *aPort)
     return rv;
 
   // if the port isn't set, use the default
   // port based on the protocol
   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
-  rv = getProtocolInfo(getter_AddRefs(protocolInfo));
+  rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t socketType;
   rv = GetSocketType(&socketType);
   NS_ENSURE_SUCCESS(rv, rv);
   bool useSSLPort = (socketType == nsMsgSocketType::SSL);
   return protocolInfo->GetDefaultServerPort(useSSLPort, aPort);
 }
 
 NS_IMETHODIMP
 nsMsgIncomingServer::SetPort(int32_t aPort)
 {
   nsresult rv;
 
   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
-  rv = getProtocolInfo(getter_AddRefs(protocolInfo));
+  rv = GetProtocolInfo(getter_AddRefs(protocolInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t socketType;
   rv = GetSocketType(&socketType);
   NS_ENSURE_SUCCESS(rv, rv);
   bool useSSLPort = (socketType == nsMsgSocketType::SSL);
 
   int32_t defaultPort;
   protocolInfo->GetDefaultServerPort(useSSLPort, &defaultPort);
   return SetIntValue("port", aPort == defaultPort ? PORT_NOT_SET : aPort);
 }
 
-nsresult
-nsMsgIncomingServer::getProtocolInfo(nsIMsgProtocolInfo **aResult)
+NS_IMETHODIMP
+nsMsgIncomingServer::GetProtocolInfo(nsIMsgProtocolInfo **aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
-  nsresult rv;
 
   nsCString type;
-  rv = GetType(type);
+  nsresult rv = GetType(type);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX);
   contractid.Append(type);
 
   nsCOMPtr<nsIMsgProtocolInfo> protocolInfo = do_GetService(contractid.get(), &rv);
   NS_ENSURE_SUCCESS(rv, rv);
-  protocolInfo.swap(*aResult);
+
+  protocolInfo.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgIncomingServer::GetRetentionSettings(nsIMsgRetentionSettings **settings)
 {
   NS_ENSURE_ARG_POINTER(settings);
   nsMsgRetainByPreference retainByPreference;
   int32_t daysToKeepHdrs = 0;
--- a/mailnews/base/util/nsMsgIncomingServer.h
+++ b/mailnews/base/util/nsMsgIncomingServer.h
@@ -66,17 +66,16 @@ protected:
   static nsresult GetDeferredServers(nsIMsgIncomingServer *destServer, nsCOMArray<nsIPop3IncomingServer>& aServers);
 
   nsresult CreateRootFolder();
   virtual nsresult CreateRootFolderFromUri(const nsCString &serverUri,
                                            nsIMsgFolder **rootFolder) = 0;
 
   nsresult InternalSetHostName(const nsACString& aHostname, const char * prefName);
 
-  nsresult getProtocolInfo(nsIMsgProtocolInfo **aResult);
   nsCOMPtr <nsIFile> mFilterFile;
   nsCOMPtr <nsIMsgFilterList> mFilterList;
   nsCOMPtr <nsIMsgFilterList> mEditableFilterList;
   nsCOMPtr<nsIPrefBranch> mPrefBranch;
   nsCOMPtr<nsIPrefBranch> mDefPrefBranch;
 
   // these allow us to handle duplicate incoming messages, e.g. delete them.
   nsDataHashtable<nsCStringHashKey,int32_t> m_downloadedHdrs;
--- a/mailnews/base/util/nsMsgUtils.cpp
+++ b/mailnews/base/util/nsMsgUtils.cpp
@@ -35,16 +35,17 @@
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISpamSettings.h"
 #include "nsICryptoHash.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIRssIncomingServer.h"
 #include "nsIMsgFolder.h"
+#include "nsIMsgProtocolInfo.h"
 #include "nsIMsgMessageService.h"
 #include "nsIMsgAccountManager.h"
 #include "nsIOutputStream.h"
 #include "nsMsgFileStream.h"
 #include "nsIFileURL.h"
 #include "nsNetUtil.h"
 #include "nsIProtocolProxyService2.h"
 #include "nsIMsgDatabase.h"
@@ -954,26 +955,29 @@ GetOrCreateFolder(const nsACString &aURI
   rv = msgFolder->GetParent(getter_AddRefs(parent));
   if (NS_FAILED(rv) || !parent)
   {
     nsCOMPtr <nsIFile> folderPath;
     // for local folders, path is to the berkeley mailbox.
     // for imap folders, path needs to have .msf appended to the name
     msgFolder->GetFilePath(getter_AddRefs(folderPath));
 
-    nsCString type;
-    rv = server->GetType(type);
-    NS_ENSURE_SUCCESS(rv,rv);
+    nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
+    rv = server->GetProtocolInfo(getter_AddRefs(protocolInfo));
+    NS_ENSURE_SUCCESS(rv, rv);
 
-    bool isImapFolder = type.Equals("imap");
+    bool isAsyncFolder;
+    rv = protocolInfo->GetFoldersCreatedAsync(&isAsyncFolder);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     // if we can't get the path from the folder, then try to create the storage.
     // for imap, it doesn't matter if the .msf file exists - it still might not
     // exist on the server, so we should try to create it
     bool exists = false;
-    if (!isImapFolder && folderPath)
+    if (!isAsyncFolder && folderPath)
       folderPath->Exists(&exists);
     if (!exists)
     {
       // Hack to work around a localization bug with the Junk Folder.
       // Please see Bug #270261 for more information...
       nsString localizedJunkName;
       msgFolder->GetName(localizedJunkName);
 
@@ -991,17 +995,17 @@ GetOrCreateFolder(const nsACString &aURI
       // ugh, I hate this hack
       // we have to do this (for now)
       // because imap and local are different (one creates folder asynch, the other synch)
       // one will notify the listener, one will not.
       // I blame nsMsgCopy.
       // we should look into making it so no matter what the folder type
       // we always call the listener
       // this code should move into local folder's version of CreateStorageIfMissing()
-      if (!isImapFolder && aListener) {
+      if (!isAsyncFolder && aListener) {
         rv = aListener->OnStartRunningUrl(nullptr);
         NS_ENSURE_SUCCESS(rv,rv);
 
         rv = aListener->OnStopRunningUrl(nullptr, NS_OK);
         NS_ENSURE_SUCCESS(rv,rv);
       }
     }
   }
--- a/mailnews/compose/src/nsMsgCopy.cpp
+++ b/mailnews/compose/src/nsMsgCopy.cpp
@@ -6,16 +6,17 @@
 
 #include "nsCOMPtr.h"
 #include "nsMsgBaseCID.h"
 #include "nsMsgFolderFlags.h"
 #include "nsIMsgFolder.h"
 #include "nsIMsgAccountManager.h"
 #include "nsIMsgFolder.h"
 #include "nsIMsgIncomingServer.h"
+#include "nsIMsgProtocolInfo.h"
 #include "nsISupports.h"
 #include "nsIRDFService.h"
 #include "nsIRDFResource.h"
 #include "nsRDFCID.h"
 #include "nsIURL.h"
 #include "nsNetCID.h"
 #include "nsMsgCompUtils.h"
 #include "prcmon.h"
@@ -357,45 +358,57 @@ nsMsgCopy::GetSentFolder(nsIMsgIdentity 
   }
   CreateIfMissing(folder, waitForUrl);
   return ret;
 }
 
 nsresult
 nsMsgCopy::CreateIfMissing(nsIMsgFolder **folder, bool *waitForUrl)
 {
-  nsresult ret = NS_OK;
+  nsresult rv = NS_OK;
   if (folder && *folder)
   {
-    nsCOMPtr <nsIMsgFolder> parent;
+    nsCOMPtr<nsIMsgFolder> parent;
     (*folder)->GetParent(getter_AddRefs(parent));
     if (!parent)
     {
-      nsCOMPtr <nsIFile> folderPath;
+      nsCOMPtr<nsIFile> folderPath;
       // for local folders, path is to the berkeley mailbox.
       // for imap folders, path needs to have .msf appended to the name
       (*folder)->GetFilePath(getter_AddRefs(folderPath));
-        bool isImapFolder = !PL_strncasecmp(mSavePref, "imap:", 5);
+
+      nsCOMPtr<nsIMsgIncomingServer> server;
+      rv = (*folder)->GetServer(getter_AddRefs(server));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
+      rv = server->GetProtocolInfo(getter_AddRefs(protocolInfo));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      bool isAsyncFolder;
+      rv = protocolInfo->GetFoldersCreatedAsync(&isAsyncFolder);
+      NS_ENSURE_SUCCESS(rv, rv);
+
       // if we can't get the path from the folder, then try to create the storage.
       // for imap, it doesn't matter if the .msf file exists - it still might not
       // exist on the server, so we should try to create it
       bool exists = false;
-      if (!isImapFolder && folderPath)
+      if (!isAsyncFolder && folderPath)
         folderPath->Exists(&exists);
         if (!exists)
         {
           (*folder)->CreateStorageIfMissing(this);
-          if (isImapFolder)
+          if (isAsyncFolder)
             *waitForUrl = true;
 
-          ret = NS_OK;
+          rv = NS_OK;
         }
       }
     }
-  return ret;
+  return rv;
 }
 ////////////////////////////////////////////////////////////////////////////////////
 // Utility Functions for MsgFolders
 ////////////////////////////////////////////////////////////////////////////////////
 nsresult
 LocateMessageFolder(nsIMsgIdentity   *userIdentity,
                     nsMsgDeliverMode aFolderType,
                     const char       *aFolderURI,
--- a/mailnews/imap/src/nsImapService.cpp
+++ b/mailnews/imap/src/nsImapService.cpp
@@ -2934,16 +2934,23 @@ NS_IMETHODIMP nsImapService::GetCanGetIn
 
 NS_IMETHODIMP nsImapService::GetShowComposeMsgLink(bool *showComposeMsgLink)
 {
   NS_ENSURE_ARG_POINTER(showComposeMsgLink);
   *showComposeMsgLink = true;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsImapService::GetFoldersCreatedAsync(bool *aAsyncCreation)
+{
+  NS_ENSURE_ARG_POINTER(aAsyncCreation);
+  *aAsyncCreation = true;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsImapService::GetListOfFoldersWithPath(nsIImapIncomingServer *aServer, 
                                                       nsIMsgWindow *aMsgWindow, 
                                                       const nsACString &folderPath)
 {
   nsresult rv;
   nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(aServer);
   if (!server) 
     return NS_ERROR_FAILURE;
--- a/mailnews/local/src/nsMovemailService.cpp
+++ b/mailnews/local/src/nsMovemailService.cpp
@@ -628,8 +628,16 @@ nsMovemailService::GetDefaultServerPort(
 
 NS_IMETHODIMP
 nsMovemailService::GetShowComposeMsgLink(bool *showComposeMsgLink)
 {
   NS_ENSURE_ARG_POINTER(showComposeMsgLink);
   *showComposeMsgLink = true;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsMovemailService::GetFoldersCreatedAsync(bool *aAsyncCreation)
+{
+  NS_ENSURE_ARG_POINTER(aAsyncCreation);
+  *aAsyncCreation = false;
+  return NS_OK;
+}
--- a/mailnews/local/src/nsNoneService.cpp
+++ b/mailnews/local/src/nsNoneService.cpp
@@ -153,8 +153,16 @@ nsNoneService::GetDefaultServerPort(bool
 
 NS_IMETHODIMP 
 nsNoneService::GetShowComposeMsgLink(bool *showComposeMsgLink)
 {
     NS_ENSURE_ARG_POINTER(showComposeMsgLink);
     *showComposeMsgLink = false;    
     return NS_OK;
 }
+
+NS_IMETHODIMP
+nsNoneService::GetFoldersCreatedAsync(bool *aAsyncCreation)
+{
+  NS_ENSURE_ARG_POINTER(aAsyncCreation);
+  *aAsyncCreation = false;
+  return NS_OK;
+}
--- a/mailnews/local/src/nsPop3Service.cpp
+++ b/mailnews/local/src/nsPop3Service.cpp
@@ -604,16 +604,24 @@ NS_IMETHODIMP
 nsPop3Service::GetShowComposeMsgLink(bool *showComposeMsgLink)
 {
     NS_ENSURE_ARG_POINTER(showComposeMsgLink);
     *showComposeMsgLink = true;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsPop3Service::GetFoldersCreatedAsync(bool *aAsyncCreation)
+{
+  NS_ENSURE_ARG_POINTER(aAsyncCreation);
+  *aAsyncCreation = false;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsPop3Service::GetDefaultServerPort(bool isSecure, int32_t *aPort)
 {
     NS_ENSURE_ARG_POINTER(aPort);
 
     if (!isSecure)
       return GetDefaultPort(aPort);
 
     *aPort = nsIPop3URL::DEFAULT_POP3S_PORT;
--- a/mailnews/local/src/nsRssService.cpp
+++ b/mailnews/local/src/nsRssService.cpp
@@ -114,8 +114,15 @@ NS_IMETHODIMP nsRssService::GetDefaultDo
 }
 
 NS_IMETHODIMP nsRssService::GetShowComposeMsgLink(bool *aShowComposeMsgLink)
 {
     NS_ENSURE_ARG_POINTER(aShowComposeMsgLink);
     *aShowComposeMsgLink = false;    
     return NS_OK;
 }
+
+NS_IMETHODIMP nsRssService::GetFoldersCreatedAsync(bool *aAsyncCreation)
+{
+  NS_ENSURE_ARG_POINTER(aAsyncCreation);
+  *aAsyncCreation = false;
+  return NS_OK;
+}
--- a/mailnews/news/src/nsNntpService.cpp
+++ b/mailnews/news/src/nsNntpService.cpp
@@ -1354,16 +1354,24 @@ nsNntpService::GetCanGetIncomingMessages
 NS_IMETHODIMP
 nsNntpService::GetShowComposeMsgLink(bool *showComposeMsgLink)
 {
     NS_ENSURE_ARG_POINTER(showComposeMsgLink);
     *showComposeMsgLink = false;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNntpService::GetFoldersCreatedAsync(bool *aAsyncCreation)
+{
+  NS_ENSURE_ARG_POINTER(aAsyncCreation);
+  *aAsyncCreation = false;
+  return NS_OK;
+}
+
 //
 // rhp: Right now, this is the same as simple DisplayMessage, but it will change
 // to support print rendering.
 //
 NS_IMETHODIMP nsNntpService::DisplayMessageForPrinting(const char* aMessageURI, nsISupports * aDisplayConsumer,
                                                   nsIMsgWindow *aMsgWindow, nsIUrlListener * aUrlListener, nsIURI ** aURL)
 {
   mPrintingOperation = true;
--- a/suite/mailnews/mailCommands.js
+++ b/suite/mailnews/mailCommands.js
@@ -374,19 +374,19 @@ function SaveAsTemplate(uri)
   if (uri)
   {
     var hdr = messenger.msgHdrFromURI(uri);
     var identity = GetIdentityForHeader(hdr, Components.interfaces.nsIMsgCompType.Template);
     var templates = MailUtils.getFolderForURI(identity.stationeryFolder, false);
     if (!templates.parent)
     {
       templates.setFlag(Components.interfaces.nsMsgFolderFlags.Templates);
-      let isImap = templates.server.type == "imap";
+      let isAsync = templates.server.protocolInfo.foldersCreatedAsync;
       templates.createStorageIfMissing(new saveAsUrlListener(uri, identity));
-      if (isImap)
+      if (isAsync)
         return;
     }
     messenger.saveAs(uri, false, identity, null);
   }
 }
 
 function MarkSelectedMessagesRead(markRead)
 {
--- a/suite/mailnews/mailWindowOverlay.js
+++ b/suite/mailnews/mailWindowOverlay.js
@@ -1174,49 +1174,49 @@ BatchMessageMover.prototype =
     {
       this._currentKey = key;
       let batch = this._batches[key];
       let [srcFolder, archiveFolderUri, granularity, keepFolderStructure, msgYear, msgMonth] = batch;
       let msgs = batch.slice(6);
 
       let archiveFolder = GetMsgFolderFromUri(archiveFolderUri, false);
       let dstFolder = archiveFolder;
-      // For imap folders, we need to create the sub-folders asynchronously,
-      // so we chain the urls using the listener called back from 
-      // createStorageIfMissing. For local, createStorageIfMissing is
-      // synchronous.
-      let isImap = archiveFolder.server.type == "imap";
+      // For folders on some servers (e.g. IMAP), we need to create the
+      // sub-folders asynchronously, so we chain the urls using the listener
+      // called back from createStorageIfMissing. For local,
+      // createStorageIfMissing is synchronous.
+      let isAsync = archiveFolder.server.protocolInfo.foldersCreatedAsync;
       if (!archiveFolder.parent)
       {
         archiveFolder.setFlag(Components.interfaces.nsMsgFolderFlags.Archive);
         archiveFolder.createStorageIfMissing(this);
-        if (isImap)
+        if (isAsync)
           return;
       }
       if (!archiveFolder.canCreateSubfolders)
         granularity = Components.interfaces.nsIMsgIdentity.singleArchiveFolder;
       if (granularity >= Components.interfaces.nsIMsgIdentity.perYearArchiveFolders)
       {
         archiveFolderUri += "/" + msgYear;
         dstFolder = GetMsgFolderFromUri(archiveFolderUri, false);
         if (!dstFolder.parent)
         {
           dstFolder.createStorageIfMissing(this);
-          if (isImap)
+          if (isAsync)
             return;
         }
       }
       if (granularity >= Components.interfaces.nsIMsgIdentity.perMonthArchiveFolders)
       {
         archiveFolderUri += "/" + msgMonth;
         dstFolder = GetMsgFolderFromUri(archiveFolderUri, false);
         if (!dstFolder.parent)
         {
           dstFolder.createStorageIfMissing(this);
-          if (isImap)
+          if (isAsync)
             return;
         }
       }
 
       // Create the folder structure in Archives
       // For imap folders, we need to create the sub-folders asynchronously,
       // so we chain the actions using the listener called back from 
       // createSubfolder. For local, createSubfolder is synchronous.
@@ -1234,24 +1234,24 @@ BatchMessageMover.prototype =
           folder = folder.parent;
         }
         // Determine Archive folder structure
         for (let i = 0; i < folderNames.length; ++i)
         {
           let folderName = folderNames[i];
           if (!dstFolder.containsChildNamed(folderName))
           {
-            // Create Archive sub-folder (IMAP: async) 
-            if (isImap)
+            // Create Archive sub-folder (IMAP: async)
+            if (isAsync)
             {
               this._dstFolderParent = dstFolder;
               this._dstFolderName = folderName;
             }
             dstFolder.createSubfolder(folderName, msgWindow);
-            if (isImap)
+            if (isAsync)
               return;
           }
           dstFolder = dstFolder.getChildNamed(folderName);
         }
       }
 
       if (dstFolder != srcFolder)
       {