Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Protected Member Functions | Protected Attributes | Private Attributes
nsMsgPurgeService Class Reference

#include <nsMsgPurgeService.h>

Inheritance diagram for nsMsgPurgeService:
Inheritance graph
Collaboration diagram for nsMsgPurgeService:
Collaboration graph

List of all members.

Public Member Functions

 nsMsgPurgeService ()
virtual ~nsMsgPurgeService ()
PerformPurge ()
void init ()
void shutdown ()
void onSearchHit (in nsIMsgDBHdr header, in nsIMsgFolder folder)
void onSearchDone (in nsresult status)
void onNewSearch ()

Protected Member Functions

PRInt32 FindServer (nsIMsgIncomingServer *server)
nsresult SetupNextPurge ()
nsresult PurgeSurver (nsIMsgIncomingServer *server)
nsresult SearchFolderToPurge (nsIMsgFolder *folder, PRInt32 purgeInterval)

Protected Attributes

nsCOMPtr< nsITimermPurgeTimer
nsCOMPtr< nsIMsgSearchSessionmSearchSession
nsCOMPtr< nsIMsgFoldermSearchFolder
nsCOMPtr< nsISupportsArraymHdrsToDelete
nsVoidArray mPurgeArray
PRBool mHaveShutdown

Private Attributes

PRInt32 mMinDelayBetweenPurges
PRInt32 mPurgeTimerInterval

Detailed Description

Definition at line 55 of file nsMsgPurgeService.h.

Constructor & Destructor Documentation

Definition at line 75 of file nsMsgPurgeService.cpp.

  mHaveShutdown = PR_FALSE;
  mMinDelayBetweenPurges = 480;  // never purge a folder more than once every 8 hours (60 min/hour * 8 hours)
  mPurgeTimerInterval = 5;  // fire the purge timer every 5 minutes, starting 5 minutes after the service is created (when we load accounts)

Definition at line 82 of file nsMsgPurgeService.cpp.

  if (mPurgeTimer)

Here is the call graph for this function:

Member Function Documentation

void nsIMsgPurgeService::init ( ) [inherited]
void nsIMsgSearchNotify::onSearchHit ( in nsIMsgDBHdr  header,
in nsIMsgFolder  folder 
) [inherited]

