Back to index

lightning-sunbird  0.9+nobinonly
nsMsgPurgeService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Navin Gupta <naving@netscape.com> (Original Developer)
00024  *   Seth Spitzer <sspitzer@netscape.com>
00025  *   David Bienvenu <bienvenu@mozilla.org>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #ifdef MOZ_LOGGING
00042 // sorry, this has to be before the pre-compiled header
00043 #define FORCE_PR_LOG /* Allow logging in the release build */
00044 #endif
00045 
00046 #include "nsMsgPurgeService.h"
00047 #include "nsCRT.h"
00048 #include "nsIMsgAccountManager.h"
00049 #include "nsMsgBaseCID.h"
00050 #include "nsMsgUtils.h"
00051 #include "nsMsgSearchCore.h"
00052 #include "msgCore.h"
00053 #include "nsISpamSettings.h"
00054 #include "nsIMsgSearchTerm.h"
00055 #include "nsIMsgHdr.h"
00056 #include "nsIRDFService.h"
00057 #include "nsIFileSpec.h"
00058 #include "nsIMsgProtocolInfo.h"
00059 #include "nsIMsgFilterPlugin.h"
00060 #include "nsIPrefBranch.h"
00061 #include "nsIPrefService.h"
00062 #include "prlog.h"
00063 #include "nsMsgFolderFlags.h"
00064 
00065 static PRLogModuleInfo *MsgPurgeLogModule = nsnull;
00066 
00067 NS_IMPL_ISUPPORTS2(nsMsgPurgeService, nsIMsgPurgeService, nsIMsgSearchNotify)
00068 
00069 void OnPurgeTimer(nsITimer *timer, void *aPurgeService)
00070 {
00071   nsMsgPurgeService *purgeService = (nsMsgPurgeService*)aPurgeService;
00072   purgeService->PerformPurge();           
00073 }
00074 
00075 nsMsgPurgeService::nsMsgPurgeService()
00076 {
00077   mHaveShutdown = PR_FALSE;
00078   mMinDelayBetweenPurges = 480;  // never purge a folder more than once every 8 hours (60 min/hour * 8 hours)
00079   mPurgeTimerInterval = 5;  // fire the purge timer every 5 minutes, starting 5 minutes after the service is created (when we load accounts)
00080 }
00081 
00082 nsMsgPurgeService::~nsMsgPurgeService()
00083 {
00084   if (mPurgeTimer)
00085     mPurgeTimer->Cancel();
00086   
00087   if(!mHaveShutdown)
00088     Shutdown();
00089 }
00090 
00091 NS_IMETHODIMP nsMsgPurgeService::Init()
00092 {
00093   nsresult rv;
00094   
00095   if (!MsgPurgeLogModule)
00096     MsgPurgeLogModule = PR_NewLogModule("MsgPurge");
00097 
00098   // these prefs are here to help QA test this feature
00099   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00100   if (NS_SUCCEEDED(rv))
00101   {
00102     PRInt32 min_delay;
00103     rv = prefBranch->GetIntPref("mail.purge.min_delay", &min_delay);
00104     if (NS_SUCCEEDED(rv) &&  min_delay) 
00105       mMinDelayBetweenPurges = min_delay;
00106     
00107     PRInt32 purge_timer_interval;
00108     rv = prefBranch->GetIntPref("mail.purge.timer_interval", &purge_timer_interval);
00109     if (NS_SUCCEEDED(rv) &&  purge_timer_interval) 
00110       mPurgeTimerInterval = purge_timer_interval;
00111   }
00112   
00113   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("mail.purge.min_delay=%d minutes",mMinDelayBetweenPurges));
00114   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("mail.purge.timer_interval=%d minutes",mPurgeTimerInterval));
00115 
00116   // don't start purging right away.
00117   // because the accounts aren't loaded and because the user might be trying to sign in
00118   // or startup, etc.
00119   SetupNextPurge();
00120 
00121   mHaveShutdown = PR_FALSE;
00122   return NS_OK;
00123 }
00124 
00125 NS_IMETHODIMP nsMsgPurgeService::Shutdown()
00126 {
00127   if (mPurgeTimer) 
00128   {
00129     mPurgeTimer->Cancel();
00130     mPurgeTimer = nsnull;
00131   }
00132   
00133   mHaveShutdown = PR_TRUE;
00134   return NS_OK;
00135 }
00136 
00137 nsresult nsMsgPurgeService::SetupNextPurge()
00138 {
00139   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("setting to check again in %d minutes",mPurgeTimerInterval));
00140 
00141   // Convert mPurgeTimerInterval into milliseconds
00142   PRUint32 timeInMSUint32 = mPurgeTimerInterval * 60000;
00143 
00144   // Can't currently reset a timer when it's in the process of
00145   // calling Notify. So, just release the timer here and create a new one.
00146   if(mPurgeTimer)
00147     mPurgeTimer->Cancel();
00148   
00149   mPurgeTimer = do_CreateInstance("@mozilla.org/timer;1");
00150   mPurgeTimer->InitWithFuncCallback(OnPurgeTimer, (void*)this, timeInMSUint32, 
00151     nsITimer::TYPE_ONE_SHOT);
00152    
00153   return NS_OK;
00154 }
00155 
00156 // This is the function that looks for the first folder to purge. It also 
00157 // applies retention settings to any folder that hasn't had retention settings
00158 // applied in mMinDelayBetweenPurges minutes (default, 8 hours).
00159 // However, if we've spent more than .5 seconds in this loop, don't
00160 // apply any more retention settings because it might lock up the UI.
00161 // This might starve folders later on in the hierarchy, since we always
00162 // start at the top, but since we also apply retention settings when you
00163 // open a folder, or when you compact all folders, I think this will do
00164 // for now, until we have a cleanup on shutdown architecture.
00165 nsresult nsMsgPurgeService::PerformPurge()
00166 {
00167   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("performing purge"));
00168 
00169   nsresult rv;
00170   
00171   nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00172   NS_ENSURE_SUCCESS(rv,rv);
00173   PRBool keepApplyingRetentionSettings = PR_TRUE;
00174 
00175   nsCOMPtr<nsISupportsArray> allServers;
00176   rv = accountManager->GetAllServers(getter_AddRefs(allServers));
00177   if (NS_SUCCEEDED(rv) && allServers)
00178   {
00179     PRUint32 numServers;
00180     rv = allServers->Count(&numServers);
00181     PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%d servers", numServers));
00182     nsCOMPtr<nsIMsgFolder> folderToPurge;
00183     PRIntervalTime startTime = PR_IntervalNow();
00184     PRInt32 purgeIntervalToUse;
00185     nsTime oldestPurgeTime = 0; // we're going to pick the least-recently purged folder
00186 
00187     // apply retention settings to folders that haven't had retention settings
00188     // applied in mMinDelayBetweenPurges minutes (default 8 hours)
00189     // Because we get last purge time from the folder cache,
00190     // this code won't open db's for folders until it decides it needs
00191     // to apply retention settings, and since nsIMsgFolder::ApplyRetentionSettings
00192     // will close any db's it opens, this code won't leave db's open.
00193     for (PRUint32 serverIndex=0; serverIndex < numServers; serverIndex++)
00194     {
00195       nsCOMPtr <nsIMsgIncomingServer> server =
00196         do_QueryElementAt(allServers, serverIndex, &rv);
00197       if (NS_SUCCEEDED(rv) && server)
00198       {
00199         if (keepApplyingRetentionSettings)
00200         {
00201           nsCOMPtr <nsIMsgFolder> rootFolder;
00202           rv = server->GetRootFolder(getter_AddRefs(rootFolder));
00203           NS_ENSURE_SUCCESS(rv, rv);
00204 
00205           nsCOMPtr <nsISupportsArray> childFolders = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
00206           NS_ENSURE_SUCCESS(rv, rv);
00207           rv = rootFolder->ListDescendents(childFolders);
00208 
00209           PRUint32 cnt =0;  
00210           childFolders->Count(&cnt);
00211 
00212           nsCOMPtr<nsISupports> supports;
00213           nsCOMPtr<nsIUrlListener> urlListener;
00214           nsCOMPtr<nsIMsgFolder> childFolder;
00215 
00216           for (PRUint32 index = 0; index < cnt; index++)
00217           {
00218             childFolder = do_QueryElementAt(childFolders, index);
00219             if (childFolder)
00220             {
00221               PRUint32 folderFlags;
00222               (void) childFolder->GetFlags(&folderFlags);
00223               if (folderFlags & MSG_FOLDER_FLAG_VIRTUAL)
00224                 continue;
00225               nsTime curFolderLastPurgeTime=0;
00226               nsXPIDLCString curFolderLastPurgeTimeString, curFolderUri;
00227               rv = childFolder->GetStringProperty("LastPurgeTime", getter_Copies(curFolderLastPurgeTimeString));
00228               if (NS_FAILED(rv))  
00229                 continue; // it is ok to fail, go on to next folder
00230                 
00231               if (!curFolderLastPurgeTimeString.IsEmpty())
00232               {
00233                 PRInt64 theTime;
00234                 PR_ParseTimeString(curFolderLastPurgeTimeString.get(), PR_FALSE, &theTime);
00235                 curFolderLastPurgeTime = theTime;
00236               }
00237   
00238               childFolder->GetURI(getter_Copies(curFolderUri));
00239               PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%s curFolderLastPurgeTime=%s (if blank, then never)", curFolderUri.get(), curFolderLastPurgeTimeString.get()));
00240 
00241               // check if this folder is due to purge
00242               // has to have been purged at least mMinDelayBetweenPurges minutes ago
00243               // we don't want to purge the folders all the time - once a day is good enough
00244               nsInt64 minDelayBetweenPurges(mMinDelayBetweenPurges);
00245               nsInt64 microSecondsPerMinute(60000000);
00246               nsTime nextPurgeTime = curFolderLastPurgeTime + (minDelayBetweenPurges * microSecondsPerMinute);
00247               nsTime currentTime; // nsTime defaults to PR_Now
00248               if (nextPurgeTime < currentTime)
00249               {
00250                 PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("purging %s", curFolderUri.get()));
00251                 childFolder->ApplyRetentionSettings();
00252               }
00253               PRIntervalTime elapsedTime;
00254               LL_SUB(elapsedTime, PR_IntervalNow(), startTime);
00255               // check if more than 500 milliseconds have elapsed in this purge process
00256               if (PR_IntervalToMilliseconds(elapsedTime) > 500)
00257               {
00258                 keepApplyingRetentionSettings = PR_FALSE;
00259                 break;
00260               }
00261             }
00262           }
00263         }
00264         nsXPIDLCString type;
00265         nsresult rv = server->GetType(getter_Copies(type));
00266         NS_ENSURE_SUCCESS(rv, rv);
00267         
00268         nsCAutoString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX);
00269         contractid.Append(type);
00270         
00271         nsCOMPtr<nsIMsgProtocolInfo> protocolInfo =
00272           do_GetService(contractid.get(), &rv);
00273         NS_ENSURE_SUCCESS(rv, PR_FALSE);
00274 
00275         nsXPIDLCString realHostName;
00276         server->GetRealHostName(getter_Copies(realHostName));
00277         PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s (%s)", serverIndex, realHostName.get(), type.get()));
00278 
00279         nsCOMPtr <nsISpamSettings> spamSettings;
00280         rv = server->GetSpamSettings(getter_AddRefs(spamSettings));
00281         NS_ENSURE_SUCCESS(rv, rv);
00282 
00283         PRInt32 spamLevel;
00284         spamSettings->GetLevel(&spamLevel);
00285         PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] spamLevel=%d (if 0, don't purge)", serverIndex, spamLevel));
00286         if (!spamLevel)
00287           continue;
00288         
00289         // check if we are set up to purge for this server
00290         // if not, skip it.
00291         PRBool purgeSpam;
00292         spamSettings->GetPurge(&purgeSpam);
00293 
00294         PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purgeSpam=%s (if false, don't purge)", serverIndex, purgeSpam ? "true" : "false"));
00295         if (!purgeSpam)
00296           continue;
00297         
00298         // check if the spam folder uri is set for this server
00299         // if not skip it.
00300         nsXPIDLCString junkFolderURI;
00301         rv = spamSettings->GetSpamFolderURI(getter_Copies(junkFolderURI));
00302         NS_ENSURE_SUCCESS(rv,rv);
00303 
00304         PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] junkFolderURI=%s (if empty, don't purge)", serverIndex, junkFolderURI.get()));
00305         if (junkFolderURI.IsEmpty())
00306           continue;
00307 
00308         // if the junk folder doesn't exist
00309         // because the folder pane isn't built yet, for example
00310         // skip this account
00311         nsCOMPtr<nsIMsgFolder> junkFolder;
00312         GetExistingFolder(junkFolderURI.get(), getter_AddRefs(junkFolder));
00313 
00314         PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s exists? %s (if doesn't exist, don't purge)", serverIndex, junkFolderURI.get(), junkFolder ? "true" : "false"));
00315         if (!junkFolder)
00316           continue;  
00317     
00318         nsTime curJunkFolderLastPurgeTime=0;
00319         nsXPIDLCString curJunkFolderLastPurgeTimeString;
00320         rv = junkFolder->GetStringProperty("curJunkFolderLastPurgeTime", getter_Copies(curJunkFolderLastPurgeTimeString));
00321         if (NS_FAILED(rv))  
00322           continue; // it is ok to fail, junk folder may not exist
00323                 
00324         if (!curJunkFolderLastPurgeTimeString.IsEmpty())
00325         {
00326           PRInt64 theTime;
00327           PR_ParseTimeString(curJunkFolderLastPurgeTimeString.get(), PR_FALSE, &theTime);
00328           curJunkFolderLastPurgeTime = theTime;
00329         }
00330   
00331         PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s curJunkFolderLastPurgeTime=%s (if blank, then never)", serverIndex, junkFolderURI.get(), curJunkFolderLastPurgeTimeString.get()));
00332 
00333         // check if this account is due to purge
00334         // has to have been purged at least mMinDelayBetweenPurges minutes ago
00335         // we don't want to purge the folders all the time
00336         nsTime nextPurgeTime = curJunkFolderLastPurgeTime + nsInt64(mMinDelayBetweenPurges * 60000000 /* convert mMinDelayBetweenPurges to into microseconds */);
00337         nsTime currentTime;
00338         if (nextPurgeTime < currentTime) 
00339         {
00340           PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge greater than min delay", serverIndex));
00341 
00342           nsCOMPtr <nsIMsgIncomingServer> junkFolderServer;
00343           rv = junkFolder->GetServer(getter_AddRefs(junkFolderServer));
00344           NS_ENSURE_SUCCESS(rv,rv);
00345           
00346           PRBool serverBusy = PR_FALSE;
00347           PRBool serverRequiresPassword = PR_TRUE;
00348           PRBool passwordPromptRequired;
00349           PRBool canSearchMessages = PR_FALSE;
00350           junkFolderServer->GetPasswordPromptRequired(&passwordPromptRequired);
00351           junkFolderServer->GetServerBusy(&serverBusy);
00352           junkFolderServer->GetServerRequiresPasswordForBiff(&serverRequiresPassword);
00353           junkFolderServer->GetCanSearchMessages(&canSearchMessages);
00354           // Make sure we're logged on before doing the search (assuming we need to be)
00355           // and make sure the server isn't already in the middle of downloading new messages
00356           // and make sure a search isn't already going on
00357           PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (search in progress? %s)", serverIndex, mSearchSession ? "true" : "false")); 
00358           PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (server busy? %s)", serverIndex, serverBusy ? "true" : "false"));
00359           PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (serverRequiresPassword? %s)", serverIndex, serverRequiresPassword ? "true" : "false"));
00360           PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (passwordPromptRequired? %s)", serverIndex, passwordPromptRequired ? "true" : "false"));
00361           if (canSearchMessages && !mSearchSession && !serverBusy && (!serverRequiresPassword || !passwordPromptRequired))
00362           {
00363             PRInt32 purgeInterval;
00364             spamSettings->GetPurgeInterval(&purgeInterval);
00365 
00366             if ((oldestPurgeTime == nsInt64(0)) || (curJunkFolderLastPurgeTime < oldestPurgeTime))
00367             {
00368               PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purging! searching for messages older than %d days", serverIndex, purgeInterval));
00369               oldestPurgeTime = curJunkFolderLastPurgeTime;
00370               purgeIntervalToUse = purgeInterval;
00371               folderToPurge = junkFolder;
00372               // if we've never purged this folder, do it...
00373               if (curJunkFolderLastPurgeTime == nsInt64(0))
00374                 break;
00375             }
00376           }
00377           else {
00378             NS_ASSERTION(canSearchMessages, "unexpected, you should be able to search");
00379             PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] not a good time for this server, try again later", serverIndex));
00380           }
00381         }
00382         else {
00383           PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge too recent", serverIndex));
00384         }
00385       }
00386     }
00387     if (folderToPurge)
00388       rv = SearchFolderToPurge(folderToPurge, purgeIntervalToUse);
00389   }
00390     
00391   // set up timer to check accounts again
00392   SetupNextPurge();
00393   return rv;
00394 }
00395 
00396 nsresult nsMsgPurgeService::SearchFolderToPurge(nsIMsgFolder *folder, PRInt32 purgeInterval)
00397 {
00398   nsresult rv;
00399   mSearchSession = do_CreateInstance(NS_MSGSEARCHSESSION_CONTRACTID, &rv);
00400   NS_ENSURE_SUCCESS(rv, rv);
00401   mSearchSession->RegisterListener(this);
00402   
00403   // update the time we attempted to purge this folder
00404   char dateBuf[100];
00405   dateBuf[0] = '\0';
00406   PRExplodedTime exploded;
00407   PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &exploded);
00408   PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%a %b %d %H:%M:%S %Y", &exploded);
00409   folder->SetStringProperty("curJunkFolderLastPurgeTime", dateBuf);
00410   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("curJunkFolderLastPurgeTime is now %s", dateBuf));
00411 
00412   nsCOMPtr<nsIMsgIncomingServer> server;
00413   rv = folder->GetServer(getter_AddRefs(server)); //we need to get the folder's server scope because imap can have local junk folder
00414   NS_ENSURE_SUCCESS(rv, rv);
00415 
00416   nsMsgSearchScopeValue searchScope;
00417   server->GetSearchScope(&searchScope);
00418 
00419   mSearchSession->AddScopeTerm(searchScope, folder);
00420   
00421   // look for messages older than the cutoff
00422   // you can't also search by junk status, see
00423   // nsMsgPurgeService::OnSearchHit()
00424   nsCOMPtr <nsIMsgSearchTerm> searchTerm;
00425   mSearchSession->CreateTerm(getter_AddRefs(searchTerm));
00426   if (searchTerm)
00427   {
00428     searchTerm->SetAttrib(nsMsgSearchAttrib::AgeInDays);
00429     searchTerm->SetOp(nsMsgSearchOp::IsGreaterThan);
00430     nsCOMPtr<nsIMsgSearchValue> searchValue;
00431     searchTerm->GetValue(getter_AddRefs(searchValue));
00432     if (searchValue)
00433     {
00434       searchValue->SetAttrib(nsMsgSearchAttrib::AgeInDays);
00435       searchValue->SetAge((PRUint32) purgeInterval);
00436       searchTerm->SetValue(searchValue);
00437     }
00438     searchTerm->SetBooleanAnd(PR_FALSE);
00439     mSearchSession->AppendTerm(searchTerm);
00440   }
00441 
00442   // we are about to search
00443   // create mHdrsToDelete array (if not previously created)
00444   if (!mHdrsToDelete)  
00445   {
00446     mHdrsToDelete = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
00447     NS_ENSURE_SUCCESS(rv, rv);
00448   }
00449   else
00450   {
00451     PRUint32 count;
00452     mHdrsToDelete->Count(&count);
00453     NS_ASSERTION(count == 0, "mHdrsToDelete is not empty");
00454     if (count > 0)
00455       mHdrsToDelete->Clear();  // this shouldn't happen
00456   }
00457 
00458   mSearchFolder = folder;
00459   return mSearchSession->Search(nsnull);
00460 }
00461     
00462 NS_IMETHODIMP nsMsgPurgeService::OnNewSearch()
00463 {
00464   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("on new search"));
00465   return NS_OK;
00466 }
00467 
00468 NS_IMETHODIMP nsMsgPurgeService::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *aFolder)
00469 {
00470   NS_ENSURE_ARG_POINTER(aMsgHdr);
00471 
00472   nsXPIDLCString messageId;
00473   nsXPIDLCString author;
00474   nsXPIDLCString subject;
00475   
00476   aMsgHdr->GetMessageId(getter_Copies(messageId));
00477   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("messageId=%s", messageId.get()));
00478   aMsgHdr->GetSubject(getter_Copies(subject));
00479   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("subject=%s",subject.get()));
00480   aMsgHdr->GetAuthor(getter_Copies(author));
00481   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("author=%s",author.get()));
00482 
00483   // double check that the message is junk before adding to 
00484   // the list of messages to delete
00485   //
00486   // note, we can't just search for messages that are junk
00487   // because not all imap server support keywords 
00488   // (which we use for the junk score)
00489   // so the junk status would be in the message db.
00490   //
00491   // see bug #194090
00492   nsXPIDLCString junkScoreStr;
00493   nsresult rv = aMsgHdr->GetStringProperty("junkscore", getter_Copies(junkScoreStr));
00494   NS_ENSURE_SUCCESS(rv,rv);
00495 
00496   PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("junkScore=%s (if empty or <= 50, don't add to list delete)", junkScoreStr.get()));
00497 
00498   // if "junkscore" is not set, don't delete the message
00499   if (junkScoreStr.IsEmpty())
00500     return NS_OK;
00501 
00502   // I set the cut off at 50. this may change
00503   // it works for our bayesian plugin, as "0" is good, and "100" is junk
00504   // but it might need tweaking for other plugins
00505   if (atoi(junkScoreStr.get()) > 50) {
00506     PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("added message to delete"));
00507     return mHdrsToDelete->AppendElement(aMsgHdr);
00508   }
00509   else 
00510     return NS_OK;
00511 }
00512 
00513 NS_IMETHODIMP nsMsgPurgeService::OnSearchDone(nsresult status)
00514 {
00515   nsresult rv = NS_OK;
00516   if (NS_SUCCEEDED(status))
00517   {
00518     PRUint32 count;
00519     mHdrsToDelete->Count(&count);
00520     PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%d messages to delete", count));
00521 
00522     if (count > 0) {
00523       PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("delete messages"));
00524       rv = mSearchFolder->DeleteMessages(mHdrsToDelete, nsnull, PR_FALSE /*delete storage*/, PR_FALSE /*isMove*/, nsnull, PR_FALSE /*allowUndo*/);
00525     }
00526   }
00527   mHdrsToDelete->Clear();
00528   mSearchSession->UnregisterListener(this);
00529   // don't cache the session
00530   // just create another search session next time we search, rather than clearing scopes, terms etc.
00531   // we also use mSearchSession to determine if the purge service is "busy"
00532   mSearchSession = nsnull;  
00533   mSearchFolder = nsnull;
00534   return NS_OK;
00535 }