author | Kent James <kent@caspia.com> |
Fri, 04 Sep 2009 17:30:07 -0700 | |
changeset 3542 | f83b9d5dddd1333a7ec6b62ff8cd168bcb0b6f25 |
parent 3541 | dde243bf059e4198a7799cf1717af76de3da007c |
child 3543 | b4c1ff77f3b2c5633d88dae46bb13da336fb321a |
push id | unknown |
push user | unknown |
push date | unknown |
reviewers | Standard8, bienvenu |
bugs | 511131 |
--- a/mail/base/content/SearchDialog.js +++ b/mail/base/content/SearchDialog.js @@ -55,16 +55,19 @@ var gSearchBundle; // Datasource search listener -- made global as it has to be registered // and unregistered in different functions. var gDataSourceSearchListener; var gViewSearchListener; var gSearchStopButton; +// Should we try to search online? +var gSearchOnline = false; + // Controller object for search results thread pane var nsSearchResultsController = { supportsCommand: function(command) { switch(command) { case "cmd_delete": case "cmd_shiftDelete": @@ -343,19 +346,36 @@ function selectFolder(folder) function updateSearchFolderPicker(folderURI) { SetFolderPicker(folderURI, gFolderPicker.id); // use the URI to get the real folder gCurrentFolder = GetMsgFolderFromUri(folderURI); - var searchLocalSystem = document.getElementById("checkSearchLocalSystem"); - if (searchLocalSystem) - searchLocalSystem.disabled = gCurrentFolder.server.searchScope == nsMsgSearchScope.offlineMail; + var searchOnline = document.getElementById("checkSearchOnline"); + if (searchOnline) + { + // We will clear and disable the search online checkbox if we are offline, or + // if the folder does not support online search. + + // Anything greater than 0 is an online server like IMAP or news. + if (gCurrentFolder.server.offlineSupportLevel && + !Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService) + .offline) + { + searchOnline.disabled = false; + } + else + { + searchOnline.checked = false; + searchOnline.disabled = true; + } + } setSearchScope(GetScopeForFolder(gCurrentFolder)); } function updateSearchLocalSystem() { setSearchScope(GetScopeForFolder(gCurrentFolder)); } @@ -387,16 +407,17 @@ function onEnterInSearchTerm() function onSearch() { let viewWrapper = gFolderDisplay.view; let searchTerms = getSearchTerms(); viewWrapper.beginViewUpdate(); viewWrapper.search.userTerms = searchTerms.length ? searchTerms : null; + viewWrapper.search.onlineSearch = gSearchOnline; viewWrapper.searchFolders = getSearchFolders(); viewWrapper.endViewUpdate(); } /** * Get the current set of search terms, returning them as a list. We filter out * dangerous and insane predicates. */ @@ -481,21 +502,79 @@ function AddSubFoldersToURI(folder) returnString += '|'; returnString += subFoldersString; } } } return returnString; } - +/** + * Determine the proper search scope to use for a folder, so that the user is + * presented with a correct list of search capabilities. The user may manually + * request on online search for certain server types. To determine if the + * folder body may be searched, we ignore whether autosync is enabled, + * figuring that after the user manually syncs, they would still expect that + * body searches would work. + * + * The available search capabilities also depend on whether the user is + * currently online or offline. Although that is also checked by the server, + * we do it ourselves because we have a more complex response to offline + * than the server's searchScope attribute provides. + * + * This method only works for real folders. + */ function GetScopeForFolder(folder) { - var searchLocalSystem = document.getElementById("checkSearchLocalSystem"); - return searchLocalSystem && searchLocalSystem.checked ? nsMsgSearchScope.offlineMail : folder.server.searchScope; + let searchOnline = document.getElementById("checkSearchOnline"); + if (searchOnline && searchOnline.checked) + { + gSearchOnline = true; + return folder.server.searchScope; + } + gSearchOnline = false; + + // We are going to search offline. The proper search scope may depend on + // whether we have the body and/or junk available or not. + let localType; + try + { + localType = folder.server.localStoreType; + } + catch (e) {} // On error, we'll just assume the default mailbox type + + let hasBody = folder.getFlag(Components.interfaces.nsMsgFolderFlags.Offline); + let nsMsgSearchScope = Components.interfaces.nsMsgSearchScope; + switch (localType) + { + case "news": + // News has four offline scopes, depending on whether junk and body + // are available. + let hasJunk = + folder.getInheritedStringProperty("dobayes.mailnews@mozilla.org#junk") + == "true"; + if (hasJunk && hasBody) + return nsMsgSearchScope.localNewsJunkBody; + if (hasJunk) // and no body + return nsMsgSearchScope.localNewsJunk; + if (hasBody) // and no junk + return nsMsgSearchScope.localNewsBody; + // We don't have offline message bodies or junk processing. + return nsMsgSearchScope.localNews; + + case "imap": + // Junk is always enabled for imap, so the offline scope only depends on + // whether the body is available. + if (!hasBody) + return nsMsgSearchScope.onlineManual; + // fall through to default + default: + return nsMsgSearchScope.offlineMail; + } + } var nsMsgViewSortType = Components.interfaces.nsMsgViewSortType; var nsMsgViewSortOrder = Components.interfaces.nsMsgViewSortOrder; var nsMsgViewFlagsType = Components.interfaces.nsMsgViewFlagsType; var nsMsgViewCommandType = Components.interfaces.nsMsgViewCommandType; function goUpdateSearchItems(commandset) @@ -583,11 +662,12 @@ function saveAsVirtualFolder() searchFolderURIs += '|' + subFolderURIs; } var dialog = window.openDialog("chrome://messenger/content/virtualFolderProperties.xul", "", "chrome,titlebar,modal,centerscreen", {folder: window.arguments[0].folder, searchTerms: toXPCOMArray(getSearchTerms(), Components.interfaces.nsISupportsArray), - searchFolderURIs: searchFolderURIs}); + searchFolderURIs: searchFolderURIs, + searchOnline: document.getElementById("checkSearchOnline").checked}); }
--- a/mail/base/content/SearchDialog.xul +++ b/mail/base/content/SearchDialog.xul @@ -118,16 +118,22 @@ <button id="search-button" oncommand="onSearchButton(event);" default="true"/> </hbox> <hbox align="center"> <checkbox id="checkSearchSubFolders" label="&searchSubfolders.label;" checked="true" accesskey="&searchSubfolders.accesskey;"/> <spacer flex="10"/> <button label="&resetButton.label;" oncommand="onResetSearch(event);" accesskey="&resetButton.accesskey;"/> </hbox> + <hbox align="center"> + <checkbox id="checkSearchOnline" + label="&searchOnline.label;" + accesskey="&searchOnline.accesskey;" + oncommand="updateSearchLocalSystem();"/> + </hbox> </vbox> <hbox flex="1"> <vbox id="searchTermListBox" flex="1"/> </hbox> </vbox> <splitter id="gray_horizontal_splitter" collapse="after" persist="state"/>
--- a/mail/locales/en-US/chrome/messenger/SearchDialog.dtd +++ b/mail/locales/en-US/chrome/messenger/SearchDialog.dtd @@ -1,13 +1,15 @@ <!-- for SearchDialog.xul --> <!ENTITY searchHeading.label "Search for messages in:"> <!ENTITY searchHeading.accesskey "h"> <!ENTITY searchSubfolders.label "Search subfolders"> <!ENTITY searchSubfolders.accesskey "e"> +<!ENTITY searchOnline.label "Search online"> +<!ENTITY searchOnline.accesskey "l"> <!ENTITY resetButton.label "Clear"> <!ENTITY resetButton.accesskey "C"> <!ENTITY openButton.label "Open"> <!ENTITY openButton.accesskey "n"> <!ENTITY deleteButton.label "Delete"> <!ENTITY deleteButton.accesskey "D"> <!ENTITY searchDialogTitle.label "Search Messages"> <!ENTITY results.label "Results">
--- a/mailnews/base/content/virtualFolderProperties.js +++ b/mailnews/base/content/virtualFolderProperties.js @@ -93,16 +93,18 @@ function onLoad() document.getElementById("name").value = arguments.newFolderName; if (arguments.searchFolderURIs) gSearchFolderURIs = arguments.searchFolderURIs; setupSearchRows(gSearchTermSession.searchTerms); doEnabling(); // we only need to disable/enable the OK button for new virtual folders } + if (typeof arguments.searchOnline != "undefined") + document.getElementById('searchOnline').checked = arguments.searchOnline; updateOnlineSearchState(); doSetOKCancel(onOK, onCancel); } function setupSearchRows(aSearchTerms) { if (aSearchTerms && aSearchTerms.Count() > 0) initializeSearchRows(nsMsgSearchScope.offlineMail, aSearchTerms); // load the search terms for the folder
--- a/mailnews/base/search/public/nsMsgSearchAdapter.h +++ b/mailnews/base/search/public/nsMsgSearchAdapter.h @@ -197,33 +197,41 @@ protected: // object makes cleanup of these tables (at shutdown-time) automagic. nsCOMPtr<nsIMsgSearchValidityTable> m_offlineMailTable; nsCOMPtr<nsIMsgSearchValidityTable> m_offlineMailFilterTable; nsCOMPtr<nsIMsgSearchValidityTable> m_onlineMailTable; nsCOMPtr<nsIMsgSearchValidityTable> m_onlineMailFilterTable; nsCOMPtr<nsIMsgSearchValidityTable> m_onlineManualFilterTable; - nsCOMPtr<nsIMsgSearchValidityTable> m_newsTable; - nsCOMPtr<nsIMsgSearchValidityTable> m_localNewsTable; // used for local news searching or offline news searching... + nsCOMPtr<nsIMsgSearchValidityTable> m_newsTable; // online news + + // Local news tables, used for local news searching or offline. + nsCOMPtr<nsIMsgSearchValidityTable> m_localNewsTable; // base table + nsCOMPtr<nsIMsgSearchValidityTable> m_localNewsJunkTable; // base + junk + nsCOMPtr<nsIMsgSearchValidityTable> m_localNewsBodyTable; // base + body + nsCOMPtr<nsIMsgSearchValidityTable> m_localNewsJunkBodyTable; // base + junk + body nsCOMPtr<nsIMsgSearchValidityTable> m_ldapTable; nsCOMPtr<nsIMsgSearchValidityTable> m_ldapAndTable; nsCOMPtr<nsIMsgSearchValidityTable> m_localABTable; nsCOMPtr<nsIMsgSearchValidityTable> m_localABAndTable; nsCOMPtr<nsIMsgSearchValidityTable> m_newsFilterTable; nsresult NewTable (nsIMsgSearchValidityTable **); nsresult InitOfflineMailTable(); nsresult InitOfflineMailFilterTable(); nsresult InitOnlineMailTable(); nsresult InitOnlineMailFilterTable(); nsresult InitOnlineManualFilterTable(); nsresult InitNewsTable(); nsresult InitLocalNewsTable(); + nsresult InitLocalNewsJunkTable(); + nsresult InitLocalNewsBodyTable(); + nsresult InitLocalNewsJunkBodyTable(); nsresult InitNewsFilterTable(); //set the custom headers in the table, changes whenever "mailnews.customHeaders" pref changes. nsresult SetOtherHeadersInTable(nsIMsgSearchValidityTable *table, const char *customHeaders); nsresult InitLdapTable(); nsresult InitLdapAndTable(); nsresult InitLocalABTable();
--- a/mailnews/base/search/public/nsMsgSearchCore.idl +++ b/mailnews/base/search/public/nsMsgSearchCore.idl @@ -48,27 +48,34 @@ interface nsIMsgDBHdr; [scriptable, uuid(5fe70a74-304e-11d3-9be1-00a0c900d445)] interface nsMsgSearchScope { const nsMsgSearchScopeValue offlineMail = 0; const nsMsgSearchScopeValue offlineMailFilter = 1; const nsMsgSearchScopeValue onlineMail = 2; const nsMsgSearchScopeValue onlineMailFilter = 3; + /// offline news, base table, no body or junk const nsMsgSearchScopeValue localNews = 4; const nsMsgSearchScopeValue news = 5; const nsMsgSearchScopeValue newsEx = 6; const nsMsgSearchScopeValue LDAP = 7; const nsMsgSearchScopeValue LocalAB = 8; const nsMsgSearchScopeValue allSearchableGroups = 9; const nsMsgSearchScopeValue newsFilter = 10; const nsMsgSearchScopeValue LocalABAnd = 11; const nsMsgSearchScopeValue LDAPAnd = 12; // IMAP and NEWS, searched using local headers const nsMsgSearchScopeValue onlineManual = 13; + /// local news + junk + const nsMsgSearchScopeValue localNewsJunk = 14; + /// local news + body + const nsMsgSearchScopeValue localNewsBody = 15; + /// local news + junk + body + const nsMsgSearchScopeValue localNewsJunkBody = 16; }; typedef long nsMsgSearchAttribValue; /** * Definitions of search attribute types. The numerical order * from here will also be used to determine the order that the * attributes display in the filter editor.
--- a/mailnews/base/search/src/nsMsgLocalSearch.cpp +++ b/mailnews/base/search/src/nsMsgLocalSearch.cpp @@ -873,81 +873,173 @@ nsresult nsMsgSearchOfflineNews::OpenSum return err; } nsresult nsMsgSearchOfflineNews::ValidateTerms () { return nsMsgSearchOfflineMail::ValidateTerms (); } +// local helper functions to set subsets of the validity table -//----------------------------------------------------------------------------- +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::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); + + aTable->SetAvailable(nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Is, 1); + aTable->SetEnabled(nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Is, 1); + aTable->SetAvailable(nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled(nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Isnt, 1); + + return NS_OK; +} + +nsresult SetBody(nsIMsgSearchValidityTable* aTable) +{ + NS_ENSURE_ARG_POINTER(aTable); + aTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::Contains, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Contains, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::DoesntContain, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::DoesntContain, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Is, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Isnt, 1); + + return NS_OK; +} + +// set the base validity table values for local news +nsresult SetLocalNews(nsIMsgSearchValidityTable* aTable) +{ + NS_ENSURE_ARG_POINTER(aTable); + + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1); + + aTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1); + + aTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1); + + aTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, 1); + aTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, 1); + aTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1); + aTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1); + aTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1); + + aTable->SetAvailable (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Is, 1); + aTable->SetAvailable (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, 1); + + aTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsEmpty, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsEmpty, 1); + aTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsntEmpty, 1); + aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsntEmpty, 1); + + aTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); + aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); + aTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1); + aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1); + aTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); + aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); + aTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Isnt, 1); + aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Isnt, 1); + aTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); + aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); + aTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); + aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); + return NS_OK; + +} + nsresult nsMsgSearchValidityManager::InitLocalNewsTable() { - NS_ASSERTION (nsnull == m_localNewsTable, "already have local news validty table"); - nsresult err = NewTable (getter_AddRefs(m_localNewsTable)); - - if (NS_SUCCEEDED(err)) - { - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1); - - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1); - - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::DoesntContain, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::DoesntContain, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Body, nsMsgSearchOp::Isnt, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Isnt, 1); - + NS_ASSERTION (nsnull == m_localNewsTable, "already have local news validity table"); + nsresult rv = NewTable(getter_AddRefs(m_localNewsTable)); + NS_ENSURE_SUCCESS(rv, rv); + return SetLocalNews(m_localNewsTable); +} - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1); - - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1); - - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, 1); - - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); - m_localNewsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); - m_localNewsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); - - - } - - return err; +nsresult nsMsgSearchValidityManager::InitLocalNewsBodyTable() +{ + NS_ASSERTION (nsnull == m_localNewsBodyTable, "already have local news+body validity table"); + nsresult rv = NewTable(getter_AddRefs(m_localNewsBodyTable)); + NS_ENSURE_SUCCESS(rv, rv); + rv = SetLocalNews(m_localNewsBodyTable); + NS_ENSURE_SUCCESS(rv, rv); + return SetBody(m_localNewsBodyTable); } +nsresult nsMsgSearchValidityManager::InitLocalNewsJunkTable() +{ + NS_ASSERTION (nsnull == m_localNewsJunkTable, "already have local news+junk validity table"); + nsresult rv = NewTable(getter_AddRefs(m_localNewsJunkTable)); + NS_ENSURE_SUCCESS(rv, rv); + rv = SetLocalNews(m_localNewsJunkTable); + NS_ENSURE_SUCCESS(rv, rv); + return SetJunk(m_localNewsJunkTable); +} +nsresult nsMsgSearchValidityManager::InitLocalNewsJunkBodyTable() +{ + NS_ASSERTION (nsnull == m_localNewsJunkBodyTable, "already have local news+junk+body validity table"); + nsresult rv = NewTable(getter_AddRefs(m_localNewsJunkBodyTable)); + NS_ENSURE_SUCCESS(rv, rv); + rv = SetLocalNews(m_localNewsJunkBodyTable); + NS_ENSURE_SUCCESS(rv, rv); + rv = SetJunk(m_localNewsJunkBodyTable); + NS_ENSURE_SUCCESS(rv, rv); + return SetBody(m_localNewsJunkBodyTable); +}
--- a/mailnews/base/search/src/nsMsgSearchAdapter.cpp +++ b/mailnews/base/search/src/nsMsgSearchAdapter.cpp @@ -1044,16 +1044,38 @@ NS_IMETHODIMP nsMsgSearchValidityManager break; case nsMsgSearchScope::localNews: if (!m_localNewsTable) rv = InitLocalNewsTable(); if (m_localNewsTable) rv = SetOtherHeadersInTable(m_localNewsTable, customHeaders.get()); *ppOutTable = m_localNewsTable; break; + case nsMsgSearchScope::localNewsJunk: + if (!m_localNewsJunkTable) + rv = InitLocalNewsJunkTable(); + if (m_localNewsJunkTable) + rv = SetOtherHeadersInTable(m_localNewsJunkTable, customHeaders.get()); + *ppOutTable = m_localNewsJunkTable; + break; + case nsMsgSearchScope::localNewsBody: + if (!m_localNewsBodyTable) + rv = InitLocalNewsBodyTable(); + if (m_localNewsBodyTable) + rv = SetOtherHeadersInTable(m_localNewsBodyTable, customHeaders.get()); + *ppOutTable = m_localNewsBodyTable; + break; + case nsMsgSearchScope::localNewsJunkBody: + if (!m_localNewsJunkBodyTable) + rv = InitLocalNewsJunkBodyTable(); + if (m_localNewsJunkBodyTable) + rv = SetOtherHeadersInTable(m_localNewsJunkBodyTable, customHeaders.get()); + *ppOutTable = m_localNewsJunkBodyTable; + break; + case nsMsgSearchScope::onlineManual: if (!m_onlineManualFilterTable) rv = InitOnlineManualFilterTable(); if (m_onlineManualFilterTable) rv = SetOtherHeadersInTable(m_onlineManualFilterTable, customHeaders.get()); *ppOutTable = m_onlineManualFilterTable; break; case nsMsgSearchScope::LDAP:
--- a/mailnews/base/search/src/nsMsgSearchTerm.cpp +++ b/mailnews/base/search/src/nsMsgSearchTerm.cpp @@ -1941,31 +1941,35 @@ nsresult nsMsgSearchScopeTerm::Initializ nsresult err = NS_OK; switch (m_attribute) { case nsMsgSearchScope::onlineMail: m_adapter = new nsMsgSearchOnlineMail (this, termList); break; case nsMsgSearchScope::offlineMail: + case nsMsgSearchScope::onlineManual: m_adapter = new nsMsgSearchOfflineMail (this, termList); break; case nsMsgSearchScope::newsEx: NS_ASSERTION(PR_FALSE, "not supporting newsEx yet"); break; case nsMsgSearchScope::news: m_adapter = new nsMsgSearchNews (this, termList); break; case nsMsgSearchScope::allSearchableGroups: NS_ASSERTION(PR_FALSE, "not supporting allSearchableGroups yet"); break; case nsMsgSearchScope::LDAP: NS_ASSERTION(PR_FALSE, "not supporting LDAP yet"); break; case nsMsgSearchScope::localNews: + case nsMsgSearchScope::localNewsJunk: + case nsMsgSearchScope::localNewsBody: + case nsMsgSearchScope::localNewsJunkBody: m_adapter = new nsMsgSearchOfflineNews (this, termList); break; default: NS_ASSERTION(PR_FALSE, "invalid scope"); err = NS_ERROR_FAILURE; } if (m_adapter)
--- a/mailnews/base/src/searchSpec.js +++ b/mailnews/base/src/searchSpec.js @@ -375,52 +375,62 @@ SearchSpec.prototype = { // MatchHdr. if (this.owner.isSynthetic) { // We don't want to pass in a folder, and we don't want to use the // allSearchableGroups scope, so we cheat and use AddDirectoryScopeTerm. session.addDirectoryScopeTerm(nsMsgSearchScope.offlineMail); return; } - // We are filtering if we have mail view terms or user terms. When - // filtering, we bias towards offline search. The only time we would use - // an online search when filtering is if one of the constraints uses the - // body attribute and the folder is not marked for offline access. - // We are not filtering if we only have virtual folder terms, in which case - // we honor the onlineSearch attribute. This means that we use the - // folder's server's searchScope if the folder is not explicitly marked - // offline. - // For further discussion on this choice of logic, please read from: - // https://bugzilla.mozilla.org/show_bug.cgi?id=474701#c73 - let filtering = this._virtualFolderTerms == null && - this._viewTerms == null; - let ioService = Cc["@mozilla.org/network/io-service;1"] .getService(Ci.nsIIOService); + let validityManager = Cc['@mozilla.org/mail/search/validityManager;1'] + .getService(Ci.nsIMsgSearchValidityManager); for each (let [, folder] in Iterator(this.owner._underlyingFolders)) { // we do not need to check isServer here because _underlyingFolders // filtered it out when it was initialized. let scope; - let folderIsOffline = (folder instanceof nsIMsgLocalMailFolder) || - (folder.flags & nsMsgFolderFlags.Offline) || - ioService.offline; - // To restate the above logic into simpler rules, the scope is definitely - // offline if: - // - Folders available offline always use offline search. - // - If we are filtering and don't have a body term, use offline search. - // - If we are not filtering and our virtual folder is not marked for - // onlineSearch. - if (folderIsOffline || - (filtering && !haveBodyTerm) || - (!filtering && !this.onlineSearch)) - scope = nsMsgSearchScope.offlineMail; - // Otherwise, it's up to the folder's sever's searchScope. - else - scope = folder.server.searchScope; + let serverScope = folder.server.searchScope; + // If we're offline, or this is a local folder, or there's no separate + // online scope, use server scope. + if (ioService.offline || (serverScope == nsMsgSearchScope.offlineMail) || + (folder instanceof nsIMsgLocalMailFolder)) + scope = serverScope; + else { + // we need to test the validity in online and offline tables + let onlineValidityTable = validityManager.getTable(serverScope); + + let offlineScope; + if (folder.flags & nsMsgFolderFlags.Offline) + offlineScope = nsMsgSearchScope.offlineMail; + else + // The onlineManual table is used for local search when there is no + // body available. + offlineScope = nsMsgSearchScope.onlineManual; + + let offlineValidityTable = validityManager.getTable(offlineScope); + let offlineAvailable = true; + let onlineAvailable = true; + for each (let term in fixIterator(session.searchTerms, + nsIMsgSearchTerm)) { + if (!offlineValidityTable.getAvailable(term.attrib, term.op)) + offlineAvailable = false; + if (!onlineValidityTable.getAvailable(term.attrib, term.op)) + onlineAvailable = false; + } + // If both scopes work, honor the onlineSearch request + if (onlineAvailable && offlineAvailable) + scope = this.onlineSearch ? serverScope : offlineScope; + // If only one works, use it. Otherwise, default to offline + else if (onlineAvailable) + scope = serverScope; + else + scope = offlineScope; + } session.addScopeTerm(scope, folder); } }, prettyStringOfSearchTerms: function(aSearchTerms) { if (aSearchTerms == null) return ' (none)\n';
--- a/mailnews/news/src/nsNntpIncomingServer.cpp +++ b/mailnews/news/src/nsNntpIncomingServer.cpp @@ -2112,17 +2112,19 @@ nsNntpIncomingServer::GetFilterScope(nsM } NS_IMETHODIMP nsNntpIncomingServer::GetSearchScope(nsMsgSearchScopeValue *searchScope) { NS_ENSURE_ARG_POINTER(searchScope); if (WeAreOffline()) { - *searchScope = nsMsgSearchScope::localNews; + // This value is set to the localNewsBody scope to be compatible with + // the legacy default value. + *searchScope = nsMsgSearchScope::localNewsBody; } else { *searchScope = nsMsgSearchScope::news; } return NS_OK; } NS_IMETHODIMP