Definition at line 165 of file nsMsgPurgeService.cpp.

  PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("performing purge"));

  nsresult rv;
  nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
  PRBool keepApplyingRetentionSettings = PR_TRUE;

  nsCOMPtr<nsISupportsArray> allServers;
  rv = accountManager->GetAllServers(getter_AddRefs(allServers));
  if (NS_SUCCEEDED(rv) && allServers)
    PRUint32 numServers;
    rv = allServers->Count(&numServers);
    PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%d servers", numServers));
    nsCOMPtr<nsIMsgFolder> folderToPurge;
    PRIntervalTime startTime = PR_IntervalNow();
    PRInt32 purgeIntervalToUse;
    nsTime oldestPurgeTime = 0; // we're going to pick the least-recently purged folder

    // apply retention settings to folders that haven't had retention settings
    // applied in mMinDelayBetweenPurges minutes (default 8 hours)
    // Because we get last purge time from the folder cache,
    // this code won't open db's for folders until it decides it needs
    // to apply retention settings, and since nsIMsgFolder::ApplyRetentionSettings
    // will close any db's it opens, this code won't leave db's open.
    for (PRUint32 serverIndex=0; serverIndex < numServers; serverIndex++)
      nsCOMPtr <nsIMsgIncomingServer> server =
        do_QueryElementAt(allServers, serverIndex, &rv);
      if (NS_SUCCEEDED(rv) && server)
        if (keepApplyingRetentionSettings)
          nsCOMPtr <nsIMsgFolder> rootFolder;
          rv = server->GetRootFolder(getter_AddRefs(rootFolder));
          NS_ENSURE_SUCCESS(rv, rv);

          nsCOMPtr <nsISupportsArray> childFolders = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
          NS_ENSURE_SUCCESS(rv, rv);
          rv = rootFolder->ListDescendents(childFolders);

          PRUint32 cnt =0;  

          nsCOMPtr<nsISupports> supports;
          nsCOMPtr<nsIUrlListener> urlListener;
          nsCOMPtr<nsIMsgFolder> childFolder;

          for (PRUint32 index = 0; index < cnt; index++)
            childFolder = do_QueryElementAt(childFolders, index);
            if (childFolder)
              PRUint32 folderFlags;
              (void) childFolder->GetFlags(&folderFlags);
              if (folderFlags & MSG_FOLDER_FLAG_VIRTUAL)
              nsTime curFolderLastPurgeTime=0;
              nsXPIDLCString curFolderLastPurgeTimeString, curFolderUri;
              rv = childFolder->GetStringProperty("LastPurgeTime", getter_Copies(curFolderLastPurgeTimeString));
              if (NS_FAILED(rv))  
                continue; // it is ok to fail, go on to next folder
              if (!curFolderLastPurgeTimeString.IsEmpty())
                PRInt64 theTime;
                PR_ParseTimeString(curFolderLastPurgeTimeString.get(), PR_FALSE, &theTime);
                curFolderLastPurgeTime = theTime;
              PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%s curFolderLastPurgeTime=%s (if blank, then never)", curFolderUri.get(), curFolderLastPurgeTimeString.get()));

              // check if this folder is due to purge
              // has to have been purged at least mMinDelayBetweenPurges minutes ago
              // we don't want to purge the folders all the time - once a day is good enough
              nsInt64 minDelayBetweenPurges(mMinDelayBetweenPurges);
              nsInt64 microSecondsPerMinute(60000000);
              nsTime nextPurgeTime = curFolderLastPurgeTime + (minDelayBetweenPurges * microSecondsPerMinute);
              nsTime currentTime; // nsTime defaults to PR_Now
              if (nextPurgeTime < currentTime)
                PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("purging %s", curFolderUri.get()));
              PRIntervalTime elapsedTime;
              LL_SUB(elapsedTime, PR_IntervalNow(), startTime);
              // check if more than 500 milliseconds have elapsed in this purge process
              if (PR_IntervalToMilliseconds(elapsedTime) > 500)
                keepApplyingRetentionSettings = PR_FALSE;
        nsXPIDLCString type;
        nsresult rv = server->GetType(getter_Copies(type));
        NS_ENSURE_SUCCESS(rv, rv);
        nsCOMPtr<nsIMsgProtocolInfo> protocolInfo =
          do_GetService(contractid.get(), &rv);

        nsXPIDLCString realHostName;
        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s (%s)", serverIndex, realHostName.get(), type.get()));

        nsCOMPtr <nsISpamSettings> spamSettings;
        rv = server->GetSpamSettings(getter_AddRefs(spamSettings));
        NS_ENSURE_SUCCESS(rv, rv);

        PRInt32 spamLevel;
        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] spamLevel=%d (if 0, don't purge)", serverIndex, spamLevel));
        if (!spamLevel)
        // check if we are set up to purge for this server
        // if not, skip it.
        PRBool purgeSpam;

        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purgeSpam=%s (if false, don't purge)", serverIndex, purgeSpam ? "true" : "false"));
        if (!purgeSpam)
        // check if the spam folder uri is set for this server
        // if not skip it.
        nsXPIDLCString junkFolderURI;
        rv = spamSettings->GetSpamFolderURI(getter_Copies(junkFolderURI));

        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] junkFolderURI=%s (if empty, don't purge)", serverIndex, junkFolderURI.get()));
        if (junkFolderURI.IsEmpty())

        // if the junk folder doesn't exist
        // because the folder pane isn't built yet, for example
        // skip this account
        nsCOMPtr<nsIMsgFolder> junkFolder;
        GetExistingFolder(junkFolderURI.get(), getter_AddRefs(junkFolder));

        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s exists? %s (if doesn't exist, don't purge)", serverIndex, junkFolderURI.get(), junkFolder ? "true" : "false"));
        if (!junkFolder)
        nsTime curJunkFolderLastPurgeTime=0;
        nsXPIDLCString curJunkFolderLastPurgeTimeString;
        rv = junkFolder->GetStringProperty("curJunkFolderLastPurgeTime", getter_Copies(curJunkFolderLastPurgeTimeString));
        if (NS_FAILED(rv))  
          continue; // it is ok to fail, junk folder may not exist
        if (!curJunkFolderLastPurgeTimeString.IsEmpty())
          PRInt64 theTime;
          PR_ParseTimeString(curJunkFolderLastPurgeTimeString.get(), PR_FALSE, &theTime);
          curJunkFolderLastPurgeTime = theTime;
        PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s curJunkFolderLastPurgeTime=%s (if blank, then never)", serverIndex, junkFolderURI.get(), curJunkFolderLastPurgeTimeString.get()));

        // check if this account is due to purge
        // has to have been purged at least mMinDelayBetweenPurges minutes ago
        // we don't want to purge the folders all the time
        nsTime nextPurgeTime = curJunkFolderLastPurgeTime + nsInt64(mMinDelayBetweenPurges * 60000000 /* convert mMinDelayBetweenPurges to into microseconds */);
        nsTime currentTime;
        if (nextPurgeTime < currentTime) 
          PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge greater than min delay", serverIndex));

          nsCOMPtr <nsIMsgIncomingServer> junkFolderServer;
          rv = junkFolder->GetServer(getter_AddRefs(junkFolderServer));
          PRBool serverBusy = PR_FALSE;
          PRBool serverRequiresPassword = PR_TRUE;
          PRBool passwordPromptRequired;
          PRBool canSearchMessages = PR_FALSE;
          // Make sure we're logged on before doing the search (assuming we need to be)
          // and make sure the server isn't already in the middle of downloading new messages
          // and make sure a search isn't already going on
          PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (search in progress? %s)", serverIndex, mSearchSession ? "true" : "false")); 
          PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (server busy? %s)", serverIndex, serverBusy ? "true" : "false"));
          PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (serverRequiresPassword? %s)", serverIndex, serverRequiresPassword ? "true" : "false"));
          PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (passwordPromptRequired? %s)", serverIndex, passwordPromptRequired ? "true" : "false"));
          if (canSearchMessages && !mSearchSession && !serverBusy && (!serverRequiresPassword || !passwordPromptRequired))
            PRInt32 purgeInterval;

            if ((oldestPurgeTime == nsInt64(0)) || (curJunkFolderLastPurgeTime < oldestPurgeTime))
              PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purging! searching for messages older than %d days", serverIndex, purgeInterval));
              oldestPurgeTime = curJunkFolderLastPurgeTime;
              purgeIntervalToUse = purgeInterval;
              folderToPurge = junkFolder;
              // if we've never purged this folder, do it...
              if (curJunkFolderLastPurgeTime == nsInt64(0))
          else {
            NS_ASSERTION(canSearchMessages, "unexpected, you should be able to search");
            PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] not a good time for this server, try again later", serverIndex));
        else {
          PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge too recent", serverIndex));
    if (folderToPurge)
      rv = SearchFolderToPurge(folderToPurge, purgeIntervalToUse);
  // set up timer to check accounts again
  return rv;

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsMsgPurgeService::SearchFolderToPurge ( nsIMsgFolder folder,
PRInt32  purgeInterval 
) [protected]

Definition at line 396 of file nsMsgPurgeService.cpp.

  nsresult rv;
  mSearchSession = do_CreateInstance(NS_MSGSEARCHSESSION_CONTRACTID, &rv);
  // update the time we attempted to purge this folder
  char dateBuf[100];
  dateBuf[0] = '\0';
  PRExplodedTime exploded;
  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &exploded);
  PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%a %b %d %H:%M:%S %Y", &exploded);
  folder->SetStringProperty("curJunkFolderLastPurgeTime", dateBuf);
  PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("curJunkFolderLastPurgeTime is now %s", dateBuf));

  nsCOMPtr<nsIMsgIncomingServer> server;
  rv = folder->GetServer(getter_AddRefs(server)); //we need to get the folder's server scope because imap can have local junk folder

  nsMsgSearchScopeValue searchScope;

  mSearchSession->AddScopeTerm(searchScope, folder);
  // look for messages older than the cutoff
  // you can't also search by junk status, see
  // nsMsgPurgeService::OnSearchHit()
  nsCOMPtr <nsIMsgSearchTerm> searchTerm;
  if (searchTerm)
    nsCOMPtr<nsIMsgSearchValue> searchValue;
    if (searchValue)
      searchValue->SetAge((PRUint32) purgeInterval);

  // we are about to search
  // create mHdrsToDelete array (if not previously created)
  if (!mHdrsToDelete)  
    mHdrsToDelete = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);
    PRUint32 count;
    NS_ASSERTION(count == 0, "mHdrsToDelete is not empty");
    if (count > 0)
      mHdrsToDelete->Clear();  // this shouldn't happen

  mSearchFolder = folder;
  return mSearchSession->Search(nsnull);

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 137 of file nsMsgPurgeService.cpp.

  PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("setting to check again in %d minutes",mPurgeTimerInterval));

  // Convert mPurgeTimerInterval into milliseconds
  PRUint32 timeInMSUint32 = mPurgeTimerInterval * 60000;

  // Can't currently reset a timer when it's in the process of
  // calling Notify. So, just release the timer here and create a new one.
  mPurgeTimer = do_CreateInstance(";1");
  mPurgeTimer->InitWithFuncCallback(OnPurgeTimer, (void*)this, timeInMSUint32, 
  return NS_OK;

Here is the call graph for this function:

Here is the caller graph for this function:

Member Data Documentation

Definition at line 81 of file nsMsgPurgeService.h.

Definition at line 79 of file nsMsgPurgeService.h.

Definition at line 84 of file nsMsgPurgeService.h.

Definition at line 80 of file nsMsgPurgeService.h.

Definition at line 76 of file nsMsgPurgeService.h.

Definition at line 85 of file nsMsgPurgeService.h.

Definition at line 78 of file nsMsgPurgeService.h.

Definition at line 77 of file nsMsgPurgeService.h.

The documentation for this class was generated from the following files: