Back to index

lightning-sunbird  0.9+nobinonly
nsMsgSearchNews.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "msgCore.h"
00038 #include "nsMsgSearchAdapter.h"
00039 #include "nsXPIDLString.h"
00040 #include "nsUnicharUtils.h"
00041 #include "nsReadableUtils.h"
00042 #include "nsMsgSearchScopeTerm.h"
00043 #include "nsMsgResultElement.h"
00044 #include "nsMsgSearchTerm.h"
00045 #include "nsIMsgHdr.h"
00046 #include "nsMsgSearchNews.h"
00047 #include "nsIDBFolderInfo.h"
00048 #include "prprf.h"
00049 
00050 // Implementation of search for IMAP mail folders
00051 
00052 
00053 // Implementation of search for newsgroups
00054 
00055 
00056 //-----------------------------------------------------------------------------
00057 //----------- Adapter class for searching XPAT-capable news servers -----------
00058 //-----------------------------------------------------------------------------
00059 
00060 
00061 const char *nsMsgSearchNews::m_kNntpFrom = "FROM ";
00062 const char *nsMsgSearchNews::m_kNntpSubject = "SUBJECT ";
00063 const char *nsMsgSearchNews::m_kTermSeparator = "/";
00064 
00065 
00066 nsMsgSearchNews::nsMsgSearchNews (nsMsgSearchScopeTerm *scope, nsISupportsArray *termList) : nsMsgSearchAdapter (scope, termList)
00067 {
00068 }
00069 
00070 
00071 nsMsgSearchNews::~nsMsgSearchNews ()
00072 {
00073 }
00074 
00075 
00076 nsresult nsMsgSearchNews::ValidateTerms ()
00077 {
00078        nsresult err = nsMsgSearchAdapter::ValidateTerms ();
00079        if (NS_OK == err)
00080        {
00081               err = Encode (&m_encoding);
00082        }
00083 
00084        return err;
00085 }
00086 
00087 
00088 nsresult nsMsgSearchNews::Search (PRBool *aDone)
00089 {
00090        // the state machine runs in the news: handler
00091        nsresult err = NS_ERROR_NOT_IMPLEMENTED;
00092        return err;
00093 }
00094 
00095 PRUnichar *nsMsgSearchNews::EncodeToWildmat (const PRUnichar *value)
00096 {
00097        // Here we take advantage of XPAT's use of the wildmat format, which allows
00098        // a case-insensitive match by specifying each case possibility for each character
00099        // So, "FooBar" is encoded as "[Ff][Oo][Bb][Aa][Rr]"
00100 
00101   PRUnichar *caseInsensitiveValue = (PRUnichar*) nsMemory::Alloc(sizeof(PRUnichar) * ((4 * nsCRT::strlen(value)) + 1));
00102        if (caseInsensitiveValue)
00103        {
00104               PRUnichar *walkValue = caseInsensitiveValue;
00105               while (*value)
00106               {
00107                      if (nsCRT::IsAsciiAlpha(*value))
00108                      {
00109                             *walkValue++ = (PRUnichar)'[';
00110                             *walkValue++ = ToUpperCase((PRUnichar)*value);
00111                             *walkValue++ = ToLowerCase((PRUnichar)*value);
00112                             *walkValue++ = (PRUnichar)']';
00113                      }
00114                      else
00115                             *walkValue++ = *value;
00116                      value++;
00117               }
00118               *walkValue = 0;
00119        }
00120        return caseInsensitiveValue;
00121 }
00122 
00123 
00124 char *nsMsgSearchNews::EncodeTerm (nsIMsgSearchTerm *term)
00125 {
00126        // Develop an XPAT-style encoding for the search term
00127 
00128        NS_ASSERTION(term, "null term");
00129        if (!term)
00130               return nsnull;
00131 
00132        // Find a string to represent the attribute
00133        const char *attribEncoding = nsnull;
00134   nsMsgSearchAttribValue attrib;
00135 
00136   term->GetAttrib(&attrib);
00137 
00138        switch (attrib)
00139        {
00140        case nsMsgSearchAttrib::Sender:
00141               attribEncoding = m_kNntpFrom;
00142               break;
00143        case nsMsgSearchAttrib::Subject:
00144               attribEncoding = m_kNntpSubject;
00145               break;
00146        default:
00147               NS_ASSERTION(PR_FALSE,"malformed search"); // malformed search term?
00148               return nsnull;
00149        }
00150 
00151        // Build a string to represent the string pattern
00152        PRBool leadingStar = PR_FALSE;
00153        PRBool trailingStar = PR_FALSE;
00154        int overhead = 1; // null terminator
00155   nsMsgSearchOpValue op;
00156   term->GetOp(&op);
00157 
00158        switch (op)
00159        {
00160        case nsMsgSearchOp::Contains:
00161               leadingStar = PR_TRUE;
00162               trailingStar = PR_TRUE;
00163               overhead += 2;
00164               break;
00165        case nsMsgSearchOp::Is:
00166               break;
00167        case nsMsgSearchOp::BeginsWith:
00168               trailingStar = PR_TRUE;
00169               overhead++;
00170               break;
00171        case nsMsgSearchOp::EndsWith:
00172               leadingStar = PR_TRUE;
00173               overhead++;
00174               break;
00175        default:
00176               NS_ASSERTION(PR_FALSE,"malformed search"); // malformed search term?
00177               return nsnull;
00178        }
00179        
00180     // ### i18N problem Get the csid from FE, which is the correct csid for term
00181 //     int16 wincsid = INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel);
00182 
00183        // Do INTL_FormatNNTPXPATInRFC1522Format trick for non-ASCII string
00184 //     unsigned char *intlNonRFC1522Value = INTL_FormatNNTPXPATInNonRFC1522Format (wincsid, (unsigned char*)term->m_value.u.string);
00185   nsCOMPtr <nsIMsgSearchValue> searchValue;
00186 
00187   nsresult rv = term->GetValue(getter_AddRefs(searchValue));
00188   if (NS_FAILED(rv) || !searchValue)
00189     return nsnull;
00190 
00191 
00192   nsXPIDLString intlNonRFC1522Value;
00193   rv = searchValue->GetStr(getter_Copies(intlNonRFC1522Value));
00194        if (NS_FAILED(rv) || !intlNonRFC1522Value)
00195               return nsnull;
00196               
00197        PRUnichar *caseInsensitiveValue = EncodeToWildmat (intlNonRFC1522Value);
00198        if (!caseInsensitiveValue)
00199               return nsnull;
00200 
00201        // TO DO: Do INTL_FormatNNTPXPATInRFC1522Format trick for non-ASCII string
00202        // Unfortunately, we currently do not handle xxx or xxx search in XPAT
00203        // Need to add the INTL_FormatNNTPXPATInRFC1522Format call after we can do that
00204        // so we should search a string in either RFC1522 format and non-RFC1522 format
00205               
00206        PRUnichar *escapedValue = EscapeSearchUrl (caseInsensitiveValue);
00207        nsMemory::Free(caseInsensitiveValue);
00208        if (!escapedValue)
00209               return nsnull;
00210 
00211 #if 0
00212        // We also need to apply NET_Escape to it since we have to pass 8-bits data
00213        // And sometimes % in the 7-bit doulbe byte JIS
00214        // 
00215        PRUnichar * urlEncoded = nsEscape(escapedValue, url_Path);
00216        nsCRT::free(escapedValue);
00217 
00218        if (! urlEncoded)
00219               return nsnull;
00220 
00221        char *pattern = new char [nsCRT::strlen(urlEncoded) + overhead];
00222        if (!pattern)
00223               return nsnull;
00224        else 
00225               pattern[0] = '\0';
00226 #else
00227     nsCAutoString pattern;
00228 #endif
00229 
00230     
00231        if (leadingStar)
00232       pattern.Append('*');
00233     AppendUTF16toUTF8(escapedValue, pattern);
00234        if (trailingStar)
00235       pattern.Append('*');
00236 
00237        // Combine the XPAT command syntax with the attribute and the pattern to
00238        // form the term encoding
00239        const char xpatTemplate[] = "XPAT %s 1- %s";
00240        int termLength = (sizeof(xpatTemplate) - 1) + strlen(attribEncoding) + pattern.Length() + 1;
00241        char *termEncoding = new char [termLength];
00242        if (termEncoding)
00243               PR_snprintf (termEncoding, termLength, xpatTemplate, attribEncoding, pattern.get());
00244 
00245        return termEncoding;
00246 }
00247 
00248 nsresult nsMsgSearchNews::GetEncoding(char **result)
00249 {
00250   NS_ENSURE_ARG(result);
00251   *result = ToNewCString(m_encoding);
00252   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00253 }
00254 
00255 nsresult nsMsgSearchNews::Encode (nsCString *outEncoding)
00256 {
00257        NS_ASSERTION(outEncoding, "no out encoding");
00258        if (!outEncoding)
00259               return NS_ERROR_NULL_POINTER;
00260 
00261        nsresult err = NS_OK;
00262 
00263   PRUint32 numTerms;
00264 
00265   m_searchTerms->Count(&numTerms);
00266        char **intermediateEncodings = new char * [numTerms];
00267        if (intermediateEncodings)
00268        {
00269               // Build an XPAT command for each term
00270               int encodingLength = 0;
00271               PRUint32 i;
00272               for (i = 0; i < numTerms; i++)
00273               {
00274       nsCOMPtr<nsIMsgSearchTerm> pTerm;
00275       m_searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
00276                                (void **)getter_AddRefs(pTerm));
00277                      // set boolean OR term if any of the search terms are an OR...this only works if we are using
00278                      // homogeneous boolean operators.
00279       PRBool isBooleanOpAnd;
00280       pTerm->GetBooleanAnd(&isBooleanOpAnd);
00281                      m_ORSearch = !isBooleanOpAnd;
00282               
00283                      intermediateEncodings[i] = EncodeTerm (pTerm);   
00284                      if (intermediateEncodings[i])
00285                             encodingLength += strlen(intermediateEncodings[i]) + strlen(m_kTermSeparator);
00286               }
00287               encodingLength += strlen("?search");
00288               // Combine all the term encodings into one big encoding
00289               char *encoding = new char [encodingLength + 1];
00290               if (encoding)
00291               {
00292                      PL_strcpy (encoding, "?search");
00293 
00294       m_searchTerms->Count(&numTerms);
00295 
00296                      for (i = 0; i < numTerms; i++)
00297                      {
00298                             if (intermediateEncodings[i])
00299                             {
00300                                    PL_strcat (encoding, m_kTermSeparator);
00301                                    PL_strcat (encoding, intermediateEncodings[i]);
00302                                    delete [] intermediateEncodings[i];
00303                             }
00304                      }
00305                      *outEncoding = encoding;
00306               }
00307               else
00308                      err = NS_ERROR_OUT_OF_MEMORY;
00309        }
00310        else
00311               err = NS_ERROR_OUT_OF_MEMORY;
00312        delete [] intermediateEncodings;
00313 
00314        return err;
00315 }
00316 
00317 NS_IMETHODIMP nsMsgSearchNews::AddHit(nsMsgKey key)
00318 {
00319   m_candidateHits.Add (key); 
00320   return NS_OK;
00321 }
00322 
00323 /* void CurrentUrlDone (in long exitCode); */
00324 NS_IMETHODIMP nsMsgSearchNews::CurrentUrlDone(PRInt32 exitCode)
00325 {
00326        CollateHits();
00327        ReportHits();
00328   return NS_OK;
00329 }
00330 
00331 
00332 #if 0 // need to switch this to a notify stop loading handler, I think.
00333 void nsMsgSearchNews::PreExitFunction (URL_Struct * /*url*/, int status, MWContext *context)
00334 {
00335        MSG_SearchFrame *frame = MSG_SearchFrame::FromContext (context);
00336        nsMsgSearchNews *adapter = (nsMsgSearchNews*) frame->GetRunningAdapter();
00337        adapter->CollateHits();
00338        adapter->ReportHits();
00339 
00340        if (status == MK_INTERRUPTED)
00341        {
00342               adapter->Abort();
00343               frame->EndCylonMode();
00344        }
00345        else
00346        {
00347               frame->m_idxRunningScope++;
00348               if (frame->m_idxRunningScope >= frame->m_scopeList.Count())
00349                      frame->EndCylonMode();
00350        }
00351 }
00352 #endif // 0
00353 PRBool nsMsgSearchNews::DuplicateHit(PRUint32 artNum)  
00354 // ASSUMES m_hits is sorted!!
00355 {
00356        PRUint32 index;
00357        for (index = 0; index < m_hits.GetSize(); index++)
00358               if (artNum == m_hits.ElementAt(index))
00359                      return PR_TRUE;
00360        return PR_FALSE;
00361 }
00362 
00363 
00364 void nsMsgSearchNews::CollateHits ()
00365 {
00366        // Since the XPAT commands are processed one at a time, the result set for the
00367        // entire query is the intersection of results for each XPAT command if an AND Search
00368        // otherwise we want the union of all the search hits (minus the duplicates of course)
00369 
00370        if (m_candidateHits.GetSize() == 0)
00371               return;
00372 
00373        // Sort the article numbers first, so it's easy to tell how many hits
00374        // on a given article we got
00375        m_candidateHits.QuickSort(CompareArticleNumbers);
00376        int size = m_candidateHits.GetSize();
00377        int index = 0;
00378        PRUint32 candidate = m_candidateHits.ElementAt(index);
00379 
00380        if (m_ORSearch)
00381        {
00382               for (index = 0; index < size; index++)
00383               {
00384                      candidate = m_candidateHits.ElementAt(index);
00385                      if (!DuplicateHit(candidate)) // if not a dup, add it to the hit list
00386                             m_hits.Add (candidate);
00387               }
00388               return;
00389        }
00390 
00391 
00392        // otherwise we have a traditional and search which must be collated
00393 
00394        // In order to get promoted into the hits list, a candidate article number
00395        // must appear in the results of each XPAT command. So if we fire 3 XPAT
00396        // commands (one per search term), the article number must appear 3 times.
00397        // If it appears less than 3 times, it matched some search terms, but not all
00398 
00399        PRUint32 termCount;
00400   m_searchTerms->Count(&termCount);
00401        PRUint32 candidateCount = 0;
00402        while (index < size)
00403        {
00404               if (candidate == m_candidateHits.ElementAt(index))
00405                      candidateCount++;
00406               else
00407                      candidateCount = 1;
00408               if (candidateCount == termCount)
00409                      m_hits.Add (m_candidateHits.ElementAt(index));
00410               candidate = m_candidateHits.ElementAt(index++);
00411        }
00412 }
00413 
00414 void nsMsgSearchNews::ReportHits ()
00415 {
00416   nsCOMPtr <nsIMsgDatabase> db;
00417   nsCOMPtr <nsIDBFolderInfo>  folderInfo;
00418   nsCOMPtr <nsIMsgFolder> scopeFolder;
00419 
00420   nsresult err = m_scope->GetFolder(getter_AddRefs(scopeFolder));
00421   if (NS_SUCCEEDED(err) && scopeFolder)
00422   {
00423     err = scopeFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(db));
00424   }
00425 
00426   if (db)
00427   {
00428          for (PRUint32 i = 0; i < m_hits.GetSize(); i++)
00429          {
00430       nsCOMPtr <nsIMsgDBHdr> header;
00431 
00432                 db->GetMsgHdrForKey(m_hits.ElementAt(i), getter_AddRefs(header));
00433                 if (header)
00434                        ReportHit(header, scopeFolder);
00435          }
00436   }
00437 }
00438 
00439 // ### this should take an nsIMsgFolder instead of a string location.
00440 void nsMsgSearchNews::ReportHit (nsIMsgDBHdr *pHeaders, nsIMsgFolder *folder)
00441 {
00442     // this is totally filched from msg_SearchOfflineMail until I decide whether the 
00443     // right thing is to get them from the db or from NNTP
00444 
00445     nsresult err = NS_OK;
00446     nsCOMPtr<nsIMsgSearchSession> session;
00447     nsCOMPtr <nsIMsgFolder> scopeFolder;
00448     err = m_scope->GetFolder(getter_AddRefs(scopeFolder));
00449     m_scope->GetSearchSession(getter_AddRefs(session));
00450     if (session)
00451       session->AddSearchHit (pHeaders, scopeFolder);
00452 }
00453 
00454 
00455 
00456 int PR_CALLBACK nsMsgSearchNews::CompareArticleNumbers (const void *v1, const void *v2, void *data)
00457 {
00458        // QuickSort callback to compare article numbers
00459 
00460        uint32 i1 = *(uint32*) v1;
00461        uint32 i2 = *(uint32*) v2;
00462        return i1 - i2;
00463 }
00464 
00465 
00466 //-----------------------------------------------------------------------------
00467 //-------- Adapter class for searching SEARCH-capable news servers ------------
00468 //-----------------------------------------------------------------------------
00469 
00470 
00471 const char *nsMsgSearchNewsEx::m_kSearchTemplate = "?search/SEARCH HEADER NEWSGROUPS %s %s";
00472 const char *nsMsgSearchNewsEx::m_kProfileTemplate = "%s/dummy?profile/PROFILE NEW %s HEADER NEWSGROUPS %s %s";
00473 
00474 nsMsgSearchNewsEx::nsMsgSearchNewsEx (nsMsgSearchScopeTerm *scope, nsISupportsArray *termList) : nsMsgSearchNews (scope, termList) 
00475 {
00476 }
00477 
00478 
00479 nsMsgSearchNewsEx::~nsMsgSearchNewsEx () 
00480 {
00481 }
00482 
00483 
00484 nsresult nsMsgSearchNewsEx::ValidateTerms ()
00485 {
00486        nsresult err = nsMsgSearchAdapter::ValidateTerms ();
00487        if (NS_OK == err)
00488               err = Encode (&m_encoding);
00489   // this used to create a url struct for some reason.
00490        return err;
00491 }
00492 
00493 nsresult nsMsgSearchNewsEx::Search (PRBool *aDone)
00494 {
00495        // State machine runs in mknews.c?
00496        return NS_ERROR_NOT_IMPLEMENTED;
00497 }
00498 
00499 nsresult nsMsgSearchNewsEx::Encode (nsCString *ppOutEncoding)
00500 {
00501        *ppOutEncoding = "";
00502        char *imapTerms = nsnull;
00503 
00504        // Figure out the charsets to use for the search terms and targets.
00505        nsXPIDLString srcCharset, dstCharset;
00506        GetSearchCharsets(getter_Copies(srcCharset), getter_Copies(dstCharset));
00507 
00508        nsresult err = EncodeImap (&imapTerms, m_searchTerms, srcCharset.get(), dstCharset.get(), PR_TRUE /*reallyDredd*/);
00509 #ifdef DOING_DREDD
00510        if (NS_OK == err)
00511        {
00512               char *scopeString = nsnull; 
00513               err = m_scope->m_frame->EncodeDreddScopes (&scopeString);
00514               if (NS_OK == err)
00515               {
00516                      // Wrap the pattern with the RFC-977bis (Dredd) specified SEARCH syntax
00517                      char *dreddEncoding = PR_smprintf (m_kSearchTemplate, scopeString, imapTerms);
00518                      if (dreddEncoding)
00519                      {
00520                             // Build the encoding part of the URL e.g. search?SEARCH FROM "John Smith"
00521                             *ppOutEncoding = dreddEncoding;
00522                             nsCRT::free(dreddEncoding);
00523                      }
00524                      else
00525                             err = NS_ERROR_OUT_OF_MEMORY;
00526                      nsCRT::free(scopeString);
00527               }
00528        }
00529 #endif
00530        return err;
00531 }
00532 
00533 #ifdef DOING_PROFILES
00534 nsresult nsMsgSearchNewsEx::SaveProfile (const char *profileName)
00535 {
00536        nsresult err = NS_OK;
00537        MSG_FolderInfo *folder = m_scope->m_folder;
00538 
00539        // Figure out which news host to fire the URL at. Maybe we should have a virtual function in MSG_FolderInfo for this?
00540        MSG_NewsHost *host = nsnull;
00541        MSG_FolderInfoNews *newsFolder = folder->GetNewsFolderInfo();
00542        if (newsFolder)
00543               host = newsFolder->GetHost();
00544        else if (FOLDER_CONTAINERONLY == folder->GetType())
00545               host = ((MSG_NewsFolderInfoContainer*) folder)->GetHost();
00546 
00547        NS_ABORT_IF_FALSE(nsnull != host && nsnull != profileName, "host and profileName should not be NULL");
00548        if (nsnull != host && nsnull != profileName)
00549        {
00550               char *scopeString = nsnull;
00551               m_scope->m_frame->EncodeDreddScopes (&scopeString);
00552 
00553               // Figure out the charsets to use for the search terms and targets.
00554               int16 src_csid, dst_csid;
00555               GetSearchCSIDs(src_csid, dst_csid);
00556 
00557               char *termsString = nsnull;
00558               EncodeImap (&termsString, m_searchTerms, 
00559                                    src_csid, dst_csid,
00560                                    PR_TRUE /*reallyDredd*/);
00561 
00562               char *legalProfileName = PL_strdup(profileName);
00563 
00564               if (termsString && scopeString && legalProfileName)
00565               {
00566                      msg_MakeLegalNewsgroupComponent (legalProfileName);
00567                      char *url = PR_smprintf (m_kProfileTemplate, host->GetURLBase(),
00568                                                                 legalProfileName, scopeString,
00569                                                                 termsString);
00570                      if (url)
00571                      {
00572                             URL_Struct *urlStruct = NET_CreateURLStruct (url, NET_DONT_RELOAD);
00573                             if (urlStruct)
00574                             {
00575                                    // Set the internal_url flag so just in case someone else happens to have
00576                                    // a search-libmsg URL, it won't fire my code, and surely crash.
00577                                    urlStruct->internal_url = PR_TRUE;
00578 
00579                                    // Set the pre_exit_fn to we can turn off cylon mode when we're done
00580                                    urlStruct->pre_exit_fn = PreExitFunctionEx;
00581 
00582                                    int getUrlErr = m_scope->m_frame->m_pane->GetURL (urlStruct, PR_FALSE);
00583                                    if (getUrlErr != 0)
00584                                           err = SearchError_ScopeAgreement; // ### not really. impedance mismatch
00585                                    else
00586                                           m_scope->m_frame->BeginCylonMode();
00587                             }
00588                             else
00589                                    err = NS_ERROR_OUT_OF_MEMORY;
00590                             nsCRT::free(url);
00591                      }
00592                      else
00593                             err = NS_ERROR_OUT_OF_MEMORY;
00594               }
00595 
00596               CRTFREEIF(scopeString);
00597               delete [] termsString;
00598               CRTFREEIF(legalProfileName);
00599        }
00600        return err;
00601 }
00602 #endif // DOING_PROFILES
00603 
00604 nsresult nsMsgSearchValidityManager::InitNewsTable()
00605 {
00606   NS_ASSERTION (nsnull == m_newsTable,"don't call this twice!");
00607   nsresult rv = NewTable (getter_AddRefs(m_newsTable));
00608   
00609   if (NS_SUCCEEDED(rv))
00610   {
00611     m_newsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
00612     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
00613     m_newsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
00614     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
00615     m_newsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
00616     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
00617     m_newsTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
00618     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
00619     
00620     m_newsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
00621     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
00622     m_newsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
00623     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
00624     m_newsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
00625     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
00626     m_newsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
00627     m_newsTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
00628   }
00629   
00630   return rv;
00631 }
00632 
00633 nsresult nsMsgSearchValidityManager::InitNewsFilterTable()
00634 {
00635   NS_ASSERTION (nsnull == m_newsFilterTable, "news filter table already initted");
00636   nsresult rv = NewTable (getter_AddRefs(m_newsFilterTable));
00637   
00638   if (NS_SUCCEEDED(rv))
00639   {
00640     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
00641     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
00642     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1);
00643     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1);
00644     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
00645     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
00646     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1);
00647     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1);
00648     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
00649     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
00650     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
00651     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
00652     
00653     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1);
00654     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1);
00655     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
00656     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
00657     
00658     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
00659     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
00660     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1);
00661     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1);
00662     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
00663     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
00664     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1);
00665     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1);
00666     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
00667     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
00668     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
00669     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
00670     
00671     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1);
00672     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1);
00673     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1);
00674     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1);
00675     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1);
00676     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1);
00677     m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1);
00678     m_newsFilterTable->SetEnabled   (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1);
00679   }
00680   
00681   return rv;
00682 }
00683 
00684 
00685 #ifdef DOING_EXNEWSSEARCH
00686 nsresult nsMsgSearchValidityManager::InitNewsExTable (nsINntpIncomingServer *newsHost)
00687 {
00688        nsresult err = NS_OK;
00689 
00690        if (!m_newsExTable)
00691               err = NewTable (getter_AddRefs(m_newsExTable));
00692 
00693        if (NS_OK == err)
00694        {
00695               PRBool hasAttrib = PR_TRUE;
00696     if (newsHost)
00697       newsHost->QuerySearchableHeader("FROM", &hasAttrib);
00698               m_newsExTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, hasAttrib);
00699               m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, hasAttrib);
00700               m_newsExTable->SetAvailable (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, hasAttrib);
00701               m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, hasAttrib);
00702 
00703     if (newsHost)
00704       newsHost->QuerySearchableHeader("SUBJECT", &hasAttrib);
00705     else
00706       hasAttrib = PR_TRUE;
00707               m_newsExTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, hasAttrib);
00708               m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, hasAttrib);
00709               m_newsExTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, hasAttrib);
00710               m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, hasAttrib);
00711 
00712     if (newsHost)
00713       newsHost->QuerySearchableHeader("DATE", &hasAttrib);
00714     else
00715       hasAttrib = PR_TRUE;
00716               m_newsExTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, hasAttrib);
00717               m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, hasAttrib);
00718               m_newsExTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, hasAttrib);
00719               m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, hasAttrib);
00720 
00721     if (newsHost)
00722       newsHost->QuerySearchableHeader(":TEXT", &hasAttrib);
00723     else
00724       hasAttrib = PR_TRUE;
00725     m_newsExTable->SetAvailable (nsMsgSearchAttrib::AnyText, nsMsgSearchOp::Contains, hasAttrib);
00726     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::AnyText, nsMsgSearchOp::Contains, hasAttrib);
00727     m_newsExTable->SetAvailable (nsMsgSearchAttrib::AnyText, nsMsgSearchOp::DoesntContain, hasAttrib);
00728     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::AnyText, nsMsgSearchOp::DoesntContain, hasAttrib);
00729 
00730     if (newsHost)
00731       newsHost->QuerySearchableHeader("KEYWORDS", &hasAttrib);
00732     else
00733       hasAttrib = PR_TRUE;
00734     m_newsExTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, hasAttrib);
00735     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, hasAttrib);
00736     m_newsExTable->SetAvailable (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, hasAttrib);
00737     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, hasAttrib);
00738 
00739 #ifdef LATER
00740     // Not sure whether this would be useful or not. If so, can we specify more
00741     // than one NEWSGROUPS term to the server? If not, it would be tricky to merge
00742     // this with the NEWSGROUPS term we generate for the scope.
00743     hasAttrib = newsHost ? newsHost->QuerySearchableHeader("NEWSGROUPS") : PR_TRUE;
00744     m_newsExTable->SetAvailable (nsMsgSearchAttrib::Newsgroups, nsMsgSearchOp::IsBefore, hasAttrib);
00745     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Newsgroups, nsMsgSearchOp::IsBefore, hasAttrib);
00746     m_newsExTable->SetAvailable (nsMsgSearchAttrib::Newsgroups, nsMsgSearchOp::IsAfter, hasAttrib);
00747     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::Newsgroups, nsMsgSearchOp::IsAfter, hasAttrib);
00748 #endif
00749     if (newsHost)
00750       newsHost->QuerySearchableHeader("DATE", &hasAttrib);
00751     else
00752       hasAttrib = PR_TRUE;
00753     m_newsExTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, hasAttrib);
00754     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, hasAttrib);
00755     m_newsExTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan,  hasAttrib);
00756     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, hasAttrib);
00757     m_newsExTable->SetAvailable (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is,  hasAttrib);
00758     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, hasAttrib);
00759 
00760     // it is possible that the user enters an arbitrary header that is not searchable using NNTP search extensions
00761     m_newsExTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);   // added for arbitrary headers
00762     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
00763     m_newsExTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1);
00764     m_newsExTable->SetEnabled   (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1);
00765   }
00766 
00767   return err;
00768 }
00769 
00770 nsresult nsMsgSearchValidityManager::PostProcessValidityTable (nsINntpIncomingServer *host)
00771 {
00772        return InitNewsExTable (host);
00773 }
00774 #endif