Bug 1360117 - Improve detection of servers requiring additional IMAP select. r=jorgk
authorGene Smith <gds@chartertn.net>
Thu, 04 May 2017 02:20:02 -0400
changeset 21521 edc74844fc0aa021de8276df7305ed1e445f5768
parent 21520 a4cdf9a9fe666b2b1e045d6fae82406130ea1398
child 21522 34153f64820674523909b789c68f58e8f0c1af01
push id13102
push usermozilla@jorgk.com
push dateThu, 04 May 2017 07:14:06 +0000
treeherdercomm-central@34153f648206 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorgk
bugs1360117
Bug 1360117 - Improve detection of servers requiring additional IMAP select. r=jorgk Removes advance server option to force IMAP select and allows automatic detection based on identifier string in the IMAP ID response from servers. All control is now done via config editor: force an extra select for server, preclude extra select for server, or automatically decide based on configured strings compared to ID response.
mail/locales/en-US/chrome/messenger/am-server-advanced.dtd
mailnews/base/prefs/content/am-server-advanced.xul
mailnews/base/prefs/content/am-server.js
mailnews/base/prefs/content/am-server.xul
mailnews/imap/public/nsIImapIncomingServer.idl
mailnews/imap/public/nsIImapServerSink.idl
mailnews/imap/src/nsImapIncomingServer.cpp
mailnews/imap/src/nsImapProtocol.cpp
mailnews/imap/src/nsImapProtocol.h
mailnews/imap/src/nsSyncRunnableHelpers.cpp
mailnews/mailnews.js
suite/locales/en-US/chrome/mailnews/pref/am-server-advanced.dtd
--- a/mail/locales/en-US/chrome/messenger/am-server-advanced.dtd
+++ b/mail/locales/en-US/chrome/messenger/am-server-advanced.dtd
@@ -7,19 +7,16 @@
 <!ENTITY serverDirectory.label "IMAP server directory:">
 <!ENTITY serverDirectory.accesskey "d">
 <!ENTITY usingSubscription.label "Show only subscribed folders">
 <!ENTITY usingSubscription.accesskey "w">
 <!ENTITY dualUseFolders.label "Server supports folders that contain sub-folders and messages">
 <!ENTITY dualUseFolders.accesskey "f">
 <!ENTITY maximumConnectionsNumber.label "Maximum number of server connections to cache">
 <!ENTITY maximumConnectionsNumber.accesskey "M">
-<!ENTITY forceSelect.label "Send IMAP select to server when checking for new mail">
-<!ENTITY forceSelect.tooltip "Some servers need an additional IMAP select so new email is reliably received, or is shown as read after it has been read on another device. Selecting this option will cause some increased network traffic.">
-<!ENTITY forceSelect.accesskey "S">
 <!-- LOCALIZATION NOTE (namespaceDesc.label): Do not translate "IMAP" -->
 <!ENTITY namespaceDesc.label "These preferences specify the namespaces on your IMAP server">
 <!ENTITY personalNamespace.label "Personal namespace:">
 <!ENTITY personalNamespace.accesskey "P">
 <!ENTITY publicNamespace.label "Public (shared):">
 <!ENTITY publicNamespace.accesskey "u">
 <!ENTITY otherUsersNamespace.label "Other Users:">
 <!ENTITY otherUsersNamespace.accesskey "O">
--- a/mailnews/base/prefs/content/am-server-advanced.xul
+++ b/mailnews/base/prefs/content/am-server-advanced.xul
@@ -92,22 +92,16 @@
           <row align="center">
             <separator class="indent"/>
             <checkbox amsa_persist="true" id="overrideNamespaces"
                       label="&overrideNamespaces.label;"
                       accesskey="&overrideNamespaces.accesskey;"/>
           </row>
         </rows>
       </grid>
