Bug 540449 - Search term for junk status doesn't detect unprocessed emails, r=bienvenu
authorKent James <kent@caspia.com>
Tue, 03 May 2011 10:38:42 -0700
changeset 7679 09e5bddbead81806e1b9a96d1f014b088cec458d
parent 7678 34703bb121c7c035c2f2c61c042947402ada210a
child 7680 7e6e9dc6e84dde99642070b3b87f0f3ef0177919
push idunknown
push userunknown
push dateunknown
reviewersbienvenu
bugs540449
Bug 540449 - Search term for junk status doesn't detect unprocessed emails, r=bienvenu
mail/base/content/mailWidgets.xml
mailnews/base/search/src/nsMsgImapSearch.cpp
mailnews/base/search/src/nsMsgLocalSearch.cpp
mailnews/base/search/src/nsMsgSearchTerm.cpp
mailnews/base/test/unit/test_searchJunk.js
suite/mailnews/mailWidgets.xml
--- a/mail/base/content/mailWidgets.xml
+++ b/mail/base/content/mailWidgets.xml
@@ -1450,16 +1450,25 @@
             if (this.searchAttribute == Components.interfaces.nsMsgSearchAttrib.Keywords) {
               if (val == Components.interfaces.nsMsgSearchOp.IsEmpty ||
                   val == Components.interfaces.nsMsgSearchOp.IsntEmpty)
                 this.setAttribute("selectedIndex", "-1");
               else
                 this.setAttribute("selectedIndex", "5");
             }
 
+            // JunkStatus has the null field IsEmpty
+            if (this.searchAttribute == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
+              if (val == Components.interfaces.nsMsgSearchOp.IsEmpty ||
+                  val == Components.interfaces.nsMsgSearchOp.IsntEmpty)
+                this.setAttribute("selectedIndex", "-1");
+              else
+                this.setAttribute("selectedIndex", "6");
+            }
+
               // if it's not sender, to, cc, alladdresses, or toorcc, we don't care
               if (this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.Sender && 
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.To && 
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.ToOrCC && 
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.AllAddresses &&
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.CC ) {
               this.internalOperator = val;
               return val;
--- a/mailnews/base/search/src/nsMsgImapSearch.cpp
+++ b/mailnews/base/search/src/nsMsgImapSearch.cpp
@@ -308,16 +308,20 @@ nsMsgSearchValidityManager::InitOfflineM
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1);
   m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is,  1);
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1);
   
   m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
   m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
+  m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
+  m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
+  m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
+  m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
   
   m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
   m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
   m_offlineMailTable->SetAvailable (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
   m_offlineMailTable->SetEnabled   (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
 
@@ -916,16 +920,20 @@ nsMsgSearchValidityManager::InitOnlineMa
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1);
   m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is,  1);
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1);
 
   m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
   m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
