Back to index

lightning-sunbird  0.9+nobinonly
nsMsgOfflineManager.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) 2001
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 /*
00039  * The offline manager service - manages going online and offline, and synchronization
00040  */
00041 #include "msgCore.h"
00042 #include "netCore.h"
00043 #include "nsMsgOfflineManager.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsISupportsArray.h"
00046 #include "nsMsgBaseCID.h"
00047 #include "nsIImapService.h"
00048 #include "nsMsgImapCID.h"
00049 #include "nsIMsgSendLater.h"
00050 #include "nsIMsgAccountManager.h"
00051 #include "nsMsgCompCID.h"
00052 #include "nsIIOService.h"
00053 #include "nsNetCID.h"
00054 #include "nsMsgNewsCID.h"
00055 #include "nsINntpService.h"
00056 #include "nsXPIDLString.h"
00057 
00058 static NS_DEFINE_CID(kMsgSendLaterCID, NS_MSGSENDLATER_CID); 
00059 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
00060 
00061 NS_IMPL_THREADSAFE_ISUPPORTS5(nsMsgOfflineManager,
00062                               nsIMsgOfflineManager,
00063                               nsIMsgSendLaterListener,
00064                               nsIObserver,
00065                               nsISupportsWeakReference,
00066                               nsIUrlListener)
00067 
00068 nsMsgOfflineManager::nsMsgOfflineManager() :
00069   m_inProgress (PR_FALSE),
00070   m_sendUnsentMessages(PR_FALSE),
00071   m_downloadNews(PR_FALSE),
00072   m_downloadMail(PR_FALSE),
00073   m_playbackOfflineImapOps(PR_FALSE),
00074   m_goOfflineWhenDone(PR_FALSE),
00075   m_curState(eNoState),
00076   m_curOperation(eNoOp)
00077 {
00078 }
00079 
00080 nsMsgOfflineManager::~nsMsgOfflineManager()
00081 {
00082 }
00083 
00084 /* attribute nsIMsgWindow window; */
00085 NS_IMETHODIMP nsMsgOfflineManager::GetWindow(nsIMsgWindow * *aWindow)
00086 {
00087   NS_ENSURE_ARG(aWindow);
00088   *aWindow = m_window;
00089   NS_IF_ADDREF(*aWindow);
00090   return NS_OK;
00091 }
00092 NS_IMETHODIMP nsMsgOfflineManager::SetWindow(nsIMsgWindow * aWindow)
00093 {
00094   m_window = aWindow;
00095   if (m_window)
00096     m_window->GetStatusFeedback(getter_AddRefs(m_statusFeedback));
00097   else
00098     m_statusFeedback = nsnull;
00099   return NS_OK;
00100 }
00101 
00102 /* attribute boolean inProgress; */
00103 NS_IMETHODIMP nsMsgOfflineManager::GetInProgress(PRBool *aInProgress)
00104 {
00105   NS_ENSURE_ARG(aInProgress);
00106   *aInProgress = m_inProgress;
00107   return NS_OK;
00108 }
00109 
00110 NS_IMETHODIMP nsMsgOfflineManager::SetInProgress(PRBool aInProgress)
00111 {
00112   m_inProgress = aInProgress;
00113   return NS_OK;
00114 }
00115 
00116 nsresult nsMsgOfflineManager::StopRunning(nsresult exitStatus)
00117 {
00118   m_inProgress = PR_FALSE;
00119   return exitStatus;
00120 }
00121 
00122 nsresult nsMsgOfflineManager::AdvanceToNextState(nsresult exitStatus)
00123 {
00124   // NS_BINDING_ABORTED is used for the user pressing stop, which
00125   // should cause us to abort the offline process. Other errors
00126   // should allow us to continue.
00127   if (exitStatus == NS_BINDING_ABORTED)
00128   {
00129     return StopRunning(exitStatus);
00130   }
00131   if (m_curOperation == eGoingOnline)
00132   {
00133     switch (m_curState)
00134     {
00135     case eNoState:
00136 
00137       m_curState = eSendingUnsent;
00138       if (m_sendUnsentMessages)
00139       {
00140         SendUnsentMessages();
00141       }
00142       else
00143         AdvanceToNextState(NS_OK);
00144       break;
00145     case eSendingUnsent:
00146 
00147       m_curState = eSynchronizingOfflineImapChanges;
00148       if (m_playbackOfflineImapOps)
00149         return SynchronizeOfflineImapChanges();
00150       else
00151         AdvanceToNextState(NS_OK); // recurse to next state.
00152       break;
00153     case eSynchronizingOfflineImapChanges:
00154       m_curState = eDone;
00155       return StopRunning(exitStatus);
00156       default:
00157         NS_ASSERTION(PR_FALSE, "unhandled current state when going online");
00158     }
00159   }
00160   else if (m_curOperation == eDownloadingForOffline)
00161   {
00162     switch (m_curState)
00163     {
00164       case eNoState:
00165         m_curState = eDownloadingNews;
00166         if (m_downloadNews)
00167           DownloadOfflineNewsgroups();
00168         else
00169           AdvanceToNextState(NS_OK);
00170         break;
00171       case eSendingUnsent:
00172         if (m_goOfflineWhenDone)
00173         {
00174           SetOnlineState(PR_FALSE);
00175         }
00176         break;
00177       case eDownloadingNews:
00178         m_curState = eDownloadingMail;
00179         if (m_downloadMail)
00180           DownloadMail();
00181         else
00182           AdvanceToNextState(NS_OK);
00183         break;
00184       case eDownloadingMail:
00185         m_curState = eSendingUnsent;
00186         if (m_sendUnsentMessages)
00187           SendUnsentMessages();
00188         else
00189           AdvanceToNextState(NS_OK);
00190         break;
00191       default:
00192         NS_ASSERTION(PR_FALSE, "unhandled current state when downloading for offline");
00193     }
00194 
00195   }
00196   return NS_OK;
00197 }
00198 
00199 nsresult nsMsgOfflineManager::SynchronizeOfflineImapChanges()
00200 {
00201   nsresult rv = NS_OK;
00202        nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
00203   NS_ENSURE_SUCCESS(rv, rv);
00204   return imapService->PlaybackAllOfflineOperations(m_window, this, getter_AddRefs(mOfflineImapSync));
00205 }
00206 
00207 nsresult nsMsgOfflineManager::SendUnsentMessages()
00208 {
00209        nsresult rv;
00210        nsCOMPtr<nsIMsgSendLater> pMsgSendLater = do_CreateInstance(kMsgSendLaterCID, &rv); 
00211   NS_ENSURE_SUCCESS(rv, rv);
00212   nsCOMPtr<nsIMsgAccountManager> accountManager = 
00213            do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00214   NS_ENSURE_SUCCESS(rv, rv);
00215   // now we have to iterate over the identities, finding the *unique* unsent messages folder
00216   // for each one, determine if they have unsent messages, and if so, add them to the list
00217   // of identities to send unsent messages from.
00218   // However, I think there's only ever one unsent messages folder at the moment,
00219   // so I think we'll go with that for now.
00220   nsCOMPtr<nsISupportsArray> identities;
00221 
00222   if (NS_SUCCEEDED(rv) && accountManager) 
00223   {
00224     rv = accountManager->GetAllIdentities(getter_AddRefs(identities));
00225     NS_ENSURE_SUCCESS(rv, rv);
00226   }
00227   nsCOMPtr <nsIMsgIdentity> identityToUse;
00228   PRUint32 numIndentities;
00229   identities->Count(&numIndentities);
00230   for (PRUint32 i = 0; i < numIndentities; i++)
00231   {
00232     // convert supports->Identity
00233     nsCOMPtr<nsISupports> thisSupports;
00234     rv = identities->GetElementAt(i, getter_AddRefs(thisSupports));
00235     if (NS_FAILED(rv)) continue;
00236     
00237     nsCOMPtr<nsIMsgIdentity> thisIdentity = do_QueryInterface(thisSupports, &rv);
00238 
00239     if (NS_SUCCEEDED(rv) && thisIdentity)
00240     {
00241       nsCOMPtr <nsIMsgFolder> outboxFolder;
00242       pMsgSendLater->GetUnsentMessagesFolder(thisIdentity, getter_AddRefs(outboxFolder));
00243       if (outboxFolder)
00244       {
00245         PRInt32 numMessages;
00246         outboxFolder->GetTotalMessages(PR_FALSE, &numMessages);
00247         if (numMessages > 0)
00248         {
00249           identityToUse = thisIdentity;
00250           break;
00251         }
00252       }
00253     }
00254   }
00255        if (identityToUse) 
00256        { 
00257     pMsgSendLater->AddListener(this);
00258     pMsgSendLater->SetMsgWindow(m_window);
00259     rv = pMsgSendLater->SendUnsentMessages(identityToUse);
00260     ShowStatus("sendingUnsent");
00261     // if we succeeded, return - we'll run the next operation when the
00262     // send finishes. Otherwise, advance to the next state.
00263     if (NS_SUCCEEDED(rv))
00264       return rv;
00265        } 
00266        return AdvanceToNextState(rv);
00267 
00268 }
00269 
00270 #define MESSENGER_STRING_URL       "chrome://messenger/locale/messenger.properties"
00271 
00272 nsresult nsMsgOfflineManager::ShowStatus(const char *statusMsgName)
00273 {
00274   nsresult res = NS_OK;
00275   if (!mStringBundle)
00276   {
00277     static const char propertyURL[] = MESSENGER_STRING_URL;
00278 
00279     nsCOMPtr<nsIStringBundleService> sBundleService = 
00280              do_GetService(NS_STRINGBUNDLE_CONTRACTID, &res);
00281     if (NS_SUCCEEDED(res) && (nsnull != sBundleService)) 
00282     {
00283       res = sBundleService->CreateBundle(propertyURL, getter_AddRefs(mStringBundle));
00284     }
00285   }
00286   if (mStringBundle)
00287   {
00288     nsXPIDLString statusString;
00289               res = mStringBundle->GetStringFromName(NS_ConvertASCIItoUCS2(statusMsgName).get(), getter_Copies(statusString));
00290 
00291     if ( NS_SUCCEEDED(res))
00292       OnStatus(statusString);
00293   }
00294   return res;
00295 }
00296 
00297 nsresult nsMsgOfflineManager::DownloadOfflineNewsgroups()
00298 {
00299        nsresult rv;
00300   ShowStatus("downloadingNewsgroups");
00301   nsCOMPtr<nsINntpService> nntpService(do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv));
00302   if (NS_SUCCEEDED(rv) && nntpService)
00303     rv = nntpService->DownloadNewsgroupsForOffline(m_window, this);
00304 
00305   if (NS_FAILED(rv))
00306     return AdvanceToNextState(rv);
00307   return rv;
00308 }
00309 
00310 nsresult nsMsgOfflineManager::DownloadMail()
00311 {
00312   nsresult rv = NS_OK;
00313   ShowStatus("downloadingMail");
00314        nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
00315   NS_ENSURE_SUCCESS(rv, rv);
00316   return imapService->DownloadAllOffineImapFolders(m_window, this);
00317   // ### we should do get new mail on pop servers, and download imap messages for offline use.
00318 }
00319 
00320 /* void goOnline (in boolean sendUnsentMessages, in boolean playbackOfflineImapOperations, in nsIMsgWindow aMsgWindow); */
00321 NS_IMETHODIMP nsMsgOfflineManager::GoOnline(PRBool sendUnsentMessages, PRBool playbackOfflineImapOperations, nsIMsgWindow *aMsgWindow)
00322 {
00323   m_sendUnsentMessages = sendUnsentMessages;
00324   m_playbackOfflineImapOps = playbackOfflineImapOperations;
00325   m_curOperation = eGoingOnline;
00326   m_curState = eNoState;
00327   SetWindow(aMsgWindow);
00328   SetOnlineState(PR_TRUE);
00329   if (!m_sendUnsentMessages && !playbackOfflineImapOperations)
00330     return NS_OK;
00331   else
00332     AdvanceToNextState(NS_OK);
00333   return NS_OK;
00334 }
00335 
00336 /* void synchronizeForOffline (in boolean downloadNews, in boolean downloadMail, in boolean sendUnsentMessages, in boolean goOfflineWhenDone, in nsIMsgWindow aMsgWindow); */
00337 NS_IMETHODIMP nsMsgOfflineManager::SynchronizeForOffline(PRBool downloadNews, PRBool downloadMail, PRBool sendUnsentMessages, PRBool goOfflineWhenDone, nsIMsgWindow *aMsgWindow)
00338 {
00339   m_curOperation = eDownloadingForOffline;
00340   m_downloadNews = downloadNews;
00341   m_downloadMail = downloadMail;
00342   m_sendUnsentMessages = sendUnsentMessages;
00343   SetWindow(aMsgWindow);
00344   m_goOfflineWhenDone = goOfflineWhenDone;
00345   m_curState = eNoState;
00346   if (!downloadNews && !downloadMail && !sendUnsentMessages)
00347   {
00348     if (goOfflineWhenDone)
00349       return SetOnlineState(PR_FALSE);
00350   }
00351   else
00352     return AdvanceToNextState(NS_OK);
00353   return NS_OK;
00354 }
00355 
00356 nsresult nsMsgOfflineManager::SetOnlineState(PRBool online)
00357 {
00358   nsresult rv;
00359   nsCOMPtr<nsIIOService> netService(do_GetService(kIOServiceCID, &rv));
00360   if (NS_SUCCEEDED(rv) && netService)
00361   {
00362     rv = netService->SetOffline(!online);
00363   }
00364   return rv;
00365 }
00366 
00367   // nsIUrlListener methods
00368 
00369 NS_IMETHODIMP
00370 nsMsgOfflineManager::OnStartRunningUrl(nsIURI * aUrl)
00371 {
00372     return NS_OK;
00373 }
00374 
00375 NS_IMETHODIMP
00376 nsMsgOfflineManager::OnStopRunningUrl(nsIURI * aUrl, nsresult aExitCode)
00377 {
00378   mOfflineImapSync = nsnull;
00379 
00380   AdvanceToNextState(aExitCode);
00381   return NS_OK;
00382 }
00383 
00384 NS_IMETHODIMP nsMsgOfflineManager::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00385 {
00386   return NS_OK;
00387 }
00388 
00389 // nsIMsgSendLaterListener implementation 
00390 NS_IMETHODIMP nsMsgOfflineManager::OnStartSending(PRUint32 aTotalMessageCount)
00391 {
00392   return NS_OK;
00393 }
00394 
00395 NS_IMETHODIMP nsMsgOfflineManager::OnProgress(PRUint32 aCurrentMessage, PRUint32 aTotalMessage)
00396 {
00397   if (m_statusFeedback && aTotalMessage)
00398     return m_statusFeedback->ShowProgress ((100 * aCurrentMessage) / aTotalMessage);
00399   else
00400     return NS_OK;
00401 }
00402 
00403 NS_IMETHODIMP nsMsgOfflineManager::OnStatus(const PRUnichar *aMsg)
00404 {
00405   if (m_statusFeedback && aMsg)
00406     return m_statusFeedback->ShowStatusString (aMsg);
00407   else
00408     return NS_OK;
00409 }
00410 
00411 NS_IMETHODIMP nsMsgOfflineManager::OnStopSending(nsresult aStatus, const PRUnichar *aMsg, PRUint32 aTotalTried, 
00412                                  PRUint32 aSuccessful) 
00413 {
00414 #ifdef NS_DEBUG
00415   if (NS_SUCCEEDED(aStatus))
00416     printf("SendLaterListener::OnStopSending: Tried to send %d messages. %d successful.\n",
00417             aTotalTried, aSuccessful);
00418 #endif
00419   return AdvanceToNextState(aStatus);
00420 }