-
-      <separator class="groove"/>
-      <checkbox amsa_persist="true" id="forceSelect"
-                label="&forceSelect.label;"
-                tooltiptext="&forceSelect.tooltip;"
-                accesskey="&forceSelect.accesskey;"/>
     </vbox>
 
 
     <!-- POP3 Panel -->
     <vbox id="pop3Panel">
       <label flex="1" control="folderStorage">&pop3DeferringDesc.label;</label>
       <hbox align="center">
         <radiogroup id="folderStorage"
--- a/mailnews/base/prefs/content/am-server.js
+++ b/mailnews/base/prefs/content/am-server.js
@@ -128,17 +128,16 @@ function onAdvanced()
   serverSettings.serverPrettyName = gServer.prettyName;
   serverSettings.account = top.getCurrentAccount();
 
   if (serverType == "imap")
   {
     serverSettings.dualUseFolders = document.getElementById("imap.dualUseFolders").checked;
     serverSettings.usingSubscription = document.getElementById("imap.usingSubscription").checked;
     serverSettings.maximumConnectionsNumber = document.getElementById("imap.maximumConnectionsNumber").getAttribute("value");
-    serverSettings.forceSelect = document.getElementById("imap.forceSelect").checked;
     // string prefs
     serverSettings.personalNamespace = document.getElementById("imap.personalNamespace").getAttribute("value");
     serverSettings.publicNamespace = document.getElementById("imap.publicNamespace").getAttribute("value");
     serverSettings.serverDirectory = document.getElementById("imap.serverDirectory").getAttribute("value");
     serverSettings.otherUsersNamespace = document.getElementById("imap.otherUsersNamespace").getAttribute("value");
     serverSettings.overrideNamespaces = document.getElementById("imap.overrideNamespaces").checked;
   }
   else if (serverType == "pop3")
@@ -150,17 +149,16 @@ function onAdvanced()
   window.openDialog("chrome://messenger/content/am-server-advanced.xul",
                     "_blank", "chrome,modal,titlebar", serverSettings);
 
   if (serverType == "imap")
   {
     document.getElementById("imap.dualUseFolders").checked = serverSettings.dualUseFolders;
     document.getElementById("imap.usingSubscription").checked = serverSettings.usingSubscription;
     document.getElementById("imap.maximumConnectionsNumber").setAttribute("value", serverSettings.maximumConnectionsNumber);
-    document.getElementById("imap.forceSelect").checked = serverSettings.forceSelect;
     // string prefs
     document.getElementById("imap.personalNamespace").setAttribute("value", serverSettings.personalNamespace);
     document.getElementById("imap.publicNamespace").setAttribute("value", serverSettings.publicNamespace);
     document.getElementById("imap.serverDirectory").setAttribute("value", serverSettings.serverDirectory);
     document.getElementById("imap.otherUsersNamespace").setAttribute("value", serverSettings.otherUsersNamespace);
     document.getElementById("imap.overrideNamespaces").checked = serverSettings.overrideNamespaces;
   }
   else if (serverType == "pop3")
--- a/mailnews/base/prefs/content/am-server.xul
+++ b/mailnews/base/prefs/content/am-server.xul
@@ -323,19 +323,16 @@
       <label hidden="true" wsm_persist="true" id="imap.maximumConnectionsNumber"/>
       <label hidden="true" wsm_persist="true" id="imap.personalNamespace"/>
       <label hidden="true" wsm_persist="true" id="imap.publicNamespace"/>
       <label hidden="true" wsm_persist="true" id="imap.otherUsersNamespace"/>
       <label hidden="true" wsm_persist="true" id="imap.serverDirectory"/>
       <checkbox hidden="true" wsm_persist="true" id="imap.overrideNamespaces"
                 prefattribute="value"
                 prefstring="mail.server.%serverkey%.override_namespaces"/>
-      <checkbox hidden="true" wsm_persist="true" id="imap.forceSelect"
-                prefattribute="value"
-                prefstring="mail.server.%serverkey%.forceSelect"/>
     </hbox>
 
     <!-- NNTP -->
     <hbox hidefor="pop3,imap,movemail" align="center">
       <checkbox wsm_persist="true" id="nntp.notifyOn"
                 label="&maxMessagesStart.label;"
                 accesskey="&maxMessagesStart.accesskey;"
                 oncommand="onCheckItem('nntp.maxArticles', [this.id]);"
