Back to index

lightning-sunbird  0.9+nobinonly
nsMsgSearchAdapter.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Howard Chu <hyc@symas.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "msgCore.h"
00040 #include "nsTextFormatter.h"
00041 #include "nsMsgSearchCore.h"
00042 #include "nsMsgSearchAdapter.h"
00043 #include "nsMsgSearchScopeTerm.h"
00044 #include "nsMsgI18N.h"
00045 #include "nsIPrefService.h"
00046 #include "nsIPrefBranch.h"
00047 #include "nsIPrefLocalizedString.h"
00048 #include "nsXPIDLString.h"
00049 #include "nsReadableUtils.h"
00050 #include "nsMsgSearchTerm.h"
00051 #include "nsMsgSearchBoolExpression.h"
00052 #include "nsIIOService.h"
00053 #include "nsNetCID.h"
00054 #include "prprf.h"
00055 #include "nsAutoPtr.h"
00056 
00057 // This stuff lives in the base class because the IMAP search syntax 
00058 // is used by the Dredd SEARCH command as well as IMAP itself
00059 
00060 // km - the NOT and HEADER strings are not encoded with a trailing
00061 //      <space> because they always precede a mnemonic that has a
00062 //      preceding <space> and double <space> characters cause some
00063 //            imap servers to return an error.
00064 const char *nsMsgSearchAdapter::m_kImapBefore   = " SENTBEFORE ";
00065 const char *nsMsgSearchAdapter::m_kImapBody     = " BODY ";
00066 const char *nsMsgSearchAdapter::m_kImapCC       = " CC ";
00067 const char *nsMsgSearchAdapter::m_kImapFrom     = " FROM ";
00068 const char *nsMsgSearchAdapter::m_kImapNot      = " NOT";
00069 const char *nsMsgSearchAdapter::m_kImapUnDeleted= " UNDELETED";
00070 const char *nsMsgSearchAdapter::m_kImapOr       = " OR";
00071 const char *nsMsgSearchAdapter::m_kImapSince    = " SENTSINCE ";
00072 const char *nsMsgSearchAdapter::m_kImapSubject  = " SUBJECT ";
00073 const char *nsMsgSearchAdapter::m_kImapTo       = " TO ";
00074 const char *nsMsgSearchAdapter::m_kImapHeader   = " HEADER";
00075 const char *nsMsgSearchAdapter::m_kImapAnyText  = " TEXT ";
00076 const char *nsMsgSearchAdapter::m_kImapKeyword  = " KEYWORD ";
00077 const char *nsMsgSearchAdapter::m_kNntpKeywords = " KEYWORDS "; //ggrrrr...
00078 const char *nsMsgSearchAdapter::m_kImapSentOn = " SENTON ";
00079 const char *nsMsgSearchAdapter::m_kImapSeen = " SEEN ";
00080 const char *nsMsgSearchAdapter::m_kImapAnswered = " ANSWERED ";
00081 const char *nsMsgSearchAdapter::m_kImapNotSeen = " UNSEEN ";
00082 const char *nsMsgSearchAdapter::m_kImapNotAnswered = " UNANSWERED ";
00083 const char *nsMsgSearchAdapter::m_kImapCharset = " CHARSET ";
00084 const char *nsMsgSearchAdapter::m_kImapSizeSmaller = " SMALLER ";
00085 const char *nsMsgSearchAdapter::m_kImapSizeLarger = " LARGER ";
00086 const char *nsMsgSearchAdapter::m_kImapNew = " NEW "; 
00087 const char *nsMsgSearchAdapter::m_kImapNotNew = " OLD SEEN "; 
00088 const char *nsMsgSearchAdapter::m_kImapFlagged = " FLAGGED ";
00089 const char *nsMsgSearchAdapter::m_kImapNotFlagged = " UNFLAGGED ";
00090 
00091 #define PREF_CUSTOM_HEADERS "mailnews.customHeaders"
00092 
00093 NS_IMETHODIMP nsMsgSearchAdapter::FindTargetFolder(const nsMsgResultElement *,nsIMsgFolder * *)
00094 {
00095        return NS_ERROR_NOT_IMPLEMENTED;
00096 }
00097 
00098 NS_IMETHODIMP nsMsgSearchAdapter::ModifyResultElement(nsMsgResultElement *, nsMsgSearchValue *)
00099 {
00100        return NS_ERROR_NOT_IMPLEMENTED;
00101 }
00102 
00103 NS_IMETHODIMP nsMsgSearchAdapter::OpenResultElement(nsMsgResultElement *)
00104 {
00105        return NS_ERROR_NOT_IMPLEMENTED;
00106 }
00107 
00108 NS_IMPL_ISUPPORTS1(nsMsgSearchAdapter, nsIMsgSearchAdapter)
00109 
00110 nsMsgSearchAdapter::nsMsgSearchAdapter(nsIMsgSearchScopeTerm *scope, nsISupportsArray *searchTerms) 
00111        : m_searchTerms(searchTerms)
00112 {
00113   m_scope = scope;
00114 }
00115 
00116 nsMsgSearchAdapter::~nsMsgSearchAdapter()
00117 {
00118 }
00119 
00120 NS_IMETHODIMP nsMsgSearchAdapter::ValidateTerms ()
00121 {
00122   // all this used to do is check if the object had been deleted - we can skip that.
00123        return NS_OK;
00124 }
00125 
00126 NS_IMETHODIMP nsMsgSearchAdapter::Abort ()
00127 {
00128        return NS_ERROR_NOT_IMPLEMENTED;
00129 
00130 }
00131 NS_IMETHODIMP nsMsgSearchAdapter::Search (PRBool *aDone) 
00132 {
00133   return NS_OK; 
00134 }
00135 
00136 NS_IMETHODIMP nsMsgSearchAdapter::SendUrl () 
00137 {
00138   return NS_OK; 
00139 }
00140 
00141 /* void CurrentUrlDone (in long exitCode); */
00142 NS_IMETHODIMP nsMsgSearchAdapter::CurrentUrlDone(PRInt32 exitCode)
00143 {
00144   // base implementation doesn't need to do anything.
00145   return NS_OK;
00146 }
00147 
00148 NS_IMETHODIMP nsMsgSearchAdapter::GetEncoding (char **encoding) 
00149 {
00150   return NS_OK; 
00151 }
00152 
00153 NS_IMETHODIMP nsMsgSearchAdapter::AddResultElement (nsIMsgDBHdr *pHeaders)
00154 {
00155     NS_ASSERTION(PR_FALSE, "shouldn't call this base class impl");
00156     return NS_ERROR_FAILURE;
00157 }
00158 
00159 
00160 NS_IMETHODIMP nsMsgSearchAdapter::AddHit(nsMsgKey key)
00161 {
00162   NS_ASSERTION(PR_FALSE, "shouldn't call this base class impl");
00163   return NS_ERROR_FAILURE;
00164 }
00165 
00166 
00167 char *
00168 nsMsgSearchAdapter::GetImapCharsetParam(const PRUnichar *destCharset)
00169 {
00170        char *result = nsnull;
00171 
00172        // Specify a character set unless we happen to be US-ASCII.
00173   if (nsCRT::strcmp(destCharset, NS_LITERAL_STRING("us-ascii").get()))
00174            result = PR_smprintf("%s%s", nsMsgSearchAdapter::m_kImapCharset, NS_ConvertUCS2toUTF8(destCharset).get());
00175 
00176        return result;
00177 }
00178 
00179 /* 
00180    09/21/2000 - taka@netscape.com
00181    This method is bogus. Escape must be done against char * not PRUnichar *
00182    should be rewritten later.
00183    for now, just duplicate the string.
00184 */
00185 PRUnichar *nsMsgSearchAdapter::EscapeSearchUrl (const PRUnichar *nntpCommand)
00186 {
00187        return nsCRT::strdup(nntpCommand);
00188 #if 0
00189        PRUnichar *result = nsnull;
00190        // max escaped length is two extra characters for every character in the cmd.
00191   PRUnichar *scratchBuf = (PRUnichar*) PR_Malloc(sizeof(PRUnichar) * (3*nsCRT::strlen(nntpCommand) + 1));
00192        if (scratchBuf)
00193        {
00194               PRUnichar *scratchPtr = scratchBuf;
00195               while (PR_TRUE)
00196               {
00197                      PRUnichar ch = *nntpCommand++;
00198                      if (!ch)
00199                             break;
00200                      if (ch == '#' || ch == '?' || ch == '@' || ch == '\\')
00201                      {
00202                             *scratchPtr++ = '\\';
00203                 nsTextFormatter::snprintf(scratchPtr, 2,
00204                                           NS_LITERAL_STRING("%2.2X").get(), ch);
00205                                    /* Reviewed 4.51 safe use of sprintf */
00206                             scratchPtr += 2;
00207                      }
00208                      else
00209                             *scratchPtr++ = ch;
00210               }
00211               *scratchPtr = '\0';
00212               result = nsCRT::strdup (scratchBuf); // realloc down to smaller size
00213         nsCRT::free (scratchBuf);
00214        }
00215        return result;
00216 #endif
00217 }
00218 
00219 /* 
00220    09/21/2000 - taka@netscape.com
00221    This method is bogus. Escape must be done against char * not PRUnichar *
00222    should be rewritten later.
00223    for now, just duplicate the string.
00224 */
00225 PRUnichar *
00226 nsMsgSearchAdapter::EscapeImapSearchProtocol(const PRUnichar *imapCommand)
00227 {
00228        return nsCRT::strdup(imapCommand);
00229 #if 0
00230        PRUnichar *result = nsnull;
00231        // max escaped length is one extra character for every character in the cmd.
00232     PRUnichar *scratchBuf =
00233         (PRUnichar*) PR_Malloc (sizeof(PRUnichar) * (2*nsCRT::strlen(imapCommand) + 1));
00234        if (scratchBuf)
00235        {
00236               PRUnichar *scratchPtr = scratchBuf;
00237               while (1)
00238               {
00239                      PRUnichar ch = *imapCommand++;
00240                      if (!ch)
00241                             break;
00242                      if (ch == (PRUnichar)'\\')
00243                      {
00244                             *scratchPtr++ = (PRUnichar)'\\';
00245                             *scratchPtr++ = (PRUnichar)'\\';
00246                      }
00247                      else
00248                             *scratchPtr++ = ch;
00249               }
00250               *scratchPtr = 0;
00251         result = nsCRT::strdup (scratchBuf); // realloc down to smaller size
00252         nsCRT::free (scratchBuf);
00253        }
00254        return result;
00255 #endif
00256 }
00257 
00258 /* 
00259    09/21/2000 - taka@netscape.com
00260    This method is bogus. Escape must be done against char * not PRUnichar *
00261    should be rewritten later.
00262    for now, just duplicate the string.
00263 */
00264 PRUnichar *
00265 nsMsgSearchAdapter::EscapeQuoteImapSearchProtocol(const PRUnichar *imapCommand)
00266 {
00267        return nsCRT::strdup(imapCommand);
00268 #if 0
00269        PRUnichar *result = nsnull;
00270        // max escaped length is one extra character for every character in the cmd.
00271     PRUnichar *scratchBuf =
00272         (PRUnichar*) PR_Malloc (sizeof(PRUnichar) * (2*nsCRT::strlen(imapCommand) + 1));
00273        if (scratchBuf)
00274        {
00275               PRUnichar *scratchPtr = scratchBuf;
00276               while (1)
00277               {
00278                      PRUnichar ch = *imapCommand++;
00279                      if (!ch)
00280                             break;
00281                      if (ch == '"')
00282                      {
00283                             *scratchPtr++ = '\\';
00284                             *scratchPtr++ = '"';
00285                      }
00286                      else
00287                             *scratchPtr++ = ch;
00288               }
00289               *scratchPtr = '\0';
00290     result = nsCRT::strdup (scratchBuf); // realloc down to smaller size
00291     nsCRT::free (scratchBuf);
00292        }
00293        return result;
00294 #endif
00295 }
00296 
00297 
00298 char *nsMsgSearchAdapter::UnEscapeSearchUrl (const char *commandSpecificData)
00299 {
00300   char *result = (char*) PR_Malloc (strlen(commandSpecificData) + 1);
00301        if (result)
00302        {
00303               char *resultPtr = result;
00304               while (1)
00305               {
00306                      char ch = *commandSpecificData++;
00307                      if (!ch)
00308                             break;
00309                      if (ch == '\\')
00310                      {
00311                             char scratchBuf[3];
00312                             scratchBuf[0] = (char) *commandSpecificData++;
00313                             scratchBuf[1] = (char) *commandSpecificData++;
00314                             scratchBuf[2] = '\0';
00315                             unsigned int accum = 0;
00316                             sscanf (scratchBuf, "%X", &accum);
00317                             *resultPtr++ = (char) accum;
00318                      }
00319                      else
00320                             *resultPtr++ = ch;
00321               }
00322               *resultPtr = '\0';
00323        }
00324        return result;
00325 }
00326 
00327 
00328 nsresult 
00329 nsMsgSearchAdapter::GetSearchCharsets(PRUnichar **srcCharset, PRUnichar **dstCharset)
00330 {
00331   nsresult rv;
00332   nsAutoString destination;
00333   NS_ENSURE_ARG(srcCharset);
00334   NS_ENSURE_ARG(dstCharset);
00335   
00336   if (m_defaultCharset.IsEmpty())
00337   {
00338     m_forceAsciiSearch = PR_FALSE;  // set the default value in case of error
00339     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00340     if (NS_SUCCEEDED(rv))
00341     {
00342       nsCOMPtr<nsIPrefLocalizedString> localizedstr;
00343       rv = prefs->GetComplexValue("mailnews.view_default_charset", NS_GET_IID(nsIPrefLocalizedString),
00344                                   getter_AddRefs(localizedstr)); 
00345       if (NS_SUCCEEDED(rv))
00346         localizedstr->GetData(getter_Copies(m_defaultCharset));
00347 
00348       prefs->GetBoolPref("mailnews.force_ascii_search", &m_forceAsciiSearch);
00349     }
00350   }
00351   *srcCharset = m_defaultCharset.IsEmpty() ? 
00352     ToNewUnicode(NS_LITERAL_STRING("ISO-8859-1")) : ToNewUnicode(m_defaultCharset);
00353   
00354   if (m_scope)
00355   {
00356     // ### DMB is there a way to get the charset for the "window"?
00357     
00358     nsCOMPtr<nsIMsgFolder> folder;
00359     rv = m_scope->GetFolder(getter_AddRefs(folder));
00360     
00361     // Ask the newsgroup/folder for its csid.
00362     if (NS_SUCCEEDED(rv) && folder)
00363     {
00364       nsXPIDLCString folderCharset;
00365       folder->GetCharset(getter_Copies(folderCharset));
00366       AppendASCIItoUTF16(folderCharset, destination);
00367     }
00368   }
00369   else
00370   {
00371     destination.Assign(*srcCharset);
00372   }
00373   
00374   
00375   // If 
00376   // the destination is still CS_DEFAULT, make the destination match
00377   // the source. (CS_DEFAULT is an indication that the charset
00378   // was undefined or unavailable.)
00379   // ### well, it's not really anymore. Is there an equivalent?
00380   if (destination.Equals(m_defaultCharset))
00381   {
00382     destination.Assign(*srcCharset);
00383   }
00384   
00385   if (m_forceAsciiSearch)
00386   {
00387     // Special cases to use in order to force US-ASCII searching with Latin1
00388     // or MacRoman text. Eurgh. This only has to happen because IMAP
00389     // and Dredd servers currently (4/23/97) only support US-ASCII.
00390     // 
00391     // If the dest csid is ISO Latin 1 or MacRoman, attempt to convert the 
00392     // source text to US-ASCII. (Not for now.)
00393     // if ((dst_csid == CS_LATIN1) || (dst_csid == CS_MAC_ROMAN))
00394     destination.AssignLiteral("us-ascii");
00395   }
00396 
00397   *dstCharset = ToNewUnicode(destination);
00398   return NS_OK;
00399 }
00400 
00401 nsresult nsMsgSearchAdapter::EncodeImapTerm (nsIMsgSearchTerm *term, PRBool reallyDredd, const PRUnichar *srcCharset, const PRUnichar *destCharset, char **ppOutTerm)
00402 {
00403   nsresult err = NS_OK;
00404   PRBool useNot = PR_FALSE;
00405   PRBool useQuotes = PR_FALSE;
00406   PRBool ignoreValue = PR_FALSE;
00407   nsCAutoString arbitraryHeader;
00408   const char *whichMnemonic = nsnull;
00409   const char *orHeaderMnemonic = nsnull;
00410   
00411   *ppOutTerm = nsnull;
00412   
00413   nsCOMPtr <nsIMsgSearchValue> searchValue;
00414   nsresult rv = term->GetValue(getter_AddRefs(searchValue));
00415   
00416   if (NS_FAILED(rv))
00417     return rv;
00418   
00419   nsMsgSearchOpValue op;
00420   term->GetOp(&op);
00421   
00422   if (op == nsMsgSearchOp::DoesntContain || op == nsMsgSearchOp::Isnt)
00423     useNot = PR_TRUE;
00424   
00425   nsMsgSearchAttribValue attrib;
00426   term->GetAttrib(&attrib);
00427   
00428   switch (attrib)
00429   {
00430   case nsMsgSearchAttrib::ToOrCC:
00431     orHeaderMnemonic = m_kImapCC;
00432     // fall through to case nsMsgSearchAttrib::To:
00433   case nsMsgSearchAttrib::To:
00434     whichMnemonic = m_kImapTo;
00435     break;
00436   case nsMsgSearchAttrib::CC:
00437     whichMnemonic = m_kImapCC;
00438     break;
00439   case nsMsgSearchAttrib::Sender:
00440     whichMnemonic = m_kImapFrom;
00441     break;
00442   case nsMsgSearchAttrib::Subject:
00443     whichMnemonic = m_kImapSubject;
00444     break;
00445   case nsMsgSearchAttrib::Body:
00446     whichMnemonic = m_kImapBody;
00447     break;
00448   case nsMsgSearchAttrib::AgeInDays:  // added for searching online for age in days...
00449     // for AgeInDays, we are actually going to perform a search by date, so convert the operations for age
00450     // to the IMAP mnemonics that we would use for date!
00451     switch (op)
00452     {
00453     case nsMsgSearchOp::IsGreaterThan:
00454       whichMnemonic = m_kImapBefore;
00455       break;
00456     case nsMsgSearchOp::IsLessThan:
00457       whichMnemonic = m_kImapSince;
00458       break;
00459     case nsMsgSearchOp::Is:
00460       whichMnemonic = m_kImapSentOn;
00461       break;
00462     default:
00463       NS_ASSERTION(PR_FALSE, "invalid search operator");
00464       return NS_ERROR_INVALID_ARG;
00465     }
00466     break;
00467   case nsMsgSearchAttrib::Size:
00468     switch (op)
00469     {
00470     case nsMsgSearchOp::IsGreaterThan:
00471       whichMnemonic = m_kImapSizeLarger;
00472       break;
00473     case nsMsgSearchOp::IsLessThan:
00474       whichMnemonic = m_kImapSizeSmaller;
00475       break;
00476     default:
00477       NS_ASSERTION(PR_FALSE, "invalid search operator");
00478       return NS_ERROR_INVALID_ARG;
00479     }
00480     break;
00481     case nsMsgSearchAttrib::Date:
00482       switch (op)
00483       {
00484       case nsMsgSearchOp::IsBefore:
00485         whichMnemonic = m_kImapBefore;
00486         break;
00487       case nsMsgSearchOp::IsAfter:
00488         whichMnemonic = m_kImapSince;
00489         break;
00490       case nsMsgSearchOp::Isnt:  /* we've already added the "Not" so just process it like it was a date is search */
00491       case nsMsgSearchOp::Is:
00492         whichMnemonic = m_kImapSentOn;
00493         break;
00494       default:
00495         NS_ASSERTION(PR_FALSE, "invalid search operator");
00496         return NS_ERROR_INVALID_ARG;
00497       }
00498       break;
00499       case nsMsgSearchAttrib::AnyText:
00500         whichMnemonic = m_kImapAnyText;
00501         break;
00502       case nsMsgSearchAttrib::Keywords:
00503         whichMnemonic = m_kImapKeyword;
00504         break;
00505       case nsMsgSearchAttrib::MsgStatus:
00506         useNot = PR_FALSE; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
00507         ignoreValue = PR_TRUE; // the mnemonic is all we need
00508         PRUint32 status;
00509         searchValue->GetStatus(&status);
00510         
00511         switch (status)
00512         {
00513         case MSG_FLAG_READ:
00514           whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapSeen : m_kImapNotSeen;
00515           break;
00516         case MSG_FLAG_REPLIED:
00517           whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapAnswered : m_kImapNotAnswered;
00518           break;
00519         case MSG_FLAG_NEW:                         
00520           whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapNew : m_kImapNotNew;
00521           break; 
00522         case MSG_FLAG_MARKED:
00523           whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapFlagged : m_kImapNotFlagged;
00524           break;
00525         default:
00526           NS_ASSERTION(PR_FALSE, "invalid search operator");
00527           return NS_ERROR_INVALID_ARG;
00528         }
00529         break;
00530         default:
00531           if ( attrib > nsMsgSearchAttrib::OtherHeader && attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes)
00532           {
00533             nsXPIDLCString arbitraryHeaderTerm;
00534             term->GetArbitraryHeader(getter_Copies(arbitraryHeaderTerm));
00535             if (!arbitraryHeaderTerm.IsEmpty())
00536             {
00537               arbitraryHeader.AssignLiteral(" \"");
00538               arbitraryHeader.Append(arbitraryHeaderTerm);
00539               arbitraryHeader.AppendLiteral("\" ");
00540               whichMnemonic = arbitraryHeader.get();
00541             }
00542             else
00543               return NS_ERROR_FAILURE;
00544           }
00545           else
00546           {
00547             NS_ASSERTION(PR_FALSE, "invalid search operator");
00548             return NS_ERROR_INVALID_ARG;
00549           }
00550         }
00551         
00552         char *value = "";
00553         char dateBuf[100];
00554         dateBuf[0] = '\0';
00555         
00556         PRBool valueWasAllocated = PR_FALSE;
00557         if (attrib == nsMsgSearchAttrib::Date)
00558         {
00559           // note that there used to be code here that encoded an RFC822 date for imap searches.
00560           // The IMAP RFC 2060 is misleading to the point that it looks like it requires an RFC822
00561           // date but really it expects dd-mmm-yyyy, like dredd, and refers to the RFC822 date only in that the
00562           // dd-mmm-yyyy date will match the RFC822 date within the message.
00563           
00564           PRTime adjustedDate;
00565           searchValue->GetDate(&adjustedDate);
00566           if (whichMnemonic == m_kImapSince)
00567           {
00568             // it looks like the IMAP server searches on Since includes the date in question...
00569             // our UI presents Is, IsGreater and IsLessThan. For the IsGreater case (m_kImapSince)
00570             // we need to adjust the date so we get greater than and not greater than or equal to which
00571             // is what the IMAP server wants to search on
00572             // won't work on Mac.
00573             // ack, is this right? is PRTime seconds or microseconds?
00574             PRInt64 microSecondsPerSecond, secondsInDay, microSecondsInDay;
00575             
00576             LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
00577             LL_UI2L(secondsInDay, 60 * 60 * 24);
00578             LL_MUL(microSecondsInDay, secondsInDay, microSecondsPerSecond);
00579             LL_ADD(adjustedDate, adjustedDate, microSecondsInDay); // bump up to the day after this one...
00580           }
00581           
00582           PRExplodedTime exploded;
00583           PR_ExplodeTime(adjustedDate, PR_LocalTimeParameters, &exploded);
00584           PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%d-%b-%Y", &exploded);
00585           //         strftime (dateBuf, sizeof(dateBuf), "%d-%b-%Y", localtime (/* &term->m_value.u.date */ &adjustedDate));
00586           value = dateBuf;
00587         }
00588         else
00589         {
00590           if (attrib == nsMsgSearchAttrib::AgeInDays)
00591           {
00592             // okay, take the current date, subtract off the age in days, then do an appropriate Date search on 
00593             // the resulting day.
00594             PRUint32 ageInDays;
00595             
00596             searchValue->GetAge(&ageInDays);
00597             
00598             PRTime now = PR_Now();
00599             PRTime matchDay;
00600             
00601             PRInt64 microSecondsPerSecond, secondsInDays, microSecondsInDay;
00602             
00603             LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
00604             LL_UI2L(secondsInDays, 60 * 60 * 24 * ageInDays);
00605             LL_MUL(microSecondsInDay, secondsInDays, microSecondsPerSecond);
00606             
00607             LL_SUB(matchDay, now, microSecondsInDay); // = now - term->m_value.u.age * 60 * 60 * 24; 
00608             PRExplodedTime exploded;
00609             PR_ExplodeTime(matchDay, PR_LocalTimeParameters, &exploded);
00610             PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%d-%b-%Y", &exploded);
00611             //                     strftime (dateBuf, sizeof(dateBuf), "%d-%b-%Y", localtime (&matchDay));
00612             value = dateBuf;
00613           }
00614           else if (attrib == nsMsgSearchAttrib::Size)
00615           {
00616             PRUint32 sizeValue;
00617             nsCAutoString searchTermValue;
00618             searchValue->GetSize(&sizeValue);
00619 
00620             // Multiply by 1024 to get into kb resolution
00621             sizeValue *= 1024;
00622 
00623             // Ensure that greater than is really greater than
00624             // in kb resolution.
00625             if (op == nsMsgSearchOp::IsGreaterThan)
00626               sizeValue += 1024;
00627 
00628             searchTermValue.AppendInt(sizeValue);
00629 
00630             value = nsCRT::strdup(searchTermValue.get());
00631             valueWasAllocated = PR_TRUE;
00632           }
00633           else
00634             
00635             if (IsStringAttribute(attrib))
00636             {
00637               PRUnichar *convertedValue; // = reallyDredd ? MSG_EscapeSearchUrl (term->m_value.u.string) : msg_EscapeImapSearchProtocol(term->m_value.u.string);
00638               nsXPIDLString searchTermValue;
00639               searchValue->GetStr(getter_Copies(searchTermValue));
00640               // Ugly switch for Korean mail/news charsets.
00641               // We want to do this here because here is where
00642               // we know what charset we want to use.
00643 #ifdef DOING_CHARSET
00644               if (reallyDredd)
00645                 dest_csid = INTL_DefaultNewsCharSetID(dest_csid);
00646               else
00647                 dest_csid = INTL_DefaultMailCharSetID(dest_csid);
00648 #endif
00649               
00650               // do all sorts of crazy escaping
00651               convertedValue = reallyDredd ? EscapeSearchUrl (searchTermValue) :
00652               EscapeImapSearchProtocol(searchTermValue);
00653               useQuotes = ((!reallyDredd || 
00654                           (nsDependentString(convertedValue).FindChar(PRUnichar(' ')) != -1)) &&
00655                  (attrib != nsMsgSearchAttrib::Keywords));
00656               // now convert to char* and escape quoted_specials
00657               nsCAutoString valueStr;
00658               nsresult rv = ConvertFromUnicode(NS_LossyConvertUTF16toASCII(destCharset).get(),
00659                 nsDependentString(convertedValue), valueStr);
00660               if (NS_SUCCEEDED(rv))
00661               {
00662                 const char *vptr = valueStr.get();
00663                 // max escaped length is one extra character for every character in the cmd.
00664                 nsAutoArrayPtr<char> newValue(new char[2*strlen(vptr) + 1]);
00665                 if (newValue)
00666                 {
00667                   char *p = newValue;
00668                   while (1)
00669                   {
00670                     char ch = *vptr++;
00671                     if (!ch)
00672                       break;
00673                     if ((useQuotes ? ch == '"' : 0) || ch == '\\')
00674                       *p++ = '\\';
00675                     *p++ = ch;
00676                   }
00677                   *p = '\0';
00678                   value = nsCRT::strdup(newValue); // realloc down to smaller size
00679                 }
00680               }
00681               else
00682                 value = nsCRT::strdup("");
00683               nsCRT::free(convertedValue);
00684               valueWasAllocated = PR_TRUE;
00685               
00686             }
00687         }
00688         
00689         // this should be rewritten to use nsCString
00690         int len = strlen(whichMnemonic) + strlen(value) + (useNot ? strlen(m_kImapNot) : 0) + 
00691           (useQuotes ? 2 : 0) + strlen(m_kImapHeader) + 
00692           (orHeaderMnemonic ? (strlen(m_kImapHeader) + strlen(m_kImapOr) + (useNot ? strlen(m_kImapNot) : 0) + 
00693           strlen(orHeaderMnemonic) + strlen(value) + 2 /*""*/) : 0) + 10; // add slough for imap string literals
00694         char *encoding = new char[len];
00695         if (encoding)
00696         {
00697           encoding[0] = '\0';
00698           // Remember: if ToOrCC and useNot then the expression becomes NOT To AND Not CC as opposed to (NOT TO) || (NOT CC)
00699           if (orHeaderMnemonic && !useNot)
00700             PL_strcat(encoding, m_kImapOr);
00701           if (useNot)
00702             PL_strcat (encoding, m_kImapNot);
00703           if (!arbitraryHeader.IsEmpty())
00704             PL_strcat (encoding, m_kImapHeader);
00705           PL_strcat (encoding, whichMnemonic);
00706           if (!ignoreValue)
00707             err = EncodeImapValue(encoding, value, useQuotes, reallyDredd);
00708           
00709           if (orHeaderMnemonic)
00710           {
00711             if (useNot)
00712               PL_strcat(encoding, m_kImapNot);
00713             
00714             PL_strcat (encoding, m_kImapHeader);
00715             
00716             PL_strcat (encoding, orHeaderMnemonic);
00717             if (!ignoreValue)
00718               err = EncodeImapValue(encoding, value, useQuotes, reallyDredd);
00719           }
00720           
00721           // kmcentee, don't let the encoding end with whitespace, 
00722           // this throws off later url STRCMP
00723           if (*encoding && *(encoding + strlen(encoding) - 1) == ' ')
00724             *(encoding + strlen(encoding) - 1) = '\0';
00725         }
00726         
00727         if (value && valueWasAllocated)
00728           PR_Free (value);
00729         
00730         *ppOutTerm = encoding;
00731         
00732         return err;
00733 }
00734 
00735 nsresult nsMsgSearchAdapter::EncodeImapValue(char *encoding, const char *value, PRBool useQuotes, PRBool reallyDredd)
00736 {
00737   // By NNTP RFC, SEARCH HEADER SUBJECT "" is legal and means 'find messages without a subject header'
00738   if (!reallyDredd)
00739   {
00740     // By IMAP RFC, SEARCH HEADER SUBJECT "" is illegal and will generate an error from the server
00741     if (!value || !value[0])
00742       return NS_ERROR_NULL_POINTER;
00743   }
00744   
00745   if (!nsCRT::IsAscii(value))
00746   {
00747     nsCAutoString lengthStr;
00748     PL_strcat(encoding, "{");
00749     lengthStr.AppendInt((PRInt32) strlen(value));
00750     PL_strcat(encoding, lengthStr.get());
00751     PL_strcat(encoding, "}"CRLF);
00752     PL_strcat(encoding, value);
00753     return NS_OK;
00754   }
00755   if (useQuotes)
00756     PL_strcat(encoding, "\"");
00757   PL_strcat (encoding, value);
00758   if (useQuotes)
00759     PL_strcat(encoding, "\"");
00760   
00761   return NS_OK;
00762 }
00763 
00764 
00765 nsresult nsMsgSearchAdapter::EncodeImap (char **ppOutEncoding, nsISupportsArray *searchTerms, const PRUnichar *srcCharset, const PRUnichar *destCharset, PRBool reallyDredd)
00766 {
00767   // i've left the old code (before using CBoolExpression for debugging purposes to make sure that
00768   // the new code generates the same encoding string as the old code.....
00769   
00770   nsresult err = NS_OK;
00771   *ppOutEncoding = nsnull;
00772   
00773   PRUint32 termCount;
00774   searchTerms->Count(&termCount);
00775   PRUint32 i = 0;
00776   
00777   // create our expression
00778   nsMsgSearchBoolExpression * expression = new nsMsgSearchBoolExpression();
00779   if (!expression)
00780     return NS_ERROR_OUT_OF_MEMORY;
00781   
00782   for (i = 0; i < termCount && NS_SUCCEEDED(err); i++)
00783   {
00784     char *termEncoding;
00785     nsCOMPtr<nsIMsgSearchTerm> pTerm;
00786     searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
00787       (void **)getter_AddRefs(pTerm));
00788     err = EncodeImapTerm (pTerm, reallyDredd, srcCharset, destCharset, &termEncoding);
00789     if (NS_SUCCEEDED(err) && nsnull != termEncoding)
00790     {
00791       expression = nsMsgSearchBoolExpression::AddSearchTerm(expression, pTerm, termEncoding);
00792       delete [] termEncoding;
00793     }
00794   }
00795   
00796   if (NS_SUCCEEDED(err)) 
00797   {
00798     // Catenate the intermediate encodings together into a big string
00799     nsCAutoString encodingBuff;
00800     
00801     if (!reallyDredd)
00802       encodingBuff.Append(m_kImapUnDeleted);
00803 
00804     expression->GenerateEncodeStr(&encodingBuff);
00805     *ppOutEncoding = ToNewCString(encodingBuff);
00806   }
00807   
00808   delete expression;
00809   
00810   return err;
00811 }
00812 
00813 
00814 char *nsMsgSearchAdapter::TransformSpacesToStars (const char *spaceString, msg_TransformType transformType)
00815 {
00816        char *starString;
00817        
00818        if (transformType == kOverwrite)
00819        {
00820               if ((starString = nsCRT::strdup(spaceString)) != nsnull)
00821               {
00822                      char *star = starString;
00823                      while ((star = PL_strchr(star, ' ')) != nsnull)
00824                             *star = '*';
00825               }
00826        }
00827        else
00828        {
00829               int i, count;
00830 
00831               for (i = 0, count = 0; spaceString[i]; )
00832               {
00833                      if (spaceString[i++] == ' ')
00834                      {
00835                             count++;
00836                             while (spaceString[i] && spaceString[i] == ' ') i++;
00837                      }
00838               }
00839 
00840               if (transformType == kSurround)
00841                      count *= 2;
00842 
00843               if (count > 0)
00844               {
00845                      if ((starString = (char *)PR_Malloc(i + count + 1)) != nsnull)
00846                      {
00847                             int j;
00848 
00849                             for (i = 0, j = 0; spaceString[i]; )
00850                             {
00851                                    if (spaceString[i] == ' ')
00852                                    {
00853                                           starString[j++] = '*';
00854                                           starString[j++] = ' ';
00855                                           if (transformType == kSurround)
00856                                                  starString[j++] = '*';
00857 
00858                                           i++;
00859                                           while (spaceString[i] && spaceString[i] == ' ')
00860                                                  i++;
00861                                    }
00862                                    else
00863                                           starString[j++] = spaceString[i++];
00864                             }
00865                             starString[j] = 0;
00866                      }
00867               }
00868               else
00869                      starString = nsCRT::strdup(spaceString);
00870        }
00871 
00872        return starString;
00873 }
00874 
00875 //-----------------------------------------------------------------------------
00876 //------------------- Validity checking for menu items etc. -------------------
00877 //-----------------------------------------------------------------------------
00878 
00879 nsMsgSearchValidityTable::nsMsgSearchValidityTable ()
00880 {
00881        // Set everything to be unavailable and disabled
00882        for (int i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++)
00883     for (int j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++)
00884               {
00885                      SetAvailable (i, j, PR_FALSE);
00886                      SetEnabled (i, j, PR_FALSE);
00887                      SetValidButNotShown (i,j, PR_FALSE);
00888               }
00889        m_numAvailAttribs = 0;   // # of attributes marked with at least one available operator
00890   // assume default is Subject, which it is for mail and news search
00891   // it's not for LDAP, so we'll call SetDefaultAttrib()
00892   m_defaultAttrib = nsMsgSearchAttrib::Subject;
00893 }
00894 
00895 NS_IMPL_ISUPPORTS1(nsMsgSearchValidityTable, nsIMsgSearchValidityTable)
00896 
00897 
00898 nsresult
00899 nsMsgSearchValidityTable::GetNumAvailAttribs(PRInt32 *aResult)
00900 {
00901        m_numAvailAttribs = 0;
00902        for (int i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++)
00903               for (int j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++) {
00904             PRBool available;
00905             GetAvailable(i, j, &available);
00906                      if (available)
00907                      {
00908                             m_numAvailAttribs++;
00909                             break;
00910                      }
00911         }
00912        *aResult = m_numAvailAttribs;
00913     return NS_OK;
00914 }
00915 
00916 nsresult
00917 nsMsgSearchValidityTable::ValidateTerms (nsISupportsArray *searchTerms)
00918 {
00919        nsresult err = NS_OK;
00920   PRUint32 count;
00921 
00922   NS_ENSURE_ARG(searchTerms);
00923 
00924   searchTerms->Count(&count);
00925        for (PRUint32 i = 0; i < count; i++)
00926        {
00927     nsCOMPtr<nsIMsgSearchTerm> pTerm;
00928     searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
00929                              (void **)getter_AddRefs(pTerm));
00930 
00931               nsIMsgSearchTerm *iTerm = pTerm;
00932               nsMsgSearchTerm *term = NS_STATIC_CAST(nsMsgSearchTerm *, iTerm);
00933 //            XP_ASSERT(term->IsValid());
00934         PRBool enabled;
00935         PRBool available;
00936         GetEnabled(term->m_attribute, term->m_operator, &enabled);
00937         GetAvailable(term->m_attribute, term->m_operator, &available);
00938               if (!enabled || !available)
00939               {
00940             PRBool validNotShown;
00941             GetValidButNotShown(term->m_attribute, term->m_operator,
00942                                 &validNotShown);
00943             if (!validNotShown)
00944                             err = NS_MSG_ERROR_INVALID_SEARCH_SCOPE;
00945               }
00946        }
00947 
00948        return err;
00949 }
00950 
00951 nsresult
00952 nsMsgSearchValidityTable::GetAvailableAttributes(PRUint32 *length,
00953                                                  nsMsgSearchAttribValue **aResult)
00954 {
00955     // count first
00956     PRUint32 totalAttributes=0;
00957     PRInt32 i, j;
00958     for (i = 0; i< nsMsgSearchAttrib::kNumMsgSearchAttributes; i++) {
00959         for (j=0; j< nsMsgSearchOp::kNumMsgSearchOperators; j++) {
00960             if (m_table[i][j].bitAvailable) {
00961                 totalAttributes++;
00962                 break;
00963             }
00964         }
00965     }
00966 
00967     nsMsgSearchAttribValue *array = (nsMsgSearchAttribValue*)
00968         nsMemory::Alloc(sizeof(nsMsgSearchAttribValue) * totalAttributes);
00969     NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
00970     
00971     PRUint32 numStored=0;
00972     for (i = 0; i< nsMsgSearchAttrib::kNumMsgSearchAttributes; i++) {
00973         for (j=0; j< nsMsgSearchOp::kNumMsgSearchOperators; j++) {
00974             if (m_table[i][j].bitAvailable) {
00975                 array[numStored++] = i;
00976                 break;
00977             }
00978         }
00979     }
00980 
00981     NS_ASSERTION(totalAttributes == numStored, "Search Attributes not lining up");
00982     *length = totalAttributes;
00983     *aResult = array;
00984 
00985     return NS_OK;
00986 }
00987 
00988 nsresult
00989 nsMsgSearchValidityTable::GetAvailableOperators(nsMsgSearchAttribValue aAttribute,
00990                                                 PRUint32 *aLength,
00991                                                 nsMsgSearchOpValue **aResult)
00992 {
00993     nsMsgSearchAttribValue attr;
00994     if (aAttribute == nsMsgSearchAttrib::Default)
00995       attr = m_defaultAttrib;
00996     else
00997        attr = PR_MIN(aAttribute, nsMsgSearchAttrib::OtherHeader);
00998 
00999     PRUint32 totalOperators=0;
01000     PRInt32 i;
01001     for (i=0; i<nsMsgSearchOp::kNumMsgSearchOperators; i++) {
01002         if (m_table[attr][i].bitAvailable)
01003             totalOperators++;
01004     }
01005 
01006     nsMsgSearchOpValue *array = (nsMsgSearchOpValue*)
01007         nsMemory::Alloc(sizeof(nsMsgSearchOpValue) * totalOperators);
01008     NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
01009     
01010     PRUint32 numStored = 0;
01011     for (i=0; i<nsMsgSearchOp::kNumMsgSearchOperators;i++) {
01012         if (m_table[attr][i].bitAvailable)
01013             array[numStored++] = i;
01014     }
01015 
01016     NS_ASSERTION(totalOperators == numStored, "Search Operators not lining up");
01017     *aLength = totalOperators;
01018     *aResult = array;
01019     return NS_OK;
01020 }
01021 
01022 NS_IMETHODIMP
01023 nsMsgSearchValidityTable::SetDefaultAttrib(nsMsgSearchAttribValue aAttribute)
01024 {
01025   m_defaultAttrib = aAttribute;
01026   return NS_OK;
01027 }
01028 
01029 
01030 nsMsgSearchValidityManager::nsMsgSearchValidityManager ()
01031 {
01032 }
01033 
01034 
01035 nsMsgSearchValidityManager::~nsMsgSearchValidityManager ()
01036 {
01037     // tables released by nsCOMPtr
01038 }
01039 
01040 NS_IMPL_ISUPPORTS1(nsMsgSearchValidityManager, nsIMsgSearchValidityManager)
01041 
01042 //-----------------------------------------------------------------------------
01043 // Bottleneck accesses to the objects so we can allocate and initialize them
01044 // lazily. This way, there's no heap overhead for the validity tables until the
01045 // user actually searches that scope.
01046 //-----------------------------------------------------------------------------
01047 
01048 NS_IMETHODIMP nsMsgSearchValidityManager::GetTable (int whichTable, nsIMsgSearchValidityTable **ppOutTable)
01049 {
01050   NS_ENSURE_ARG_POINTER(ppOutTable);
01051   
01052   nsresult rv;
01053   *ppOutTable = nsnull;
01054   
01055   nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
01056   nsXPIDLCString customHeaders;
01057   if (NS_SUCCEEDED(rv))
01058     pref->GetCharPref(PREF_CUSTOM_HEADERS, getter_Copies(customHeaders));
01059   
01060   switch (whichTable)
01061   {
01062   case nsMsgSearchScope::offlineMail:
01063     if (!m_offlineMailTable)
01064       rv = InitOfflineMailTable ();
01065     if (m_offlineMailTable)
01066       rv = SetOtherHeadersInTable(m_offlineMailTable, customHeaders.get());
01067     *ppOutTable = m_offlineMailTable;
01068     break;
01069   case nsMsgSearchScope::offlineMailFilter:
01070     if (!m_offlineMailFilterTable)
01071       rv = InitOfflineMailFilterTable ();
01072     if (m_offlineMailFilterTable)
01073       rv = SetOtherHeadersInTable(m_offlineMailFilterTable, customHeaders.get());
01074     *ppOutTable = m_offlineMailFilterTable;
01075     break;
01076   case nsMsgSearchScope::onlineMail:
01077     if (!m_onlineMailTable)
01078       rv = InitOnlineMailTable ();
01079     if (m_onlineMailTable)
01080       rv = SetOtherHeadersInTable(m_onlineMailTable, customHeaders.get());
01081     *ppOutTable = m_onlineMailTable;
01082     break;
01083   case nsMsgSearchScope::onlineMailFilter:
01084     if (!m_onlineMailFilterTable)
01085       rv = InitOnlineMailFilterTable ();
01086     if (m_onlineMailFilterTable)
01087       rv = SetOtherHeadersInTable(m_onlineMailFilterTable, customHeaders.get());
01088     *ppOutTable = m_onlineMailFilterTable;
01089     break;
01090   case nsMsgSearchScope::news:
01091     if (!m_newsTable)
01092       rv = InitNewsTable();
01093     *ppOutTable = m_newsTable;
01094     break;
01095   case nsMsgSearchScope::newsFilter:
01096     if (!m_newsFilterTable)
01097       rv = InitNewsFilterTable();
01098     *ppOutTable = m_newsFilterTable;
01099     break;
01100   case nsMsgSearchScope::localNews:
01101     if (!m_localNewsTable)
01102       rv = InitLocalNewsTable();
01103     if (m_localNewsTable)
01104       rv = SetOtherHeadersInTable(m_localNewsTable, customHeaders.get());
01105     *ppOutTable = m_localNewsTable;
01106     break;
01107 #ifdef DOING_EXNEWSSEARCH
01108   case nsMsgSearchScope::newsEx:
01109     if (!m_newsExTable)
01110       rv = InitNewsExTable ();
01111     *ppOutTable = m_newsExTable;
01112     break;
01113 #endif
01114   case nsMsgSearchScope::LDAP:
01115     if (!m_ldapTable)
01116       rv = InitLdapTable ();
01117     *ppOutTable = m_ldapTable;
01118     break;
01119   case nsMsgSearchScope::LDAPAnd:
01120     if (!m_ldapAndTable)
01121       rv = InitLdapAndTable ();
01122     *ppOutTable = m_ldapAndTable;
01123     break;
01124   case nsMsgSearchScope::LocalAB:
01125     if (!m_localABTable)
01126       rv = InitLocalABTable ();
01127     *ppOutTable = m_localABTable;
01128     break;
01129   case nsMsgSearchScope::LocalABAnd:
01130     if (!m_localABAndTable)
01131       rv = InitLocalABAndTable ();    
01132     *ppOutTable = m_localABAndTable;
01133     break;
01134   default:                 
01135     NS_ASSERTION(PR_FALSE, "invalid table type");
01136     rv = NS_MSG_ERROR_INVALID_SEARCH_TERM;
01137   }
01138   
01139   NS_IF_ADDREF(*ppOutTable);
01140   return rv;
01141 }
01142 
01143 
01144 
01145 nsresult
01146 nsMsgSearchValidityManager::NewTable(nsIMsgSearchValidityTable **aTable)
01147 {
01148   NS_ENSURE_ARG_POINTER(aTable);
01149   *aTable = new nsMsgSearchValidityTable;
01150   if (!*aTable)
01151     return NS_ERROR_OUT_OF_MEMORY;
01152   NS_ADDREF(*aTable);
01153   return NS_OK;
01154 }
01155 
01156 nsresult 
01157 nsMsgSearchValidityManager::SetOtherHeadersInTable (nsIMsgSearchValidityTable *aTable, const char *customHeaders)
01158 {
01159   PRUint32 customHeadersLength = strlen(customHeaders);
01160   PRUint32 numHeaders=0;
01161   if (customHeadersLength)
01162   {
01163     char *headersString = nsCRT::strdup(customHeaders);
01164 
01165     nsCAutoString hdrStr;
01166     hdrStr.Adopt(headersString);
01167     hdrStr.StripWhitespace();  //remove whitespace before parsing
01168 
01169     char *newStr=nsnull;
01170     char *token = nsCRT::strtok(headersString,":", &newStr);
01171     while(token)
01172     {
01173       numHeaders++;
01174       token = nsCRT::strtok(newStr,":", &newStr);
01175     }
01176   }
01177 
01178   NS_ASSERTION(nsMsgSearchAttrib::OtherHeader + numHeaders < nsMsgSearchAttrib::kNumMsgSearchAttributes, "more headers than the table can hold");
01179 
01180   PRUint32 maxHdrs= PR_MIN(nsMsgSearchAttrib::OtherHeader + numHeaders+1, nsMsgSearchAttrib::kNumMsgSearchAttributes);
01181   for (PRUint32 i=nsMsgSearchAttrib::OtherHeader+1;i< maxHdrs;i++)
01182   {
01183     aTable->SetAvailable (i, nsMsgSearchOp::Contains, 1);   // added for arbitrary headers
01184     aTable->SetEnabled   (i, nsMsgSearchOp::Contains, 1); 
01185     aTable->SetAvailable (i, nsMsgSearchOp::DoesntContain, 1);
01186     aTable->SetEnabled   (i, nsMsgSearchOp::DoesntContain, 1);
01187     aTable->SetAvailable (i, nsMsgSearchOp::Is, 1);
01188     aTable->SetEnabled   (i, nsMsgSearchOp::Is, 1);
01189     aTable->SetAvailable (i, nsMsgSearchOp::Isnt, 1);
01190     aTable->SetEnabled   (i, nsMsgSearchOp::Isnt, 1);
01191   }
01192    //because custom headers can change; so reset the table for those which are no longer used. 
01193   for (PRUint32 j=maxHdrs; j < nsMsgSearchAttrib::kNumMsgSearchAttributes; j++) 
01194   {
01195     for (PRUint32 k=0; k < nsMsgSearchOp::kNumMsgSearchOperators; k++) 
01196     {
01197       aTable->SetAvailable(j,k,0);
01198       aTable->SetEnabled(j,k,0);
01199     }
01200   }
01201   return NS_OK;
01202 }
01203 
01204 nsresult nsMsgSearchValidityManager::EnableDirectoryAttribute(nsIMsgSearchValidityTable *table, nsMsgSearchAttribValue aSearchAttrib)
01205 {
01206         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::Contains, 1);
01207         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::Contains, 1);
01208         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::DoesntContain, 1);
01209         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::DoesntContain, 1);
01210         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::Is, 1);
01211         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::Is, 1);
01212         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::Isnt, 1);
01213         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::Isnt, 1);
01214         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::BeginsWith, 1);
01215         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::BeginsWith, 1);
01216         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::EndsWith, 1);
01217         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::EndsWith, 1);
01218         table->SetAvailable (aSearchAttrib, nsMsgSearchOp::SoundsLike, 1);
01219         table->SetEnabled   (aSearchAttrib, nsMsgSearchOp::SoundsLike, 1);
01220         return NS_OK;
01221 }
01222 
01223 nsresult nsMsgSearchValidityManager::InitLdapTable()
01224 {
01225   NS_ASSERTION(!m_ldapTable,"don't call this twice!");
01226 
01227   nsresult rv = NewTable(getter_AddRefs(m_ldapTable));
01228   NS_ENSURE_SUCCESS(rv,rv);
01229 
01230   rv = SetUpABTable(m_ldapTable, PR_TRUE);
01231   NS_ENSURE_SUCCESS(rv,rv);
01232   return rv;
01233 }
01234 
01235 nsresult nsMsgSearchValidityManager::InitLdapAndTable()
01236 {
01237   NS_ASSERTION(!m_ldapAndTable,"don't call this twice!");
01238 
01239   nsresult rv = NewTable(getter_AddRefs(m_ldapAndTable));
01240   NS_ENSURE_SUCCESS(rv,rv);
01241 
01242   rv = SetUpABTable(m_ldapAndTable, PR_FALSE);
01243   NS_ENSURE_SUCCESS(rv,rv);
01244   return rv;
01245 }
01246 
01247 nsresult nsMsgSearchValidityManager::InitLocalABTable()
01248 {
01249   NS_ASSERTION(!m_localABTable,"don't call this twice!");
01250 
01251   nsresult rv = NewTable(getter_AddRefs(m_localABTable));
01252   NS_ENSURE_SUCCESS(rv,rv);
01253 
01254   rv = SetUpABTable(m_localABTable, PR_TRUE);
01255   NS_ENSURE_SUCCESS(rv,rv);
01256   return rv;
01257 }
01258 
01259 nsresult nsMsgSearchValidityManager::InitLocalABAndTable()
01260 {
01261   NS_ASSERTION(!m_localABAndTable,"don't call this twice!");
01262 
01263   nsresult rv = NewTable(getter_AddRefs(m_localABAndTable));
01264   NS_ENSURE_SUCCESS(rv,rv);
01265 
01266   rv = SetUpABTable(m_localABAndTable, PR_FALSE);
01267   NS_ENSURE_SUCCESS(rv,rv);
01268   return rv;
01269 }
01270 
01271 nsresult
01272 nsMsgSearchValidityManager::SetUpABTable(nsIMsgSearchValidityTable *aTable, PRBool isOrTable)
01273 {
01274   nsresult rv = aTable->SetDefaultAttrib(isOrTable ? nsMsgSearchAttrib::Name : nsMsgSearchAttrib::DisplayName);
01275   NS_ENSURE_SUCCESS(rv,rv);
01276 
01277   if (isOrTable) {
01278     rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Name);
01279     NS_ENSURE_SUCCESS(rv,rv);
01280 
01281     rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::PhoneNumber);
01282     NS_ENSURE_SUCCESS(rv,rv);
01283   }
01284 
01285   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::DisplayName);
01286   NS_ENSURE_SUCCESS(rv,rv);
01287  
01288   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Email);
01289   NS_ENSURE_SUCCESS(rv,rv);
01290 
01291   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::AdditionalEmail);
01292   NS_ENSURE_SUCCESS(rv,rv);
01293 
01294   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::ScreenName);
01295   NS_ENSURE_SUCCESS(rv,rv);
01296   
01297   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Street);
01298   NS_ENSURE_SUCCESS(rv,rv);
01299 
01300   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::City);
01301   NS_ENSURE_SUCCESS(rv,rv);
01302   
01303   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Title);
01304   NS_ENSURE_SUCCESS(rv,rv);
01305 
01306   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Organization);
01307   NS_ENSURE_SUCCESS(rv,rv);
01308   
01309   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Department);
01310   NS_ENSURE_SUCCESS(rv,rv);
01311 
01312   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Nickname);
01313   NS_ENSURE_SUCCESS(rv,rv);
01314 
01315   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::WorkPhone);
01316   NS_ENSURE_SUCCESS(rv,rv);
01317 
01318   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::HomePhone);
01319   NS_ENSURE_SUCCESS(rv,rv);
01320 
01321   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Fax);
01322   NS_ENSURE_SUCCESS(rv,rv);
01323 
01324   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Pager);
01325   NS_ENSURE_SUCCESS(rv,rv);
01326 
01327   rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Mobile);
01328   NS_ENSURE_SUCCESS(rv,rv);
01329 
01330   return rv;
01331 }