re-enable imap subscription for servers that support xlist, r/sr=standard8, 493455
authorDavid Bienvenu <bienvenu@nventure.com>
Sat, 29 Aug 2009 11:57:46 -0700
changeset 3449 880ac704c5b75ddc9a19010239998daa1f16a027
parent 3448 2387346503a05714bde3821ed813357d6d5b3057
child 3450 8f4aadd44e102040752f31290d21491b62b187e1
push idunknown
push userunknown
push dateunknown
bugs493455
re-enable imap subscription for servers that support xlist, r/sr=standard8, 493455
mailnews/imap/src/nsImapProtocol.cpp
mailnews/imap/src/nsImapProtocol.h
--- a/mailnews/imap/src/nsImapProtocol.cpp
+++ b/mailnews/imap/src/nsImapProtocol.cpp
@@ -465,16 +465,17 @@ nsImapProtocol::nsImapProtocol() : nsMsg
   m_inputStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, PR_TRUE /* allocate new lines */, PR_FALSE /* leave CRLFs on the returned string */);
   m_currentBiffState = nsIMsgFolder::nsMsgBiffState_Unknown;
   m_progressStringId = 0;
 
   // since these are embedded in the nsImapProtocol object, but passed
   // through proxied xpcom methods, just AddRef them here.
   m_hdrDownloadCache = new nsMsgImapHdrXferInfo();
   m_downloadLineCache = new nsMsgImapLineDownloadCache();
+  m_specialXListMailboxes.Init(0);
 
   // subscription
   m_autoSubscribe = PR_TRUE;
   m_autoUnsubscribe = PR_TRUE;
   m_autoSubscribeOnOpen = PR_TRUE;
   m_deletableChildren = nsnull;
 
   mFolderLastModSeq = 0;
