Back to index

lightning-sunbird  0.9+nobinonly
nsMsgFilterList.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  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Seth Spitzer <sspitzer@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 // this file implements the nsMsgFilterList interface 
00041 
00042 #include "nsTextFormatter.h"
00043 
00044 #include "msgCore.h"
00045 #include "nsMsgFilterList.h"
00046 #include "nsMsgFilter.h"
00047 #include "nsIMsgFilterHitNotify.h"
00048 #include "nsFileStream.h"
00049 #include "nsMsgUtils.h"
00050 #include "nsMsgSearchTerm.h"
00051 #include "nsXPIDLString.h"
00052 #include "nsReadableUtils.h"
00053 #include "nsIImportService.h"
00054 #include "nsMsgBaseCID.h"
00055 #include "nsIMsgFilterService.h"
00056 #include "nsMsgSearchScopeTerm.h"
00057 #include "nsISupportsObsolete.h"
00058 #include "nsNetUtil.h"
00059 
00060 // unicode "%s" format string
00061 static const PRUnichar unicodeFormatter[] = {
00062     (PRUnichar)'%',
00063     (PRUnichar)'s',
00064     (PRUnichar)0,
00065 };
00066 
00067 
00068 nsMsgFilterList::nsMsgFilterList() :
00069     m_fileVersion(0)
00070 {
00071   // I don't know how we're going to report this error if we failed to create the isupports array...
00072 #ifdef DEBUG
00073   nsresult rv =
00074 #endif
00075     NS_NewISupportsArray(getter_AddRefs(m_filters));
00076   NS_ASSERTION(NS_SUCCEEDED(rv), "Fixme bug 180312: NS_NewISupportsArray() failed");
00077 
00078   m_loggingEnabled = PR_FALSE;
00079   m_startWritingToBuffer = PR_FALSE; 
00080   m_temporaryList = PR_FALSE;
00081   m_curFilter = nsnull;
00082   m_arbitraryHeaders.SetLength(0);
00083 }
00084 
00085 NS_IMPL_ADDREF(nsMsgFilterList)
00086 NS_IMPL_RELEASE(nsMsgFilterList)
00087 NS_IMPL_QUERY_INTERFACE1(nsMsgFilterList, nsIMsgFilterList)
00088 
00089 NS_IMETHODIMP nsMsgFilterList::CreateFilter(const PRUnichar *name,class nsIMsgFilter **aFilter)
00090 {
00091   NS_ENSURE_ARG_POINTER(aFilter);
00092 
00093   nsMsgFilter *filter = new nsMsgFilter;
00094   NS_ENSURE_TRUE(filter, NS_ERROR_OUT_OF_MEMORY);
00095     
00096   NS_ADDREF(*aFilter = filter);
00097     
00098   filter->SetFilterName(name);
00099   filter->SetFilterList(this);
00100     
00101   return NS_OK;
00102 }
00103 
00104 NS_IMPL_GETSET(nsMsgFilterList, LoggingEnabled, PRBool, m_loggingEnabled)
00105 
00106 NS_IMETHODIMP nsMsgFilterList::GetFolder(nsIMsgFolder **aFolder)
00107 {
00108   NS_ENSURE_ARG(aFolder);
00109   *aFolder = m_folder;
00110   NS_IF_ADDREF(*aFolder);
00111   return NS_OK;
00112 }
00113 
00114 NS_IMETHODIMP nsMsgFilterList::SetFolder(nsIMsgFolder *aFolder)
00115 {
00116   m_folder = aFolder;
00117   return NS_OK;
00118 }
00119 
00120 NS_IMETHODIMP nsMsgFilterList::SaveToFile(nsIOFileStream *stream)
00121 {
00122        if (!stream)
00123               return NS_ERROR_NULL_POINTER;
00124        return SaveTextFilters(stream);
00125 }
00126 
00127 NS_IMETHODIMP nsMsgFilterList::EnsureLogFile()
00128 {
00129   nsCOMPtr <nsIFileSpec> file;
00130   nsresult rv = GetLogFileSpec(getter_AddRefs(file));
00131   NS_ENSURE_SUCCESS(rv,rv);
00132 
00133   PRBool exists;
00134   rv = file->Exists(&exists);
00135   if (NS_SUCCEEDED(rv) && !exists) {
00136     rv = file->Touch();
00137     NS_ENSURE_SUCCESS(rv,rv);
00138   }
00139   return NS_OK;
00140 }
00141 
00142 nsresult nsMsgFilterList::TruncateLog()
00143 {
00144   // this will flush and close the steam
00145   nsresult rv = SetLogStream(nsnull);
00146   NS_ENSURE_SUCCESS(rv,rv);
00147 
00148   nsCOMPtr <nsIFileSpec> file;
00149   rv = GetLogFileSpec(getter_AddRefs(file));
00150   NS_ENSURE_SUCCESS(rv,rv);
00151 
00152   rv = file->Truncate(0);
00153   NS_ENSURE_SUCCESS(rv,rv);
00154   return rv;
00155 }
00156 
00157 NS_IMETHODIMP nsMsgFilterList::ClearLog()
00158 {
00159   PRBool loggingEnabled = m_loggingEnabled;
00160   
00161   // disable logging while clearing
00162   m_loggingEnabled = PR_FALSE;
00163 
00164 #ifdef DEBUG
00165   nsresult rv =
00166 #endif
00167     TruncateLog();
00168   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to truncate filter log");
00169 
00170   m_loggingEnabled = loggingEnabled;
00171 
00172   return NS_OK;
00173 }
00174 
00175 nsresult 
00176 nsMsgFilterList::GetLogFileSpec(nsIFileSpec **aFileSpec)
00177 {
00178   NS_ENSURE_ARG_POINTER(aFileSpec);
00179 
00180   // XXX todo
00181   // the path to the log file won't change
00182   // should we cache it?
00183   nsCOMPtr <nsIMsgFolder> folder;
00184   nsresult rv = GetFolder(getter_AddRefs(folder));
00185   NS_ENSURE_SUCCESS(rv,rv);
00186 
00187   nsCOMPtr <nsIMsgIncomingServer> server;
00188   rv = folder->GetServer(getter_AddRefs(server));
00189   NS_ENSURE_SUCCESS(rv,rv);
00190 
00191   nsXPIDLCString type;
00192   rv = server->GetType(getter_Copies(type));
00193   NS_ENSURE_SUCCESS(rv,rv);
00194 
00195   PRBool isServer = PR_FALSE;
00196   rv = folder->GetIsServer(&isServer);
00197   NS_ENSURE_SUCCESS(rv,rv);
00198 
00199   // for news folders (not servers), the filter file is
00200   // mcom.test.dat
00201   // where the summary file is 
00202   // mcom.test.msf
00203   // since the log is an html file we make it
00204   // mcom.test.htm
00205   if (type.Equals("nntp") && !isServer) 
00206   {
00207     nsCOMPtr<nsIFileSpec> thisFolder;
00208     rv = m_folder->GetPath(getter_AddRefs(thisFolder));
00209     NS_ENSURE_SUCCESS(rv, rv);
00210 
00211     nsCOMPtr <nsIFileSpec> filterLogFile = do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv);
00212     NS_ENSURE_SUCCESS(rv, rv);
00213     
00214     rv = filterLogFile->FromFileSpec(thisFolder);
00215     NS_ENSURE_SUCCESS(rv, rv);
00216     
00217     // NOTE:
00218     // we don't we need to call NS_MsgHashIfNecessary()
00219     // it's already been hashed, if necessary
00220     nsXPIDLCString filterLogName;
00221     rv = filterLogFile->GetLeafName(getter_Copies(filterLogName));
00222     NS_ENSURE_SUCCESS(rv,rv);
00223     
00224     filterLogName.Append(".htm");
00225     
00226     rv = filterLogFile->SetLeafName(filterLogName.get());
00227     NS_ENSURE_SUCCESS(rv,rv);
00228 
00229     NS_IF_ADDREF(*aFileSpec = filterLogFile);
00230   }
00231   else {
00232     rv = server->GetLocalPath(aFileSpec);
00233     NS_ENSURE_SUCCESS(rv,rv);
00234     
00235     rv = (*aFileSpec)->AppendRelativeUnixPath("filterlog.html");
00236     NS_ENSURE_SUCCESS(rv,rv);
00237   }
00238   return NS_OK;
00239 }
00240 
00241 NS_IMETHODIMP
00242 nsMsgFilterList::GetLogURL(char **aLogURL)
00243 {
00244   NS_ENSURE_ARG_POINTER(aLogURL);
00245 
00246   nsCOMPtr <nsIFileSpec> file;
00247   nsresult rv = GetLogFileSpec(getter_AddRefs(file));
00248   NS_ENSURE_SUCCESS(rv,rv);
00249   
00250   rv = file->GetURLString(aLogURL);
00251   NS_ENSURE_SUCCESS(rv,rv);
00252   return NS_OK;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsMsgFilterList::SetLogStream(nsIOutputStream *aLogStream)
00257 {
00258   // if there is a log stream already, close it
00259   if (m_logStream) {
00260     // will flush
00261     nsresult rv = m_logStream->Close();
00262     NS_ENSURE_SUCCESS(rv,rv);
00263   }
00264 
00265   m_logStream = aLogStream;
00266   return NS_OK;
00267 }
00268 
00269 #define LOG_HEADER "<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head>"
00270 #define LOG_HEADER_LEN (strlen(LOG_HEADER))
00271 
00272 NS_IMETHODIMP
00273 nsMsgFilterList::GetLogStream(nsIOutputStream **aLogStream)
00274 {
00275   NS_ENSURE_ARG_POINTER(aLogStream);
00276 
00277   nsresult rv;
00278 
00279   if (!m_logStream) {
00280     nsCOMPtr <nsIFileSpec> file;
00281     rv = GetLogFileSpec(getter_AddRefs(file));
00282     NS_ENSURE_SUCCESS(rv,rv);
00283 
00284     nsXPIDLCString nativePath;
00285     rv = file->GetNativePath(getter_Copies(nativePath));
00286     NS_ENSURE_SUCCESS(rv,rv);
00287 
00288     nsCOMPtr <nsILocalFile> logFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
00289     NS_ENSURE_SUCCESS(rv,rv);
00290 
00291     rv = logFile->InitWithNativePath(nsDependentCString(nativePath));
00292     NS_ENSURE_SUCCESS(rv,rv);
00293 
00294     // append to the end of the log file
00295     rv = NS_NewLocalFileOutputStream(getter_AddRefs(m_logStream),
00296                                    logFile,
00297                                    PR_CREATE_FILE | PR_WRONLY | PR_APPEND,
00298                                    0600);
00299     NS_ENSURE_SUCCESS(rv,rv);
00300 
00301     if (!m_logStream)
00302       return NS_ERROR_FAILURE;
00303 
00304     PRInt64 fileSize;
00305     rv = logFile->GetFileSize(&fileSize);
00306     NS_ENSURE_SUCCESS(rv, rv);
00307     
00308     PRUint32 fileLen;;
00309     LL_L2UI(fileLen, fileSize);
00310     // write the header at the start
00311     if (fileLen == 0)
00312     {
00313       PRUint32 writeCount;
00314       
00315       rv = m_logStream->Write(LOG_HEADER, LOG_HEADER_LEN, &writeCount);
00316       NS_ENSURE_SUCCESS(rv, rv);
00317       NS_ASSERTION(writeCount == LOG_HEADER_LEN, "failed to write out log header");
00318     }
00319   }
00320  
00321   NS_ADDREF(*aLogStream = m_logStream);
00322   return NS_OK;
00323 }
00324 
00325 NS_IMETHODIMP
00326 nsMsgFilterList::ApplyFiltersToHdr(nsMsgFilterTypeType filterType,
00327                                    nsIMsgDBHdr *msgHdr,
00328                                    nsIMsgFolder *folder,
00329                                    nsIMsgDatabase *db, 
00330                                    const char *headers,
00331                                    PRUint32 headersSize,
00332                                    nsIMsgFilterHitNotify *listener,
00333                                    nsIMsgWindow *msgWindow,
00334                                    nsILocalFile *aMessageFile)
00335 {
00336   nsCOMPtr <nsIMsgFilter>   filter;
00337   PRUint32           filterCount = 0;
00338   nsresult           rv = GetFilterCount(&filterCount);
00339   NS_ENSURE_SUCCESS(rv,rv);
00340   
00341   nsMsgSearchScopeTerm* scope = new nsMsgSearchScopeTerm(nsnull, nsMsgSearchScope::offlineMail, folder);
00342   scope->AddRef();
00343   if (!scope) return NS_ERROR_OUT_OF_MEMORY;
00344   if (aMessageFile)
00345     scope->m_localFile = aMessageFile;
00346   
00347   for (PRUint32 filterIndex = 0; filterIndex < filterCount; filterIndex++)
00348   {
00349     if (NS_SUCCEEDED(GetFilterAt(filterIndex, getter_AddRefs(filter))))
00350     {
00351       PRBool isEnabled;
00352       nsMsgFilterTypeType curFilterType;
00353       
00354       filter->GetEnabled(&isEnabled);
00355       if (!isEnabled)
00356         continue;
00357       
00358       filter->GetFilterType(&curFilterType);  
00359       if (curFilterType & filterType)
00360       {
00361         nsresult matchTermStatus = NS_OK;
00362         PRBool result;
00363         
00364         filter->SetScope(scope);
00365         matchTermStatus = filter->MatchHdr(msgHdr, folder, db, headers, headersSize, &result);
00366         filter->SetScope(nsnull);
00367         if (NS_SUCCEEDED(matchTermStatus) && result && listener)
00368         {
00369           PRBool applyMore = PR_TRUE;
00370           
00371           rv = listener->ApplyFilterHit(filter, msgWindow, &applyMore);
00372           if (NS_FAILED(rv) || !applyMore)
00373             break;
00374         }
00375       }
00376     }
00377   }
00378   scope->Release();
00379   return rv;
00380 }
00381 
00382 NS_IMETHODIMP
00383 nsMsgFilterList::SetDefaultFile(nsIFileSpec *aFileSpec)
00384 {
00385     nsresult rv;
00386     m_defaultFile = do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv);
00387     NS_ENSURE_SUCCESS(rv, rv);
00388     
00389     rv = m_defaultFile->FromFileSpec(aFileSpec);
00390     NS_ENSURE_SUCCESS(rv, rv);
00391     return NS_OK;
00392 }
00393 
00394 NS_IMETHODIMP
00395 nsMsgFilterList::GetDefaultFile(nsIFileSpec **aResult)
00396 {
00397     NS_ENSURE_ARG_POINTER(aResult);
00398 
00399     nsresult rv;
00400     nsCOMPtr<nsIFileSpec> fileSpec =
00401         do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv);
00402     NS_ENSURE_SUCCESS(rv, rv);
00403     
00404     rv = fileSpec->FromFileSpec(m_defaultFile);
00405     NS_ENSURE_SUCCESS(rv, rv);
00406     
00407     *aResult = fileSpec;
00408     NS_ADDREF(*aResult);
00409 
00410     return NS_OK;
00411 }
00412 
00413 NS_IMETHODIMP
00414 nsMsgFilterList::SaveToDefaultFile()
00415 {
00416     nsresult rv;
00417     nsCOMPtr<nsIMsgFilterService> filterService =
00418         do_GetService(NS_MSGFILTERSERVICE_CONTRACTID, &rv);
00419     NS_ENSURE_SUCCESS(rv, rv);
00420 
00421     return filterService->SaveFilterList(this, m_defaultFile);
00422 }
00423 
00424 typedef struct
00425 {
00426   nsMsgFilterFileAttribValue       attrib;
00427   const char                *attribName;
00428 } FilterFileAttribEntry;
00429 
00430 static FilterFileAttribEntry FilterFileAttribTable[] =
00431 {
00432        {nsIMsgFilterList::attribNone,                   ""},
00433        {nsIMsgFilterList::attribVersion,         "version"},
00434        {nsIMsgFilterList::attribLogging,         "logging"},
00435        {nsIMsgFilterList::attribName,                   "name"},
00436        {nsIMsgFilterList::attribEnabled,         "enabled"},
00437        {nsIMsgFilterList::attribDescription,     "description"},
00438        {nsIMsgFilterList::attribType,                   "type"},
00439        {nsIMsgFilterList::attribScriptFile,      "scriptName"},
00440        {nsIMsgFilterList::attribAction,          "action"},
00441        {nsIMsgFilterList::attribActionValue,     "actionValue"},
00442        {nsIMsgFilterList::attribCondition,              "condition"}
00443 };
00444 
00445 // If we want to buffer file IO, wrap it in here.
00446 char nsMsgFilterList::ReadChar(nsIOFileStream *aStream)
00447 {
00448   char newChar;
00449   *aStream >> newChar;
00450   if (aStream->eof())
00451     return -1;
00452   else
00453   {
00454     if (m_startWritingToBuffer)
00455       m_unparsedFilterBuffer.Append(newChar);
00456     return newChar;
00457   }
00458 }
00459 
00460 char nsMsgFilterList::SkipWhitespace(nsIOFileStream *aStream)
00461 {
00462   char ch;
00463   do
00464   {
00465     ch = ReadChar(aStream);
00466   } while (nsCRT::IsAsciiSpace((PRUnichar)ch));
00467   return ch;
00468 }
00469 
00470 PRBool nsMsgFilterList::StrToBool(nsCString &str)
00471 {
00472   return str.Equals("yes") ;
00473 }
00474 
00475 char nsMsgFilterList::LoadAttrib(nsMsgFilterFileAttribValue &attrib, nsIOFileStream *aStream)
00476 {
00477   char attribStr[100];
00478   char curChar;
00479   attrib = nsIMsgFilterList::attribNone;
00480   
00481   curChar = SkipWhitespace(aStream);
00482   int i;
00483   for (i = 0; i + 1 < (int)(sizeof(attribStr)); )
00484   {
00485     if (curChar == (char) -1 || nsCRT::IsAsciiSpace((PRUnichar)curChar) || curChar == '=')
00486       break;
00487     attribStr[i++] = curChar;
00488     curChar = ReadChar(aStream);
00489   }
00490   attribStr[i] = '\0';
00491   for (int tableIndex = 0; tableIndex < (int)(sizeof(FilterFileAttribTable) / sizeof(FilterFileAttribTable[0])); tableIndex++)
00492   {
00493     if (!PL_strcasecmp(attribStr, FilterFileAttribTable[tableIndex].attribName))
00494     {
00495       attrib = FilterFileAttribTable[tableIndex].attrib;
00496       break;
00497     }
00498   }
00499   return curChar;
00500 }
00501 
00502 const char *nsMsgFilterList::GetStringForAttrib(nsMsgFilterFileAttribValue attrib)
00503 {
00504   for (int tableIndex = 0; tableIndex < (int)(sizeof(FilterFileAttribTable) / sizeof(FilterFileAttribTable[0])); tableIndex++)
00505   {
00506     if (attrib == FilterFileAttribTable[tableIndex].attrib)
00507       return FilterFileAttribTable[tableIndex].attribName;
00508   }
00509   return nsnull;
00510 }
00511 
00512 nsresult nsMsgFilterList::LoadValue(nsCString &value, nsIOFileStream *aStream)
00513 {
00514   nsCAutoString      valueStr;
00515   char curChar;
00516   value = "";
00517   curChar = SkipWhitespace(aStream);
00518   if (curChar != '"')
00519   {
00520     NS_ASSERTION(PR_FALSE, "expecting quote as start of value");
00521     return NS_MSG_FILTER_PARSE_ERROR;
00522   }
00523   curChar = ReadChar(aStream);
00524   do
00525   {
00526     if (curChar == '\\')
00527     {
00528       char nextChar = ReadChar(aStream);
00529       if (nextChar == '"')
00530         curChar = '"';
00531       else if (nextChar == '\\')   // replace "\\" with "\"
00532       {
00533         valueStr += curChar;
00534         curChar = ReadChar(aStream);
00535       }
00536       else
00537       {
00538         valueStr += curChar;
00539         curChar = nextChar;
00540       }
00541     }
00542     else
00543     {
00544       if (curChar == (char) -1 || curChar == '"' || curChar == '\n' || curChar == '\r')
00545       {
00546         value += valueStr;
00547         break;
00548       }
00549     }
00550     valueStr += curChar;
00551     curChar = ReadChar(aStream);
00552   }
00553   while (!aStream->eof());
00554   return NS_OK;
00555 }
00556 
00557 nsresult nsMsgFilterList::LoadTextFilters(nsIOFileStream *aStream)
00558 {
00559   nsresult    err = NS_OK;
00560   nsMsgFilterFileAttribValue attrib;
00561   nsCOMPtr<nsIImportService> impSvc;
00562   nsCOMPtr<nsIMsgRuleAction> currentFilterAction;
00563   // We'd really like to move lot's of these into the objects that they refer to.
00564   aStream->seek(PR_SEEK_SET, 0);
00565   do 
00566   {
00567     nsCAutoString    value;
00568     PRInt32 intToStringResult;
00569     
00570     char curChar;
00571     curChar = LoadAttrib(attrib, aStream);
00572     if (curChar == (char) -1)  //reached eof
00573       break;
00574     err = LoadValue(value, aStream);
00575     if (err != NS_OK)
00576       break;
00577     switch(attrib)
00578     {
00579     case nsIMsgFilterList::attribNone:
00580       m_curFilter->SetUnparseable(PR_TRUE);
00581       break;
00582     case nsIMsgFilterList::attribVersion:
00583       m_fileVersion = value.ToInteger(&intToStringResult, 10);
00584       if (intToStringResult != 0)
00585       {
00586         attrib = nsIMsgFilterList::attribNone;
00587         NS_ASSERTION(PR_FALSE, "error parsing filter file version");
00588       }
00589       if (m_fileVersion == k45Version)
00590       {
00591         impSvc = do_GetService(NS_IMPORTSERVICE_CONTRACTID);
00592         NS_ASSERTION(impSvc, "cannot get importService");
00593       }
00594       break;
00595     case nsIMsgFilterList::attribLogging:
00596       m_loggingEnabled = StrToBool(value);
00597       m_unparsedFilterBuffer.Truncate(); //we are going to buffer each filter as we read them, make sure no garbage is there
00598       m_startWritingToBuffer = PR_TRUE; //filters begin now
00599       break;
00600     case nsIMsgFilterList::attribName:  //every filter starts w/ a name
00601       {
00602         if (m_curFilter)
00603         {
00604           PRInt32 nextFilterStartPos = m_unparsedFilterBuffer.RFind("name");
00605           nsCAutoString nextFilterPart;
00606           nextFilterPart = Substring(m_unparsedFilterBuffer, nextFilterStartPos, m_unparsedFilterBuffer.Length());
00607           m_unparsedFilterBuffer.Truncate(nextFilterStartPos);
00608           
00609           PRBool unparseableFilter;
00610           m_curFilter->GetUnparseable(&unparseableFilter);
00611           if (unparseableFilter)
00612           {
00613             m_curFilter->SetUnparsedBuffer(m_unparsedFilterBuffer.get());
00614             m_curFilter->SetEnabled(PR_FALSE); //disable the filter because we don't know how to apply it
00615           }
00616           m_unparsedFilterBuffer = nextFilterPart;
00617         }
00618         nsMsgFilter *filter = new nsMsgFilter;
00619         if (filter == nsnull)
00620         {
00621           err = NS_ERROR_OUT_OF_MEMORY;
00622           break;
00623         }
00624         filter->SetFilterList(NS_STATIC_CAST(nsIMsgFilterList*,this));
00625         if (m_fileVersion == k45Version && impSvc)
00626         {
00627           nsAutoString unicodeStr;
00628           impSvc->SystemStringToUnicode(value.get(), unicodeStr);
00629           filter->SetFilterName(unicodeStr.get());
00630         }
00631         else
00632         {  
00633           PRUnichar *unicodeString =
00634             nsTextFormatter::smprintf(unicodeFormatter, value.get());
00635           filter->SetFilterName(unicodeString);
00636           nsTextFormatter::smprintf_free(unicodeString);
00637         }
00638         m_curFilter = filter;
00639         m_filters->AppendElement(NS_STATIC_CAST(nsISupports*,filter));
00640       }
00641       break;
00642     case nsIMsgFilterList::attribEnabled:
00643       if (m_curFilter)
00644         m_curFilter->SetEnabled(StrToBool(value));
00645       break;
00646     case nsIMsgFilterList::attribDescription:
00647       if (m_curFilter)
00648         m_curFilter->SetFilterDesc(value.get());
00649       break;
00650     case nsIMsgFilterList::attribType:
00651       if (m_curFilter)
00652         m_curFilter->SetType((nsMsgFilterTypeType) value.ToInteger(&intToStringResult, 10));
00653       break;
00654     case nsIMsgFilterList::attribScriptFile:
00655       if (m_curFilter)
00656         m_curFilter->SetFilterScript(&value);
00657       break;
00658     case nsIMsgFilterList::attribAction:
00659       if (m_curFilter)
00660       {
00661         nsMsgRuleActionType actionType = nsMsgFilter::GetActionForFilingStr(value);
00662         if (actionType == nsMsgFilterAction::None)
00663           m_curFilter->SetUnparseable(PR_TRUE);
00664         else
00665         {
00666           err = m_curFilter->CreateAction(getter_AddRefs(currentFilterAction));
00667           NS_ENSURE_SUCCESS(err, err);
00668           currentFilterAction->SetType(actionType);
00669           m_curFilter->AppendAction(currentFilterAction);
00670         }
00671       }
00672       break;
00673     case nsIMsgFilterList::attribActionValue:
00674       if (m_curFilter && currentFilterAction)
00675       {
00676         nsMsgRuleActionType type;
00677         currentFilterAction->GetType(&type);
00678         if (type == nsMsgFilterAction::MoveToFolder ||
00679               type == nsMsgFilterAction::CopyToFolder)
00680           err = m_curFilter->ConvertMoveOrCopyToFolderValue(currentFilterAction, value);
00681         else if (type == nsMsgFilterAction::ChangePriority)
00682         {
00683           nsMsgPriorityValue outPriority;
00684           nsresult res = NS_MsgGetPriorityFromString(value.get(), outPriority);
00685           if (NS_SUCCEEDED(res))
00686             currentFilterAction->SetPriority(outPriority);
00687           else
00688             NS_ASSERTION(PR_FALSE, "invalid priority in filter file");
00689         }
00690         else if (type == nsMsgFilterAction::Label)
00691         {
00692           // upgrade label to corresponding tag/keyword
00693           PRInt32 res;
00694           PRInt32 labelInt = value.ToInteger(&res, 10);
00695           if (res == 0)
00696           {
00697             nsCAutoString keyword("$label");
00698             keyword.Append('0' + labelInt);
00699             currentFilterAction->SetType(nsMsgFilterAction::AddTag);
00700             currentFilterAction->SetStrValue(keyword.get());
00701           }
00702         }
00703         else if (type == nsMsgFilterAction::JunkScore)
00704         {
00705           PRInt32 res;
00706           PRInt32 junkScore = value.ToInteger(&res, 10);
00707           if (!res)
00708             currentFilterAction->SetJunkScore(junkScore);
00709         }
00710         else if (type == nsMsgFilterAction::Forward || type == nsMsgFilterAction::Reply
00711           || type == nsMsgFilterAction::AddTag)
00712         {
00713           currentFilterAction->SetStrValue(value.get());
00714         }
00715       }
00716       break;
00717     case nsIMsgFilterList::attribCondition:
00718       if (m_curFilter)
00719       {
00720         if ( m_fileVersion == k45Version && impSvc)
00721         {
00722           nsAutoString unicodeStr;
00723           impSvc->SystemStringToUnicode(value.get(), unicodeStr);
00724           char *utf8 = ToNewUTF8String(unicodeStr);
00725           value.Assign(utf8);
00726           nsMemory::Free(utf8);
00727         }
00728         err = ParseCondition(m_curFilter, value.get());
00729         if (err == NS_ERROR_INVALID_ARG)
00730           err = m_curFilter->SetUnparseable(PR_TRUE);
00731         NS_ENSURE_SUCCESS(err, err);
00732       }
00733       break;
00734     }
00735   } while (!aStream->eof());
00736   
00737   if (m_curFilter)
00738   {
00739     PRBool unparseableFilter;
00740     m_curFilter->GetUnparseable(&unparseableFilter);
00741     if (unparseableFilter)
00742     {
00743       m_curFilter->SetUnparsedBuffer(m_unparsedFilterBuffer.get());
00744       m_curFilter->SetEnabled(PR_FALSE);  //disable the filter because we don't know how to apply it
00745     }
00746   }
00747   
00748   return err;
00749 }
00750 
00751 // parse condition like "(subject, contains, fred) AND (body, isn't, "foo)")"
00752 // values with close parens will be quoted.
00753 // what about values with close parens and quotes? e.g., (body, isn't, "foo")")
00754 // I guess interior quotes will need to be escaped - ("foo\")")
00755 // which will get written out as (\"foo\\")\") and read in as ("foo\")"
00756 // ALL means match all messages.
00757 NS_IMETHODIMP nsMsgFilterList::ParseCondition(nsIMsgFilter *aFilter, const char *aCondition)
00758 {
00759   PRBool      done = PR_FALSE;
00760   nsresult    err = NS_OK;
00761   const char *curPtr = aCondition;
00762   if (!strcmp(aCondition, "ALL"))
00763   {
00764     nsMsgSearchTerm *newTerm = new nsMsgSearchTerm;
00765 
00766     if (newTerm) 
00767     {
00768       newTerm->m_matchAll = PR_TRUE;
00769       aFilter->AppendTerm(newTerm);
00770     }
00771     return (newTerm) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00772   }
00773 
00774   while (!done)
00775   {
00776     // insert code to save the boolean operator if there is one for this search term....
00777     const char *openParen = PL_strchr(curPtr, '(');
00778     const char *orTermPos = PL_strchr(curPtr, 'O');            // determine if an "OR" appears b4 the openParen...
00779     PRBool ANDTerm = PR_TRUE;
00780     if (orTermPos && orTermPos < openParen) // make sure OR term falls before the '('
00781       ANDTerm = PR_FALSE;
00782     
00783     char *termDup = nsnull;
00784     if (openParen)
00785     {
00786       PRBool foundEndTerm = PR_FALSE;
00787       PRBool inQuote = PR_FALSE;
00788       for (curPtr = openParen +1; *curPtr; curPtr++)
00789       {
00790         if (*curPtr == '\\' && *(curPtr + 1) == '"')
00791           curPtr++;
00792         else if (*curPtr == ')' && !inQuote)
00793         {
00794           foundEndTerm = PR_TRUE;
00795           break;
00796         }
00797         else if (*curPtr == '"')
00798           inQuote = !inQuote;
00799       }
00800       if (foundEndTerm)
00801       {
00802         int termLen = curPtr - openParen - 1;
00803         termDup = (char *) PR_Malloc(termLen + 1);
00804         if (termDup)
00805         {
00806           PL_strncpy(termDup, openParen + 1, termLen + 1);
00807           termDup[termLen] = '\0';
00808         }
00809         else
00810         {
00811           err = NS_ERROR_OUT_OF_MEMORY;
00812           break;
00813         }
00814       }
00815     }
00816     else
00817       break;
00818     if (termDup)
00819     {
00820       nsMsgSearchTerm       *newTerm = new nsMsgSearchTerm;
00821       
00822       if (newTerm) 
00823       {
00824         /* Invert nsMsgSearchTerm::EscapeQuotesInStr() */
00825         for (char *to = termDup, *from = termDup;;)
00826         {
00827           if (*from == '\\' && from[1] == '"') from++;
00828           if (!(*to++ = *from++)) break;
00829         }
00830         newTerm->m_booleanOp = (ANDTerm) ? nsMsgSearchBooleanOp::BooleanAND
00831                                          : nsMsgSearchBooleanOp::BooleanOR;
00832 
00833         err = newTerm->DeStreamNew(termDup, PL_strlen(termDup));
00834         NS_ENSURE_SUCCESS(err, err);
00835         aFilter->AppendTerm(newTerm);
00836       }
00837       PR_FREEIF(termDup);
00838     }
00839     else
00840       break;
00841   }
00842   return err;
00843 }
00844 
00845 nsresult nsMsgFilterList::WriteIntAttr(nsMsgFilterFileAttribValue attrib, int value, nsIOFileStream *aStream)
00846 {
00847        const char *attribStr = GetStringForAttrib(attrib);
00848        if (attribStr)
00849        {
00850               *aStream << attribStr;
00851               *aStream << "=\"";
00852               *aStream << value;
00853               *aStream << "\"" MSG_LINEBREAK;
00854        }
00855 //            XP_FilePrintf(fid, "%s=\"%d\"%s", attribStr, value, LINEBREAK);
00856        return NS_OK;
00857 }
00858 
00859 nsresult
00860 nsMsgFilterList::WriteStrAttr(nsMsgFilterFileAttribValue attrib,
00861                               const char *str, nsIOFileStream *aStream)
00862 {
00863        if (str && str[0] && aStream) // only proceed if we actually have a string to write out. 
00864        {
00865               char *escapedStr = nsnull;
00866               if (PL_strchr(str, '"'))
00867                      escapedStr = nsMsgSearchTerm::EscapeQuotesInStr(str);
00868 
00869               const char *attribStr = GetStringForAttrib(attrib);
00870               if (attribStr)
00871               {
00872                      *aStream << attribStr;
00873                      *aStream << "=\"";
00874                      *aStream << ((escapedStr) ? escapedStr : (const char *) str);
00875                      *aStream << "\"" MSG_LINEBREAK;
00876 //                   XP_FilePrintf(fid, "%s=\"%s\"%s", attribStr, (escapedStr) ? escapedStr : str, LINEBREAK);
00877               }
00878               PR_FREEIF(escapedStr);
00879        }
00880        return NS_OK;
00881 }
00882 
00883 nsresult nsMsgFilterList::WriteBoolAttr(nsMsgFilterFileAttribValue attrib, PRBool boolVal, nsIOFileStream *aStream)
00884 {
00885        return WriteStrAttr(attrib, (boolVal) ? "yes" : "no", aStream);
00886 }
00887 
00888 nsresult
00889 nsMsgFilterList::WriteWstrAttr(nsMsgFilterFileAttribValue attrib,
00890                                const PRUnichar *aFilterName, nsIOFileStream *aStream)
00891 {
00892     WriteStrAttr(attrib, NS_ConvertUCS2toUTF8(aFilterName).get(), aStream);
00893     return NS_OK;
00894 }
00895 
00896 nsresult nsMsgFilterList::SaveTextFilters(nsIOFileStream *aStream)
00897 {
00898        nsresult      err = NS_OK;
00899        const char *attribStr;
00900        PRUint32                    filterCount;
00901        m_filters->Count(&filterCount);
00902 
00903        attribStr = GetStringForAttrib(nsIMsgFilterList::attribVersion);
00904        err = WriteIntAttr(nsIMsgFilterList::attribVersion, kFileVersion, aStream);
00905        err = WriteBoolAttr(nsIMsgFilterList::attribLogging, m_loggingEnabled, aStream);
00906        for (PRUint32 i = 0; i < filterCount; i ++)
00907        {
00908               nsMsgFilter *filter;
00909               if (GetMsgFilterAt(i, &filter) == NS_OK && filter != nsnull)
00910               {
00911                      filter->SetFilterList(this);
00912       
00913       // if the filter is temporary, don't write it to disk
00914       PRBool isTemporary;
00915       err = filter->GetTemporary(&isTemporary);
00916       if (NS_SUCCEEDED(err) && !isTemporary) {
00917         if ((err = filter->SaveToTextFile(aStream)) != NS_OK)
00918                               break;
00919       }
00920 
00921                      NS_RELEASE(filter);
00922               }
00923               else
00924                      break;
00925        }
00926   if (NS_SUCCEEDED(err))
00927     m_arbitraryHeaders.SetLength(0);
00928        return err;
00929 }
00930 
00931 nsMsgFilterList::~nsMsgFilterList()
00932 {
00933        // filters should be released for free, because only isupports array
00934        // is holding onto them, right?
00935 //     PRUint32                    filterCount;
00936 //     m_filters->Count(&filterCount);
00937 //     for (PRUint32 i = 0; i < filterCount; i++)
00938 //     {
00939 //            nsIMsgFilter *filter;
00940 //            if (GetFilterAt(i, &filter) == NS_OK)
00941 //                   NS_RELEASE(filter);
00942 //     }
00943 }
00944 
00945 nsresult nsMsgFilterList::Close()
00946 {
00947        return NS_ERROR_NOT_IMPLEMENTED;
00948 }
00949 
00950 nsresult nsMsgFilterList::GetFilterCount(PRUint32 *pCount)
00951 {
00952        return m_filters->Count(pCount);
00953 }
00954 
00955 nsresult nsMsgFilterList::GetMsgFilterAt(PRUint32 filterIndex, nsMsgFilter **filter)
00956 {
00957        PRUint32                    filterCount;
00958        m_filters->Count(&filterCount);
00959        if (! (filterCount >= filterIndex))
00960               return NS_ERROR_INVALID_ARG;
00961        if (filter == nsnull)
00962               return NS_ERROR_NULL_POINTER;
00963        *filter = (nsMsgFilter *) m_filters->ElementAt(filterIndex);
00964        return NS_OK;
00965 }
00966 
00967 nsresult nsMsgFilterList::GetFilterAt(PRUint32 filterIndex, nsIMsgFilter **filter)
00968 {
00969     NS_ENSURE_ARG_POINTER(filter);
00970     
00971        PRUint32                    filterCount;
00972        m_filters->Count(&filterCount);
00973     NS_ENSURE_ARG(filterCount >= filterIndex);
00974 
00975        return m_filters->QueryElementAt(filterIndex, NS_GET_IID(nsIMsgFilter),
00976                                      (void **)filter);
00977 }
00978 
00979 nsresult
00980 nsMsgFilterList::GetFilterNamed(const PRUnichar *aName, nsIMsgFilter **aResult)
00981 {
00982     nsresult rv;
00983     NS_ENSURE_ARG_POINTER(aName);
00984     NS_ENSURE_ARG_POINTER(aResult);
00985     PRUint32 count=0;
00986     m_filters->Count(&count);
00987 
00988     *aResult = nsnull;
00989     PRUint32 i;
00990     for (i=0; i<count; i++) {
00991         nsCOMPtr<nsISupports> filterSupports;
00992         rv = m_filters->GetElementAt(i, getter_AddRefs(filterSupports));
00993         if (NS_FAILED(rv)) continue;
00994         
00995         // cast is safe because array is private
00996         nsIMsgFilter *filter = (nsIMsgFilter *)filterSupports.get();
00997         nsXPIDLString filterName;
00998         filter->GetFilterName(getter_Copies(filterName));
00999         if (nsCRT::strcmp(filterName, aName) == 0) {
01000             *aResult = filter;
01001             break;
01002         }
01003     }
01004 
01005     NS_IF_ADDREF(*aResult);
01006     return NS_OK;
01007 }
01008 
01009 nsresult nsMsgFilterList::SetFilterAt(PRUint32 filterIndex, nsIMsgFilter *filter)
01010 {
01011        m_filters->ReplaceElementAt(filter, filterIndex);
01012        return NS_OK;
01013 }
01014 
01015 
01016 nsresult nsMsgFilterList::RemoveFilterAt(PRUint32 filterIndex)
01017 {
01018        m_filters->RemoveElementAt(filterIndex);
01019        return NS_OK;
01020 }
01021 
01022 nsresult
01023 nsMsgFilterList::RemoveFilter(nsIMsgFilter *aFilter)
01024 {
01025     return m_filters->RemoveElement(NS_STATIC_CAST(nsISupports*, aFilter));
01026 }
01027 
01028 nsresult nsMsgFilterList::InsertFilterAt(PRUint32 filterIndex, nsIMsgFilter *aFilter)
01029 {
01030   nsMsgFilter *filter = NS_STATIC_CAST(nsMsgFilter *, aFilter);
01031   if (!m_temporaryList)
01032     filter->SetFilterList(this);
01033   m_filters->InsertElementAt(aFilter, filterIndex);
01034   return NS_OK;
01035 }
01036 
01037 // Attempt to move the filter at index filterIndex in the specified direction.
01038 // If motion not possible in that direction, we still return success.
01039 // We could return an error if the FE's want to beep or something.
01040 nsresult nsMsgFilterList::MoveFilterAt(PRUint32 filterIndex, 
01041                                        nsMsgFilterMotionValue motion)
01042 {
01043     NS_ENSURE_ARG((motion == nsMsgFilterMotion::up) ||
01044                   (motion == nsMsgFilterMotion::down));
01045 
01046        PRUint32                    filterCount;
01047        m_filters->Count(&filterCount);
01048     
01049     NS_ENSURE_ARG(filterCount >= filterIndex);
01050 
01051     PRUint32 newIndex = filterIndex;
01052     
01053        if (motion == nsMsgFilterMotion::up)
01054        {
01055         newIndex = filterIndex - 1;
01056 
01057         // are we already at the top?
01058               if (filterIndex == 0) return NS_OK;
01059        }
01060        else if (motion == nsMsgFilterMotion::down)
01061        {
01062         newIndex = filterIndex + 1;
01063         
01064         // are we already at the bottom?
01065               if (newIndex > filterCount - 1) return NS_OK;
01066        }
01067     m_filters->MoveElement(filterIndex,newIndex);
01068        return NS_OK;
01069 }
01070 
01071 nsresult nsMsgFilterList::MoveFilter(nsIMsgFilter *aFilter,
01072                                      nsMsgFilterMotionValue motion)
01073 {
01074     nsresult rv;
01075 
01076     PRInt32 filterIndex;
01077     rv = m_filters->GetIndexOf(NS_STATIC_CAST(nsISupports*,aFilter),
01078                                &filterIndex);
01079     NS_ENSURE_SUCCESS(rv, rv);
01080     NS_ENSURE_ARG(filterIndex >= 0);
01081         
01082 
01083     return MoveFilterAt(filterIndex, motion);
01084 }
01085 
01086 nsresult
01087 nsMsgFilterList::GetVersion(PRInt16 *aResult)
01088 {
01089     NS_ENSURE_ARG_POINTER(aResult);
01090     *aResult = m_fileVersion;
01091     return NS_OK;
01092 }
01093 
01094 NS_IMETHODIMP nsMsgFilterList::MatchOrChangeFilterTarget(const char *oldFolderUri, const char *newFolderUri, PRBool caseInsensitive, PRBool *found)
01095 {
01096   nsresult rv = NS_OK;
01097   PRUint32 numFilters;
01098   rv = m_filters->Count(&numFilters);
01099   NS_ENSURE_SUCCESS(rv,rv);
01100   nsCOMPtr <nsIMsgFilter> filter;
01101   nsXPIDLCString folderUri;
01102   for (PRUint32 index = 0; index < numFilters; index++)
01103   {
01104     filter = do_QueryElementAt(m_filters, index, &rv);
01105     NS_ENSURE_SUCCESS(rv, rv);
01106 
01107     nsCOMPtr<nsISupportsArray> filterActionList;
01108     rv = filter->GetActionList(getter_AddRefs(filterActionList));
01109     PRUint32 numActions;
01110     filterActionList->Count(&numActions);
01111 
01112     for (PRUint32 actionIndex =0; actionIndex < numActions; actionIndex++)
01113     {
01114       nsCOMPtr<nsIMsgRuleAction> filterAction =
01115           do_QueryElementAt(filterActionList, actionIndex);
01116       nsMsgRuleActionType actionType;
01117       if (filterAction)
01118         filterAction->GetType(&actionType);
01119       else
01120         continue;
01121 
01122       if (actionType == nsMsgFilterAction::MoveToFolder ||
01123           actionType == nsMsgFilterAction::CopyToFolder)
01124       {
01125         rv = filterAction->GetTargetFolderUri(getter_Copies(folderUri));
01126         if (NS_SUCCEEDED(rv) && folderUri)
01127            if (caseInsensitive)
01128           {
01129             if (PL_strcasecmp(folderUri,oldFolderUri) == 0 ) //local
01130             {
01131               if (newFolderUri)  //if we just want to match the uri's, newFolderUri will be null
01132                 rv = filterAction->SetTargetFolderUri(newFolderUri);
01133               NS_ENSURE_SUCCESS(rv,rv);
01134               *found =PR_TRUE;
01135             }
01136           }
01137           else
01138           {
01139             if (PL_strcmp(folderUri,oldFolderUri) == 0 )  //imap
01140             {
01141               if (newFolderUri) //if we just want to match the uri's, newFolderUri will be null
01142                 rv = filterAction->SetTargetFolderUri(newFolderUri);
01143               NS_ENSURE_SUCCESS(rv,rv);
01144               *found =PR_TRUE;
01145             }
01146           }
01147         break;  //we allow only one move action per filter
01148       }
01149     }
01150   }
01151   return rv;
01152 }
01153 
01154 // this would only return true if any filter was on "any header", which we
01155 // don't support in 6.x
01156 NS_IMETHODIMP nsMsgFilterList::GetShouldDownloadAllHeaders(PRBool *aResult)
01157 {
01158   *aResult = PR_FALSE;
01159   return NS_OK;
01160 }
01161 
01162 // leaves m_arbitraryHeaders filed in with the arbitrary headers.
01163 nsresult nsMsgFilterList::ComputeArbitraryHeaders()
01164 {
01165   nsresult rv = NS_OK;
01166   if (m_arbitraryHeaders.IsEmpty())
01167   {
01168     PRUint32 numFilters;
01169     rv = m_filters->Count(&numFilters);
01170     NS_ENSURE_SUCCESS(rv,rv);
01171     nsCOMPtr <nsIMsgFilter> filter;
01172     nsMsgSearchAttribValue attrib;
01173     nsXPIDLCString arbitraryHeader;
01174     for (PRUint32 index = 0; index < numFilters; index++)
01175     {
01176       filter = do_QueryElementAt(m_filters, index, &rv);
01177       if (NS_SUCCEEDED(rv) && filter)
01178       {
01179         nsCOMPtr <nsISupportsArray> searchTerms;
01180         PRUint32 numSearchTerms=0;
01181         filter->GetSearchTerms(getter_AddRefs(searchTerms));
01182         if (searchTerms)
01183           searchTerms->Count(&numSearchTerms);
01184         for (PRUint32 i=0; i< numSearchTerms;i++)
01185         {
01186           filter->GetTerm(i, &attrib, nsnull,nsnull,nsnull, getter_Copies(arbitraryHeader));
01187           if (arbitraryHeader && arbitraryHeader[0])
01188           {
01189             if (m_arbitraryHeaders.IsEmpty())
01190               m_arbitraryHeaders.Assign(arbitraryHeader);
01191             else if (PL_strncasecmp(m_arbitraryHeaders.get(), arbitraryHeader, arbitraryHeader.Length()))
01192             {
01193               m_arbitraryHeaders.Append(" ");
01194               m_arbitraryHeaders.Append(arbitraryHeader);
01195             }
01196           }
01197         }
01198       }
01199     }
01200   }
01201   return rv;
01202 }
01203 
01204 NS_IMETHODIMP nsMsgFilterList::GetArbitraryHeaders(char **aResult)
01205 {
01206   ComputeArbitraryHeaders();
01207   *aResult = ToNewCString(m_arbitraryHeaders);
01208   return NS_OK;
01209 }
01210 
01211 NS_IMETHODIMP nsMsgFilterList::FlushLogIfNecessary()
01212 {
01213   // only flush the log if we are logging
01214   PRBool loggingEnabled = PR_FALSE;
01215   nsresult rv = GetLoggingEnabled(&loggingEnabled);
01216   NS_ENSURE_SUCCESS(rv,rv);
01217 
01218   if (loggingEnabled) 
01219   {
01220     nsCOMPtr <nsIOutputStream> logStream;
01221     rv = GetLogStream(getter_AddRefs(logStream));    
01222     if (NS_SUCCEEDED(rv) && logStream) {
01223       rv = logStream->Flush();
01224       NS_ENSURE_SUCCESS(rv,rv);
01225     }
01226   }
01227   return rv;
01228 }
01229 
01230 #ifdef DEBUG
01231 void nsMsgFilterList::Dump()
01232 {
01233        PRUint32                    filterCount;
01234        m_filters->Count(&filterCount);
01235        printf("%d filters\n", filterCount);
01236 
01237        for (PRUint32 i = 0; i < filterCount; i++)
01238        {
01239               nsMsgFilter *filter;
01240               if (GetMsgFilterAt(i, &filter) == NS_OK)
01241               {
01242                      filter->Dump();
01243                      NS_RELEASE(filter);
01244               }
01245        }
01246 
01247 }
01248 #endif
01249 
01250 // ------------ End FilterList methods ------------------