--- a/mailnews/imap/public/nsIImapIncomingServer.idl
+++ b/mailnews/imap/public/nsIImapIncomingServer.idl
@@ -20,17 +20,17 @@ interface nsMsgImapDeleteModels
   const long MoveToTrash = 1;   /* delete moves message to the trash */
   const long DeleteNoTrash = 2; /* delete is shift delete - don't create or use trash */
 };
 
 [scriptable, uuid(ea6a0765-07b8-40df-924c-9004ed707251)]
 interface nsIImapIncomingServer : nsISupports {
 
   attribute long maximumConnectionsNumber;
-  attribute boolean forceSelect;
+  attribute ACString forceSelect;
   attribute long timeOutLimits;
   attribute ACString adminUrl;
   attribute ACString serverDirectory;
   /// RFC 2971 ID response stored as a pref
   attribute ACString serverIDPref;
   attribute boolean cleanupInboxOnExit;
   attribute nsMsgImapDeleteModel deleteModel;
   attribute boolean dualUseFolders;
--- a/mailnews/imap/public/nsIImapServerSink.idl
+++ b/mailnews/imap/public/nsIImapServerSink.idl
@@ -159,9 +159,11 @@ interface nsIImapServerSink : nsISupport
   /// remove a connection to the server
   void removeServerConnection(in nsIImapProtocol aProtocol);
   /// is the imap server shutting down?
   readonly attribute boolean serverShuttingDown;
   /// reset the connection for a particular folder
   void resetServerConnection(in ACString aFolderName);
   /// tell the server if listing using lsub command
   void setServerDoingLsub(in boolean aDoingLsub);
+  /// set force select string
+  void SetServerForceSelect(in ACString forceSelect);
 };
--- a/mailnews/imap/src/nsImapIncomingServer.cpp
+++ b/mailnews/imap/src/nsImapIncomingServer.cpp
@@ -271,18 +271,18 @@ nsImapIncomingServer::GetMaximumConnecti
 }
 
 NS_IMETHODIMP
 nsImapIncomingServer::SetMaximumConnectionsNumber(int32_t aMaxConnections)
 {
   return SetIntValue("max_cached_connections", aMaxConnections);
 }
 
-NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, ForceSelect,
-                        "forceSelect")
+NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, ForceSelect,
+                       "force_select")
 
 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, DualUseFolders,
                         "dual_use_folders")
 
 NS_IMPL_SERVERPREF_STR(nsImapIncomingServer, AdminUrl,
                        "admin_url")
 
 NS_IMPL_SERVERPREF_BOOL(nsImapIncomingServer, CleanupInboxOnExit,
@@ -3374,8 +3374,14 @@ nsImapIncomingServer::ResetServerConnect
   return ResetConnection(aFolderName);
 }
 
 NS_IMETHODIMP
 nsImapIncomingServer::SetServerDoingLsub(bool aDoingLsub)
 {
   return SetDoingLsub(aDoingLsub);
 }
+
+NS_IMETHODIMP
+nsImapIncomingServer::SetServerForceSelect(const nsACString &aForceSelect)
+{
+  return SetForceSelect(aForceSelect);
+}
--- a/mailnews/imap/src/nsImapProtocol.cpp
+++ b/mailnews/imap/src/nsImapProtocol.cpp
@@ -316,16 +316,18 @@ static bool gFetchByChunks = true;
 static bool gInitialized = false;
 static bool gHideUnusedNamespaces = true;
 static bool gHideOtherUsersFromList = false;
 static bool gUseEnvelopeCmd = false;
 static bool gUseLiteralPlus = true;
 static bool gExpungeAfterDelete = false;
 static bool gCheckDeletedBeforeExpunge = false; //bug 235004
 static int32_t gResponseTimeout = 60;
+static nsCString gForceSelectDetect;
+static nsTArray<nsCString> gForceSelectServersArray;
 
 // let delete model control expunging, i.e., don't ever expunge when the
 // user chooses the imap delete model, otherwise, expunge when over the
 // threshhold. This is the normal TB behavior.
 static const int32_t kAutoExpungeDeleteModel = 0;
 // Expunge whenever the folder is opened
 static const int32_t kAutoExpungeAlways = 1;
 // Expunge when over the threshhold, independent of the delete model.
@@ -360,16 +362,20 @@ nsresult nsImapProtocol::GlobalInitializ
     aPrefBranch->GetBoolPref("mail.imap.expunge_after_delete",
                              &gExpungeAfterDelete);
     aPrefBranch->GetBoolPref("mail.imap.check_deleted_before_expunge",
                              &gCheckDeletedBeforeExpunge);
     aPrefBranch->GetIntPref("mail.imap.expunge_option", &gExpungeOption);
     aPrefBranch->GetIntPref("mail.imap.expunge_threshold_number",
                             &gExpungeThreshold);
     aPrefBranch->GetIntPref("mailnews.tcptimeout", &gResponseTimeout);
+    aPrefBranch->GetCharPref("mail.imap.force_select_detect",
+                             getter_Copies(gForceSelectDetect));
+    ParseString(gForceSelectDetect, ';', gForceSelectServersArray);
+
     nsCOMPtr<nsIXULAppInfo> appInfo(do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
 
     if (appInfo)
     {
       nsCString appName, appVersion;
       appInfo->GetName(appName);
       appInfo->GetVersion(appVersion);
       PL_strncpyz(gAppName, appName.get(), kAppBufSize);
@@ -501,16 +507,17 @@ nsImapProtocol::nsImapProtocol() : nsMsg
   m_autoUnsubscribe = true;
   m_autoSubscribeOnOpen = true;
   m_deletableChildren = nullptr;
 
   mFolderLastModSeq = 0;
 
   Configure(gTooFastTime, gIdealTime, gChunkAddSize, gChunkSize,
                     gChunkThreshold, gFetchByChunks);
+  m_forceSelect = false;
 }
 
 nsresult nsImapProtocol::Configure(int32_t TooFastTime, int32_t IdealTime,
                   int32_t ChunkAddSize, int32_t ChunkSize, int32_t ChunkThreshold,
                   bool FetchByChunks)
 {
   m_tooFastTime = TooFastTime;    // secs we read too little too fast
   m_idealTime = IdealTime;    // secs we read enough in good time
@@ -535,17 +542,17 @@ nsImapProtocol::Initialize(nsIImapHostSe
   nsresult rv = m_downloadLineCache->GrowBuffer(kDownLoadCacheSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   m_flagState = new nsImapFlagAndUidState(kImapFlagAndUidStateSize);
   if (!m_flagState)
     return NS_ERROR_OUT_OF_MEMORY;
 
   aServer->GetUseIdle(&m_useIdle);
-  aServer->GetForceSelect(&m_forceSelect);
+  aServer->GetForceSelect(m_forceSelectValue);
   aServer->GetUseCondStore(&m_useCondStore);
   aServer->GetUseCompressDeflate(&m_useCompressDeflate);
   NS_ADDREF(m_flagState);
 
   m_hostSessionList = aHostSessionList; // no ref count...host session list has life time > connection
   m_parser.SetHostSessionList(aHostSessionList);
   m_parser.SetFlagState(m_flagState);
 
@@ -7767,16 +7774,60 @@ bool nsImapProtocol::GetListSubscribedIs
     Version eightZeroThree("8.0.3_");
     if ((serverVersion < sevenTwoThree) ||
         ((serverVersion >= eightZeroZero) && (serverVersion < eightZeroThree)))
       return true;
   }
   return false;
 }
 
+// This identifies servers that require an extra imap SELECT to detect new
+// email in a mailbox. Servers requiring this are found by comparing their
+// ID string, returned with imap ID command, to strings entered in
+// mail.imap.force_select_detect. Only openwave servers used by
+// Charter/Spectrum ISP returning an ID containing the strings ""name" "Email Mx""
+// and ""vendor" "Openwave Messaging"" are now known to have this issue. The
+// compared strings can be modified with the config editor if necessary
+// (e.g., a "version" substring could be added). Also, additional servers
+// having a different set of strings can be added if ever needed.
+// The mail.imap.force_select_detect uses semicolon delimiter between
+// servers and within a server substrings to compare are comma delimited.
+// This example force_select_detect value shows how two servers types
+// could be detected:
+// "name" "Email Mx","vendor" "Openwave Messaging";"vendor" "Yahoo! Inc.","name" "Y!IMAP";
+bool nsImapProtocol::IsExtraSelectNeeded()
+{
+  bool retVal;
+  for (uint32_t i = 0; i < gForceSelectServersArray.Length(); i++)
+  {
+    retVal = true;
+    nsTArray<nsCString> forceSelectStringsArray;
+    ParseString(gForceSelectServersArray[i], ',', forceSelectStringsArray);
+    for (uint32_t j = 0; j < forceSelectStringsArray.Length(); j++)
+    {
+      // Each substring within the server string must be contained in ID string.
+      // First un-escape any comma (%2c) or semicolon (%3b) within the substring.
+      nsAutoCString unescapedString;
+      MsgUnescapeString(forceSelectStringsArray[j], 0, unescapedString);
+      if (GetServerStateParser().GetServerID()
+          .Find(unescapedString, CaseInsensitiveCompare) == kNotFound)
+      {
+        retVal = false;
+        break;
+      }
+    }
+    // Matches found for all substrings for the server.
+    if (retVal)
+      return true;
+  }
+
+  // If reached, no substrings match for any server.
+  return false;
+}
+
 void nsImapProtocol::Lsub(const char *mailboxPattern, bool addDirectoryIfNecessary)
 {
   ProgressEventFunctionUsingName("imapStatusLookingForMailbox");
 
   IncrementCommandTagNumber();
 
   char *boxnameWithOnlineDirectory = nullptr;
   if (addDirectoryIfNecessary)
@@ -8194,22 +8245,88 @@ void nsImapProtocol::ProcessAfterAuthent
   // backend.  If we enable compression early the proxy
   // will be confused.
   if (UseCompressDeflate())
     StartCompressDeflate();
 
   if ((GetServerStateParser().GetCapabilityFlag() & kHasEnableCapability) &&
        UseCondStore())
     EnableCondStore();
+
+  bool haveIdResponse = false;
   if ((GetServerStateParser().GetCapabilityFlag() & kHasIDCapability) &&
        m_sendID)
   {
     ID();
     if (m_imapServerSink && !GetServerStateParser().GetServerID().IsEmpty())
+    {
+      haveIdResponse = true;
+      // Determine value for m_forceSelect based on config editor
+      // entries and comparison to imap ID string returned by the server.
       m_imapServerSink->SetServerID(GetServerStateParser().GetServerID());
+      switch (m_forceSelectValue.get()[0])
+      {
+      // Yes: Set to always force even if imap server doesn't need it.
+      case 'y':
+      case 'Y':
+        m_forceSelect = true;
+        break;
+
+      // No: Set to never force a select for this imap server.
+      case 'n':
+      case 'N':
+        m_forceSelect = false;
+        break;
+
+      // Auto: Set to force only if imap server requires it.
+      default:
+        nsAutoCString statusString;
+        m_forceSelect = IsExtraSelectNeeded();
+        // Setting to "yes-auto" or "no-auto" avoids doing redundant calls to
+        // IsExtraSelectNeeded() on subsequent ID() occurrences. It also
+        // provides feedback to the user regarding the detection status.
+        if (m_forceSelect)
+        {
+          // Set preference value to "yes-auto".
+          statusString.Assign("yes-auto");
+        }
+        else
+        {
+          // Set preference value to "no-auto".
+          statusString.Assign("no-auto");
+        }
+        m_imapServerSink->SetServerForceSelect(statusString);
+        break;
+      }
+    }
+  }
+
+  // If no ID capability or empty ID response, user may still want to
+  // change "force select".
+  if (!haveIdResponse)
+  {
+    switch (m_forceSelectValue.get()[0])
+    {
+    case 'a':
+      {
+        // If default "auto", set to "no-auto" so visible in config editor
+        // and set/keep m_forceSelect false.
+        nsAutoCString statusString;
+        statusString.Assign("no-auto");
+        m_imapServerSink->SetServerForceSelect(statusString);
+        m_forceSelect = false;
+      }
+      break;
+    case 'y':
+    case 'Y':
+      m_forceSelect = true;
+      break;
+    default:
+      m_forceSelect = false;
+    }
   }
 }
 
 void nsImapProtocol::SetupMessageFlagsString(nsCString& flagString,
                                              imapMessageFlagsType flags,
                                              uint16_t userFlags)
 {
     if (flags & kImapMsgSeenFlag)
--- a/mailnews/imap/src/nsImapProtocol.h
+++ b/mailnews/imap/src/nsImapProtocol.h
@@ -551,16 +551,17 @@ private:
   bool FolderNeedsACLInitialized(const char *folderName);
   void DiscoverMailboxList();
   void DiscoverAllAndSubscribedBoxes();
   void MailboxDiscoveryFinished();
   void NthLevelChildList(const char *onlineMailboxPrefix, int32_t depth);
   // LIST SUBSCRIBED command (from RFC 5258) crashes some servers. so we need to
   // identify those servers
   bool GetListSubscribedIsBrokenOnServer();
+  bool IsExtraSelectNeeded();
   void Lsub(const char *mailboxPattern, bool addDirectoryIfNecessary);
   void List(const char *mailboxPattern, bool addDirectoryIfNecessary,
             bool useXLIST = false);
   void Subscribe(const char *mailboxName);
   void Unsubscribe(const char *mailboxName);
   void Idle();
   void EndIdle(bool waitForResponse = true);
   // Some imap servers include the mailboxName following the dir-separator in the list of
@@ -658,16 +659,17 @@ private:
   bool m_needNoop;
   bool m_idle;
   bool m_useIdle;
   int32_t m_noopCount;
   bool    m_autoSubscribe, m_autoUnsubscribe, m_autoSubscribeOnOpen;
   bool m_closeNeededBeforeSelect;
   bool m_retryUrlOnError;
   bool m_preferPlainText;
+  nsCString m_forceSelectValue;
   bool m_forceSelect;
 
   int32_t m_uidValidity; // stored uid validity for the selected folder.
 
   enum EMailboxHierarchyNameState {
     kNoOperationInProgress,
       kDiscoverBaseFolderInProgress,
       kDiscoverTrashFolderInProgress,
--- a/mailnews/imap/src/nsSyncRunnableHelpers.cpp
+++ b/mailnews/imap/src/nsSyncRunnableHelpers.cpp
@@ -450,16 +450,17 @@ NS_SYNCRUNNABLEMETHOD1(ImapServerSink, G
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, UpdateTrySTARTTLSPref, bool)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetOriginalUsername, nsACString &)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerKey, nsACString &)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerPassword, nsACString &)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, RemoveServerConnection, nsIImapProtocol *)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, GetServerShuttingDown, bool *)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, ResetServerConnection, const nsACString &)
 NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerDoingLsub, bool)