+  m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
+  m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
+  m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
+  m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
 
   m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
   m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
   m_onlineManualFilterTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
   m_onlineManualFilterTable->SetEnabled(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
 
--- a/mailnews/base/search/src/nsMsgLocalSearch.cpp
+++ b/mailnews/base/search/src/nsMsgLocalSearch.cpp
@@ -880,16 +880,20 @@ nsresult nsMsgSearchOfflineNews::Validat
 nsresult SetJunk(nsIMsgSearchValidityTable* aTable)
 {
   NS_ENSURE_ARG_POINTER(aTable);
 
   aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
   aTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
   aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
   aTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
+  aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
+  aTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
+  aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
+  aTable->SetEnabled(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
 
   aTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
   aTable->SetEnabled(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
   aTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
   aTable->SetEnabled(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
   aTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
   aTable->SetEnabled(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
 
--- a/mailnews/base/search/src/nsMsgSearchTerm.cpp
+++ b/mailnews/base/search/src/nsMsgSearchTerm.cpp
@@ -1394,16 +1394,27 @@ nsresult nsMsgSearchTerm::MatchSize (PRU
   *pResult = result;
   return NS_OK;
 }
 
 nsresult nsMsgSearchTerm::MatchJunkStatus(const char *aJunkScore, PRBool *pResult)
 {
   NS_ENSURE_ARG_POINTER(pResult);
 
+  if (m_operator == nsMsgSearchOp::IsEmpty)
+  {
+    *pResult = !(aJunkScore && *aJunkScore);
+    return NS_OK;
+  }
+  else if (m_operator == nsMsgSearchOp::IsntEmpty)
+  {
+    *pResult = (aJunkScore && *aJunkScore);
+    return NS_OK;
+  }
+
   nsMsgJunkStatus junkStatus;
   if (aJunkScore && *aJunkScore) {
       junkStatus = (atoi(aJunkScore) == nsIJunkMailPlugin::IS_SPAM_SCORE) ?
           nsIJunkMailPlugin::JUNK :
           nsIJunkMailPlugin::GOOD;
 
   }
   else {
--- a/mailnews/base/test/unit/test_searchJunk.js
+++ b/mailnews/base/test/unit/test_searchJunk.js
@@ -44,21 +44,24 @@ const copyService = Cc["@mozilla.org/mes
 const nsMsgSearchScope = Ci.nsMsgSearchScope;
 const nsMsgSearchAttrib = Ci.nsMsgSearchAttrib;
 const nsMsgSearchOp = Ci.nsMsgSearchOp;
 
 const IsGreaterThan = nsMsgSearchOp.IsGreaterThan;
 const IsLessThan = nsMsgSearchOp.IsLessThan;
 const Is = nsMsgSearchOp.Is;
 const Isnt = nsMsgSearchOp.Isnt;
+const IsEmpty = nsMsgSearchOp.IsEmpty;
+const IsntEmpty = nsMsgSearchOp.IsntEmpty;
 
 const offlineMail = nsMsgSearchScope.offlineMail;
 
 const JunkScoreOrigin = nsMsgSearchAttrib.JunkScoreOrigin;
 const JunkPercent = nsMsgSearchAttrib.JunkPercent;
+const JunkStatus = nsMsgSearchAttrib.JunkStatus;
 
 const fileName = "../../../data/bugmail1";
 
 /*
  * The search for junkpercent is defined as the effective value,
  * while the "junkpercent" database term is always the result
  * from the bayes filter. This is optimized to make views that
  * rely on junk percent search work with the best value for junk
@@ -68,16 +71,55 @@ const fileName = "../../../data/bugmail1
  * This means that the search for "junk percent" only uses the 
  * database junkpercent value if junkscoreorigin is "plugin".
  * Otherwise, it uses junkstatus (if set) or defaults to 0
  * (not junk) if the message is unclassified.
  */
 
 var Tests = 
 [
+  // test empty junk status
+  { junkScore: false,
+    testValue: 90,
+    attrib: JunkStatus,
+    op: IsEmpty,
+    count: 1},
+  { junkScore: false,
+    testValue: 90,
+    attrib: JunkStatus,
+    op: IsntEmpty,
+    count: 0},
+  { junkScore: "0",
+    junkScoreOrigin: "plugin",
+    junkPercent: "10",
+    testValue: 90,
+    attrib: JunkStatus,
+    op: IsntEmpty,
+    count: 1},
+  { junkScore: "0",
+    junkScoreOrigin: "plugin",
+    junkPercent: "10",
+    testValue: 90,
+    attrib: JunkStatus,
+    op: IsEmpty,
+    count: 0},
+  { junkScore: "100",
+    junkScoreOrigin: "plugin",
+    junkPercent: "10",
+    testValue: 90,
+    attrib: JunkStatus,
+    op: IsntEmpty,
+    count: 1},
+  { junkScore: "100",
+    junkScoreOrigin: "plugin",
+    junkPercent: "10",
+    testValue: 90,
+    attrib: JunkStatus,
+    op: IsEmpty,
+    count: 0},
   // Use junkpercent from database
   { junkScore: "0",
     junkScoreOrigin: "plugin",
     junkPercent: "10",
     testValue: 90,
     attrib: JunkPercent,
     op: IsGreaterThan,
     count: 0},
@@ -238,19 +280,22 @@ var copyListener =
 // Runs at completion of each copy
 // process each test from queue, calls itself upon completion of each search
 var testObject;
 function testJunkSearch()
 {
   var test = Tests.shift();
   if (test)
   {
-    hdr.setStringProperty("junkpercent", test.junkPercent);
-    hdr.setStringProperty("junkscoreorigin", test.junkScoreOrigin);
-    hdr.setStringProperty("junkscore", test.junkScore);
+    if (test.junkScore)
+    {
+      hdr.setStringProperty("junkpercent", test.junkPercent);
+      hdr.setStringProperty("junkscoreorigin", test.junkScoreOrigin);
+      hdr.setStringProperty("junkscore", test.junkScore);
+    }
 
     testObject = new TestSearch(gLocalInboxFolder,
                          test.testValue,
                          test.attrib,
                          test.op,
                          test.count,
                          testJunkSearch);
   }
--- a/suite/mailnews/mailWidgets.xml
+++ b/suite/mailnews/mailWidgets.xml
@@ -1229,16 +1229,25 @@
             if (this.searchAttribute == Components.interfaces.nsMsgSearchAttrib.Keywords) {
               if (val == Components.interfaces.nsMsgSearchOp.IsEmpty ||
                   val == Components.interfaces.nsMsgSearchOp.IsntEmpty)
                 this.setAttribute("selectedIndex", "-1");
               else
                 this.setAttribute("selectedIndex", "5");
             }
 
+            // JunkStatus has the null field IsEmpty
+            if (this.searchAttribute == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
+              if (val == Components.interfaces.nsMsgSearchOp.IsEmpty ||
+                  val == Components.interfaces.nsMsgSearchOp.IsntEmpty)
+                this.setAttribute("selectedIndex", "-1");
+              else
+                this.setAttribute("selectedIndex", "6");
+            }
+
               // if it's not sender, to, cc, alladdresses, or toorcc, we don't care
               if (this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.Sender && 
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.To && 
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.ToOrCC && 
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.AllAddresses &&
                 this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.CC ) {
               this.internalOperator = val;
               return val;