Back to index

lightning-sunbird  0.9+nobinonly
nsMsgBiffManager.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) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifdef MOZ_LOGGING
00039 #define FORCE_PR_LOG /* Allow logging in the release build */
00040 #endif
00041 
00042 #include "nsMsgBiffManager.h"
00043 #include "nsCRT.h"
00044 #include "nsIMsgMailSession.h"
00045 #include "nsIMsgAccountManager.h"
00046 #include "nsMsgBaseCID.h"
00047 #include "nsIObserverService.h"
00048 #include "nsStatusBarBiffManager.h"
00049 #include "nsCOMArray.h"
00050 #include "prlog.h"
00051 
00052 static NS_DEFINE_CID(kStatusBarBiffManagerCID, NS_STATUSBARBIFFMANAGER_CID);
00053 
00054 static PRLogModuleInfo *MsgBiffLogModule = nsnull;
00055 
00056 NS_IMPL_ISUPPORTS4(nsMsgBiffManager, nsIMsgBiffManager, nsIIncomingServerListener, nsIObserver, nsISupportsWeakReference)
00057 
00058 void OnBiffTimer(nsITimer *timer, void *aBiffManager)
00059 {
00060   nsMsgBiffManager *biffManager = (nsMsgBiffManager*)aBiffManager;
00061   biffManager->PerformBiff();             
00062 }
00063 
00064 nsMsgBiffManager::nsMsgBiffManager()
00065 {
00066   mBiffArray = nsnull;
00067   mHaveShutdown = PR_FALSE;
00068   mInited = PR_FALSE;
00069 }
00070 
00071 nsMsgBiffManager::~nsMsgBiffManager()
00072 {
00073   
00074   if (mBiffTimer) {
00075     mBiffTimer->Cancel();
00076   }
00077   
00078   PRInt32 count = mBiffArray->Count();
00079   PRInt32 i;
00080   for(i=0; i < count; i++)
00081   {
00082     nsBiffEntry *biffEntry = (nsBiffEntry*)mBiffArray->ElementAt(i);
00083     delete biffEntry;
00084   }
00085   delete mBiffArray;
00086   
00087   if(!mHaveShutdown)
00088   {
00089     Shutdown();
00090   }
00091 }
00092 
00093 NS_IMETHODIMP nsMsgBiffManager::Init()
00094 {
00095   if (mInited)
00096     return NS_OK;
00097 
00098   mInited = PR_TRUE;
00099   nsresult rv;
00100   
00101   nsCOMPtr<nsIMsgAccountManager> accountManager = 
00102   do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00103   if (NS_SUCCEEDED(rv))
00104   {
00105     accountManager->AddIncomingServerListener(this);
00106   }
00107 
00108   if(mHaveShutdown) //in turbo mode on profile change we don't need to do anything below this
00109   {
00110     mHaveShutdown = PR_FALSE;
00111     return NS_OK;
00112   }
00113 
00114   mBiffArray = new nsVoidArray();
00115   if(!mBiffArray)
00116     return NS_ERROR_OUT_OF_MEMORY;
00117   
00118   nsCOMPtr<nsIObserverService> observerService = 
00119     do_GetService("@mozilla.org/observer-service;1", &rv);
00120   if (NS_SUCCEEDED(rv))
00121   {    
00122     observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
00123   }
00124   
00125   
00126   //Ensure status bar biff service has started
00127   nsCOMPtr<nsStatusBarBiffManager> statusBarBiffService = 
00128     do_GetService(kStatusBarBiffManagerCID, &rv);
00129   
00130   if (!MsgBiffLogModule)
00131     MsgBiffLogModule = PR_NewLogModule("MsgBiff");
00132 
00133   return NS_OK;
00134 }
00135 
00136 NS_IMETHODIMP nsMsgBiffManager::Shutdown()
00137 {
00138   if (mBiffTimer) 
00139   {
00140     mBiffTimer->Cancel();
00141     mBiffTimer = nsnull;
00142   }
00143   nsresult rv;
00144   nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00145   if (NS_SUCCEEDED(rv))
00146   {
00147     accountManager->RemoveIncomingServerListener(this);
00148   }
00149   
00150   mHaveShutdown = PR_TRUE;
00151   mInited = PR_FALSE;
00152   return NS_OK;
00153 }
00154 
00155 
00156 NS_IMETHODIMP nsMsgBiffManager::AddServerBiff(nsIMsgIncomingServer *server)
00157 {
00158   nsresult rv;
00159   PRInt32 biffMinutes;
00160   
00161   rv = server->GetBiffMinutes(&biffMinutes);
00162   if(NS_FAILED(rv))
00163     return rv;
00164   
00165   //Don't add if biffMinutes isn't > 0
00166   if(biffMinutes > 0)
00167   {
00168     PRInt32 serverIndex = FindServer(server);
00169     //Only add it if it hasn't been added already.
00170     if(serverIndex == -1)
00171     {
00172       nsBiffEntry *biffEntry = new nsBiffEntry;
00173       if(!biffEntry)
00174         return NS_ERROR_OUT_OF_MEMORY;
00175       biffEntry->server = server;
00176       nsTime currentTime;
00177       rv = SetNextBiffTime(biffEntry, currentTime);
00178       if(NS_FAILED(rv))
00179         return rv;
00180       
00181       AddBiffEntry(biffEntry);
00182       SetupNextBiff();
00183     }
00184   }
00185   return NS_OK;
00186 }
00187 
00188 NS_IMETHODIMP nsMsgBiffManager::RemoveServerBiff(nsIMsgIncomingServer *server)
00189 {
00190   PRInt32 pos = FindServer(server);
00191   if(pos != -1)
00192   {
00193     nsBiffEntry *biffEntry = (nsBiffEntry*)mBiffArray->ElementAt(pos);
00194     mBiffArray->RemoveElementAt(pos);
00195     delete biffEntry;
00196   }
00197   
00198   //Should probably reset biff time if this was the server that gets biffed next.
00199        return NS_OK;
00200 }
00201 
00202 
00203 NS_IMETHODIMP nsMsgBiffManager::ForceBiff(nsIMsgIncomingServer *server)
00204 {
00205   return NS_OK;
00206 }
00207 
00208 NS_IMETHODIMP nsMsgBiffManager::ForceBiffAll()
00209 {
00210   return NS_OK;
00211 }
00212 
00213 NS_IMETHODIMP nsMsgBiffManager::OnServerLoaded(nsIMsgIncomingServer *server)
00214 {
00215   nsresult rv;
00216   PRBool doBiff = PR_FALSE;
00217   
00218   rv = server->GetDoBiff(&doBiff);
00219   
00220   if(NS_SUCCEEDED(rv) && doBiff)
00221   {
00222     rv = AddServerBiff(server);
00223   }
00224   
00225   return rv;
00226 }
00227 
00228 NS_IMETHODIMP nsMsgBiffManager::OnServerUnloaded(nsIMsgIncomingServer *server)
00229 {
00230   return RemoveServerBiff(server);
00231 }
00232 
00233 NS_IMETHODIMP nsMsgBiffManager::OnServerChanged(nsIMsgIncomingServer *server)
00234 {
00235   // nothing required.  If the hostname or username changed
00236   // the next time biff fires, we'll ping the right server
00237   return NS_OK;
00238 }
00239 
00240 NS_IMETHODIMP nsMsgBiffManager::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00241 {
00242   if(!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
00243   {
00244     Shutdown();
00245   }
00246   
00247   return NS_OK;
00248 }
00249 
00250 PRInt32 nsMsgBiffManager::FindServer(nsIMsgIncomingServer *server)
00251 {
00252   PRInt32 count = mBiffArray->Count();
00253   for(PRInt32 i = 0; i < count; i++)
00254   {
00255     nsBiffEntry *biffEntry = (nsBiffEntry*)mBiffArray->ElementAt(i);
00256     if(server == biffEntry->server.get())
00257       return i;
00258   }
00259   return -1;
00260 }
00261 
00262 nsresult nsMsgBiffManager::AddBiffEntry(nsBiffEntry *biffEntry)
00263 {
00264   PRInt32 i;
00265   PRInt32 count = mBiffArray->Count();
00266   for(i = 0; i < count; i++)
00267   {
00268     nsBiffEntry *current = (nsBiffEntry*)mBiffArray->ElementAt(i);
00269     if(biffEntry->nextBiffTime < current->nextBiffTime)
00270       break;
00271     
00272   }
00273   PR_LOG(MsgBiffLogModule, PR_LOG_ALWAYS, ("inserting biff entry at %d\n", i));
00274   mBiffArray->InsertElementAt(biffEntry, i);
00275   return NS_OK;
00276 }
00277 
00278 nsresult nsMsgBiffManager::SetNextBiffTime(nsBiffEntry *biffEntry, nsTime startTime)
00279 {
00280   nsresult rv;
00281   nsIMsgIncomingServer *server = biffEntry->server;
00282   
00283   if(!server)
00284     return NS_ERROR_FAILURE;
00285   
00286   PRInt32 biffInterval;
00287   rv = server->GetBiffMinutes(&biffInterval);
00288   if(NS_FAILED(rv))
00289     return rv;
00290   //Add 60 secs/minute in microseconds to current time. biffEntry->nextBiffTime's
00291   //constructor makes it the current time.
00292   nsInt64 chosenTimeInterval = biffInterval;
00293   chosenTimeInterval *= 60000000;
00294   biffEntry->nextBiffTime = startTime;
00295   biffEntry->nextBiffTime += chosenTimeInterval;
00296   return NS_OK;
00297 }
00298 
00299 nsresult nsMsgBiffManager::SetupNextBiff()
00300 {
00301   
00302   if(mBiffArray->Count() > 0)
00303   {
00304     
00305     //Get the next biff entry
00306     nsBiffEntry *biffEntry = (nsBiffEntry*)mBiffArray->ElementAt(0);
00307     nsTime currentTime;
00308     nsInt64 biffDelay;
00309     nsInt64 ms(1000);
00310     if(currentTime > biffEntry->nextBiffTime)
00311     {
00312       PRInt64 microSecondsPerSecond;
00313   
00314       LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
00315       LL_MUL(biffDelay, 30, microSecondsPerSecond); //let's wait 30 seconds before firing biff again
00316     }
00317     else
00318       biffDelay = biffEntry->nextBiffTime - currentTime;
00319     //Convert biffDelay into milliseconds
00320     nsInt64 timeInMS = biffDelay / ms;
00321     PRUint32 timeInMSUint32 = (PRUint32)timeInMS;
00322     //Can't currently reset a timer when it's in the process of
00323     //calling Notify. So, just release the timer here and create a new one.
00324     if(mBiffTimer)
00325     {
00326       mBiffTimer->Cancel();
00327     }
00328     PR_LOG(MsgBiffLogModule, PR_LOG_ALWAYS, ("setting %d timer\n", timeInMSUint32));
00329     mBiffTimer = do_CreateInstance("@mozilla.org/timer;1");
00330     mBiffTimer->InitWithFuncCallback(OnBiffTimer, (void*)this, timeInMSUint32, 
00331                                      nsITimer::TYPE_ONE_SHOT);
00332     
00333   }
00334   return NS_OK;
00335 }
00336 
00337 //This is the function that does a biff on all of the servers whose time it is to biff.
00338 nsresult nsMsgBiffManager::PerformBiff()
00339 {
00340   nsTime currentTime;
00341   nsCOMArray <nsIMsgFolder> targetFolders;
00342   PR_LOG(MsgBiffLogModule, PR_LOG_ALWAYS, ("performing biffs\n"));
00343 
00344   for(PRInt32 i = 0; i < mBiffArray->Count(); i++)
00345   {
00346     nsBiffEntry *current = (nsBiffEntry*)mBiffArray->ElementAt(i);
00347     if(current->nextBiffTime < currentTime)
00348     {
00349       PRBool serverBusy = PR_FALSE;
00350       PRBool serverRequiresPassword = PR_TRUE;
00351       PRBool passwordPromptRequired; 
00352 
00353       current->server->GetPasswordPromptRequired(&passwordPromptRequired);
00354       current->server->GetServerBusy(&serverBusy);
00355       current->server->GetServerRequiresPasswordForBiff(&serverRequiresPassword);
00356       // find the dest folder we're actually downloading to...
00357       nsCOMPtr<nsIMsgFolder> rootMsgFolder;
00358       current->server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
00359       PRInt32 targetFolderIndex = targetFolders.IndexOfObject(rootMsgFolder);
00360       if (targetFolderIndex == kNotFound)
00361         targetFolders.AppendObject(rootMsgFolder);
00362 
00363       // so if we need to be authenticated to biff, check that we are
00364       // (since we don't want to prompt the user for password UI)
00365       // and make sure the server isn't already in the middle of downloading new messages
00366       if(!serverBusy && (!serverRequiresPassword || !passwordPromptRequired) && targetFolderIndex == kNotFound)
00367       {
00368         nsXPIDLCString serverKey;
00369         current->server->GetKey(getter_Copies(serverKey));
00370         nsresult rv = current->server->PerformBiff(nsnull);
00371         PR_LOG(MsgBiffLogModule, PR_LOG_ALWAYS, ("biffing server %s rv = %x\n", serverKey.get(), rv));
00372       }
00373       else
00374       {
00375         PR_LOG(MsgBiffLogModule, PR_LOG_ALWAYS, ("not biffing server serverBusy = %d requirespassword = %d password prompt required = %d targetFolderIndex = %d\n",
00376           serverBusy, serverRequiresPassword, passwordPromptRequired, targetFolderIndex));
00377       }
00378       // if we didn't do this server because the destination server was already being
00379       // biffed into, leave this server in the biff array so it will fire next.
00380       if (targetFolderIndex == kNotFound)
00381       {
00382         mBiffArray->RemoveElementAt(i);
00383         i--; //Because we removed it we need to look at the one that just moved up.
00384         SetNextBiffTime(current, currentTime);
00385         AddBiffEntry(current);
00386       }
00387 #ifdef DEBUG_David_Bienvenu
00388       else
00389         printf("dest account performing biff\n");
00390 #endif
00391     }
00392     else
00393       //since we're in biff order, there's no reason to keep checking
00394       break;
00395   }
00396   SetupNextBiff();
00397   return NS_OK;
00398 }
00399