+NS_SYNCRUNNABLEMETHOD1(ImapServerSink, SetServerForceSelect, const nsACString &)
 
 
 namespace mozilla {
 namespace mailnews {
 
 NS_IMPL_ISUPPORTS(OAuth2ThreadHelper, msgIOAuth2ModuleListener)
 
 OAuth2ThreadHelper::OAuth2ThreadHelper(nsIMsgIncomingServer *aServer)
--- a/mailnews/mailnews.js
+++ b/mailnews/mailnews.js
@@ -495,21 +495,35 @@ pref("mail.server.default.serverFilterNa
 pref("mail.server.default.serverFilterTrustFlags", 1); // 1 == trust positives, 2 == trust negatives, 3 == trust both
 pref("mail.server.default.purgeSpam", false);
 pref("mail.server.default.purgeSpamInterval", 14); // 14 days
 pref("mail.server.default.check_all_folders_for_new", false);
 // should we inhibit whitelisting of the email addresses for a server's identities?
 pref("mail.server.default.inhibitWhiteListingIdentityUser", true);
 // should we inhibit whitelisting of the domain for a server's identities?
 pref("mail.server.default.inhibitWhiteListingIdentityDomain", false);
-// When forceSelect is true, sends extra/redundant imap SELECT when checking for
-// new mail. Needed by some imap servers. Also, if server does not support IDLE,
-// this can help insure messages are marked as "read" after being read in other
-// email clients.
-pref("mail.server.default.forceSelect", false);
+
+// When force_select is "auto" the ID response for the server will be compared to
+// force_select_detect below and, if they compare, an extra imap select will
+// be sent when checking for new mail. If force_select is "no", the extra
+// select will never occur, and, if "yes" it will always occur when checking for
+// new email (both regardless of the ID response string).
+// The extra select insures that new emails are automatically detected by servers
+// requiring it. Also, if a server does not support IDLE, setting this to "yes"
+// can insure messages are marked as "read" after being read in other email clients.
+pref("mail.server.default.force_select", "auto");
+
+// Specify imap ID response substrings that must occur to cause the extra/forced
+// imap select for server(s).  Substrings are comma separated within a given server
+// (all substrings within a server must be found in the ID response string) and
+// servers are semicolon separated. Currently only 1 server type is known
+// to require the extra select -- Openwave server used by Charter-Spectrum ISP.
+pref("mail.imap.force_select_detect", "\"name\" \"Email Mx\",\"vendor\" \"Openwave Messaging\"");
+// Example if ever another server requires the extra select (ID substrings from Yahoo! added):
+//pref("mail.imap.force_select_detect", "\"name\" \"Email Mx\",\"vendor\" \"Openwave Messaging\";\"vendor\" \"Yahoo! Inc.\",\"name\" \"Y!IMAP\";");
 
 // to activate auto-sync feature (preemptive message download for imap) by default
 pref("mail.server.default.autosync_offline_stores",true);
 pref("mail.server.default.offline_download",true);
 
 // -1 means no limit, no purging of offline stores.
 pref("mail.server.default.autosync_max_age_days", -1);
 
--- a/suite/locales/en-US/chrome/mailnews/pref/am-server-advanced.dtd
+++ b/suite/locales/en-US/chrome/mailnews/pref/am-server-advanced.dtd
@@ -7,19 +7,16 @@
 <!ENTITY serverDirectory.label "IMAP server directory:">
 <!ENTITY serverDirectory.accesskey "d">
 <!ENTITY usingSubscription.label "Show only subscribed folders">
 <!ENTITY usingSubscription.accesskey "w">
 <!ENTITY dualUseFolders.label "Server supports folders that contain sub-folders and messages">
 <!ENTITY dualUseFolders.accesskey "f">
 <!ENTITY maximumConnectionsNumber.label "Maximum number of server connections to cache">
 <!ENTITY maximumConnectionsNumber.accesskey "M">
-<!ENTITY forceSelect.label "Send IMAP select to server when checking for new mail">
-<!ENTITY forceSelect.tooltip "Some servers need an additional IMAP select so new email is reliably received, or is shown as read after it has been read on another device. Selecting this option will cause some increased network traffic.">
-<!ENTITY forceSelect.accesskey "S">
 <!-- LOCALIZATION NOTE (namespaceDesc.label): DONT_TRANSLATE "IMAP" -->
 <!ENTITY namespaceDesc.label "These preferences specify the namespaces on your IMAP server">
 <!ENTITY personalNamespace.label "Personal namespace:">
 <!ENTITY personalNamespace.accesskey "P">
 <!ENTITY publicNamespace.label "Public (shared):">
 <!ENTITY publicNamespace.accesskey "u">
 <!ENTITY otherUsersNamespace.label "Other Users:">
 <!ENTITY otherUsersNamespace.accesskey "O">