@@ -4733,16 +4734,24 @@ nsImapProtocol::DiscoverMailboxSpec(nsIm
     return;
 
   m_hostSessionList->GetDefaultNamespaceOfTypeForHost(
     GetImapServerKey(), kPersonalNamespace, ns);
   const char *nsPrefix = ns ? ns->GetPrefix() : 0;
 
   switch (m_hierarchyNameState)
   {
+  case kXListing:
+    if (adoptedBoxSpec->mBoxFlags &
+        (kImapXListTrash|kImapAllMail|kImapInbox|kImapSent|kImapSpam|kImapDrafts))
+    {
+      nsCString mailboxName(adoptedBoxSpec->mAllocatedPathName);
+      m_specialXListMailboxes.Put(mailboxName, adoptedBoxSpec->mBoxFlags);
+    }
+    break;
   case kListingForCreate:
   case kNoOperationInProgress:
   case kDiscoverTrashFolderInProgress:
   case kListingForInfoAndDiscovery:
     {
       if (ns && nsPrefix) // if no personal namespace, there can be no Trash folder
       {
         PRBool onlineTrashFolderExists = PR_FALSE;
@@ -4797,16 +4806,25 @@ nsImapProtocol::DiscoverMailboxSpec(nsIm
       if (!adoptedBoxSpec->mAllocatedPathName.IsEmpty())
       {
         if (m_hierarchyNameState == kListingForCreate)
           adoptedBoxSpec->mBoxFlags |= kNewlyCreatedFolder;
 
         if (m_imapServerSink)
         {
           PRBool newFolder;
+
+          if (m_specialXListMailboxes.Count() > 0)
+          {
+            PRInt32 hashValue = 0;
+            nsCString strHashKey(adoptedBoxSpec->mAllocatedPathName);
+            m_specialXListMailboxes.Get(strHashKey, &hashValue);
+            adoptedBoxSpec->mBoxFlags |= hashValue;
+          }
+
           m_imapServerSink->PossibleImapMailbox(adoptedBoxSpec->mAllocatedPathName,
                                                 adoptedBoxSpec->mHierarchySeparator,
                                                 adoptedBoxSpec->mBoxFlags, &newFolder);
           // if it's a new folder to the server sink, setting discovery status to
           // eContinueNew will cause us to get the ACL for the new folder.
           if (newFolder)
             SetMailboxDiscoveryStatus(eContinueNew);
 
@@ -6944,29 +6962,35 @@ void nsImapProtocol::DiscoverAllAndSubsc
 // and also when the user manually requests a re-sync, by collapsing and
 // expanding a host in the folder pane.  This is not used for the subscribe
 // pane.
 // DiscoverMailboxList() also gets the ACLs for each newly discovered folder
 void nsImapProtocol::DiscoverMailboxList()
 {
   PRBool usingSubscription = PR_FALSE;
 
+  m_hostSessionList->GetHostIsUsingSubscription(GetImapServerKey(), usingSubscription);
   // should we check a pref here, to be able to turn off XList?
-  if (GetServerStateParser().GetCapabilityFlag() & kHasXListCapability)
-    m_hostSessionList->SetHostIsUsingSubscription(GetImapServerKey(), PR_FALSE);
+  PRBool hasXLIST = GetServerStateParser().GetCapabilityFlag() & kHasXListCapability;
+  if (hasXLIST && usingSubscription)
+  {
+    m_hierarchyNameState = kXListing;
+    // We use "%.%" since gmail special folders are unlikely
+    // to be more than 2 levels deep.
+    List("%.%", PR_TRUE, PR_TRUE);
+  }
 
   SetMailboxDiscoveryStatus(eContinue);
   if (GetServerStateParser().ServerHasACLCapability())
     m_hierarchyNameState = kListingForInfoAndDiscovery;
   else
     m_hierarchyNameState = kNoOperationInProgress;
 
   // Pretend that the Trash folder doesn't exist, so we will rediscover it if we need to.
   m_hostSessionList->SetOnlineTrashFolderExistsForHost(GetImapServerKey(), PR_FALSE);
-  m_hostSessionList->GetHostIsUsingSubscription(GetImapServerKey(), usingSubscription);
 
   // iterate through all namespaces and LSUB them.
   PRUint32 count = 0;
   m_hostSessionList->GetNumberOfNamespacesForHost(GetImapServerKey(), count);
   for (PRUint32 i = 0; i < count; i++ )
   {
     nsIMAPNamespace * ns = nsnull;
     m_hostSessionList->GetNamespaceNumberForHost(GetImapServerKey(),i,ns);
@@ -7051,18 +7075,18 @@ void nsImapProtocol::DiscoverMailboxList
             pattern2 += "%";
             // pattern2 = PR_smprintf("%s%%%c%%", prefix, delimiter);
           }
         }
         if (usingSubscription) // && !GetSubscribingNow())  should never get here from subscribe pane
           Lsub(pattern.get(), PR_TRUE);
         else
         {
-          List(pattern.get(), PR_TRUE);
-          List(pattern2.get(), PR_TRUE);
+          List(pattern.get(), PR_TRUE, hasXLIST);
+          List(pattern2.get(), PR_TRUE, hasXLIST);
         }
       }
     }
   }
 
   // explicitly LIST the INBOX if (a) we're not using subscription, or (b) we are using subscription and
   // the user wants us to always show the INBOX.
   PRBool listInboxForHost = PR_FALSE;
@@ -7337,33 +7361,34 @@ void nsImapProtocol::Lsub(const char *ma
 
   PR_Free(boxnameWithOnlineDirectory);
 
   nsresult rv = SendData(command.get());
   if (NS_SUCCEEDED(rv))
     ParseIMAPandCheckForNewMail();
 }
 
-void nsImapProtocol::List(const char *mailboxPattern, PRBool addDirectoryIfNecessary)
+void nsImapProtocol::List(const char *mailboxPattern, PRBool addDirectoryIfNecessary,
+                          PRBool useXLIST)
 {
   ProgressEventFunctionUsingId (IMAP_STATUS_LOOKING_FOR_MAILBOX);
 
   IncrementCommandTagNumber();
 
   char *boxnameWithOnlineDirectory = nsnull;
   if (addDirectoryIfNecessary)
     m_runningUrl->AddOnlineDirectoryIfNecessary(mailboxPattern, &boxnameWithOnlineDirectory);
 
   nsCString escapedPattern;
   CreateEscapedMailboxName(boxnameWithOnlineDirectory ?
                         boxnameWithOnlineDirectory :
                         mailboxPattern, escapedPattern);
 
   nsCString command (GetServerCommandTag());
-  command += GetServerStateParser().GetCapabilityFlag() & kHasXListCapability ?
+  command += useXLIST ?
     " xlist \"\" \"" : " list \"\" \"";
   command += escapedPattern;
   command += "\""CRLF;
 
   PR_Free(boxnameWithOnlineDirectory);
 
   nsresult rv = SendData(command.get());
   if (NS_SUCCEEDED(rv))
--- a/mailnews/imap/src/nsImapProtocol.h
+++ b/mailnews/imap/src/nsImapProtocol.h
@@ -539,17 +539,18 @@ private:
   char * CreatePossibleTrashName(const char *prefix);
   const char * GetTrashFolderName();
   PRBool FolderNeedsACLInitialized(const char *folderName);
   void DiscoverMailboxList();
   void DiscoverAllAndSubscribedBoxes();
   void MailboxDiscoveryFinished();
   void NthLevelChildList(const char *onlineMailboxPrefix, PRInt32 depth);
   void Lsub(const char *mailboxPattern, PRBool addDirectoryIfNecessary);
-  void List(const char *mailboxPattern, PRBool addDirectoryIfNecessary);
+  void List(const char *mailboxPattern, PRBool addDirectoryIfNecessary,
+            PRBool useXLIST = PR_FALSE);
   void Subscribe(const char *mailboxName);
   void Unsubscribe(const char *mailboxName);
   void Idle();
   void EndIdle(PRBool waitForResponse = PR_TRUE);
   // Some imap servers include the mailboxName following the dir-separator in the list of
   // subfolders of the mailboxName. In fact, they are the same. So we should decide if
   // we should delete such subfolder and provide feedback if the delete operation succeed.
   PRBool DeleteSubFolders(const char* aMailboxName, PRBool & aDeleteSelf);
@@ -596,16 +597,18 @@ private:
   PRBool  m_ignoreExpunges;
   PRBool  m_useSecAuth;
   PRInt32 m_socketType;
   PRInt32 m_chunkSize;
   PRInt32 m_chunkThreshold;
   nsRefPtr <nsMsgImapLineDownloadCache> m_downloadLineCache;
   nsRefPtr <nsMsgImapHdrXferInfo> m_hdrDownloadCache;
   nsCOMPtr <nsIImapHeaderInfo> m_curHdrInfo;
+  // mapping between special xlist mailboxes and the corresponding folder flag
+  nsDataHashtable<nsCStringHashKey, PRInt32> m_specialXListMailboxes;
 
   nsIImapHostSessionList * m_hostSessionList;
 
   PRBool m_fromHeaderSeen;
 
   // these settings allow clients to override various pieces of the connection info from the url
   PRBool m_overRideUrlConnectionInfo;
 
@@ -639,16 +642,17 @@ private:
   enum EMailboxHierarchyNameState {
     kNoOperationInProgress,
       kDiscoverBaseFolderInProgress,
       kDiscoverTrashFolderInProgress,
       kDeleteSubFoldersInProgress,
       kListingForInfoOnly,
       kListingForInfoAndDiscovery,
       kDiscoveringNamespacesOnly,
+      kXListing,
       kListingForCreate
   };
   EMailboxHierarchyNameState  m_hierarchyNameState;
   EMailboxDiscoverStatus      m_discoveryStatus;
   nsVoidArray                 m_listedMailboxList;
   nsVoidArray*                m_deletableChildren;
   PRUint32                    m_flagChangeCount;
   PRTime                      m_lastCheckTime;