Part of bug 440794 - Leverage Offline capabilities to make sending email appear faster - protect against shutting down whilst sending email when quit-application-requested has not been received. r/sr=bienvenu
This commit is contained in:
Родитель
f635ec258d
Коммит
0f0f5d8063
|
@ -55,6 +55,8 @@
|
|||
#include "nsIWindowMediator.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIMsgMailNewsUrl.h"
|
||||
#include "prcmon.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsMsgMailSession)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsMsgMailSession)
|
||||
|
@ -525,17 +527,28 @@ nsMsgMailSession::GetDataFilesDir(const char* dirName, nsIFile **dataFilesDir)
|
|||
NS_IMPL_ISUPPORTS3(nsMsgShutdownService, nsIMsgShutdownService, nsIUrlListener, nsIObserver)
|
||||
|
||||
nsMsgShutdownService::nsMsgShutdownService()
|
||||
: mProcessedShutdown(PR_FALSE),
|
||||
mQuitForced(PR_FALSE),
|
||||
mReadyToQuit(PR_FALSE)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
|
||||
if (observerService)
|
||||
{
|
||||
observerService->AddObserver(this, "quit-application-requested", PR_FALSE);
|
||||
observerService->AddObserver(this, "quit-application-granted", PR_FALSE);
|
||||
observerService->AddObserver(this, "quit-application", PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
nsMsgShutdownService::~nsMsgShutdownService()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
|
||||
if (observerService)
|
||||
{
|
||||
observerService->RemoveObserver(this, "quit-application-requested");
|
||||
observerService->RemoveObserver(this, "quit-application-granted");
|
||||
observerService->RemoveObserver(this, "quit-application");
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsMsgShutdownService::ProcessNextTask()
|
||||
|
@ -578,11 +591,22 @@ nsresult nsMsgShutdownService::ProcessNextTask()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsMsgShutdownService::AttemptShutdown()
|
||||
void nsMsgShutdownService::AttemptShutdown()
|
||||
{
|
||||
nsCOMPtr<nsIAppStartup> appStartup = do_GetService(NS_APPSTARTUP_CONTRACTID);
|
||||
NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
|
||||
return appStartup->Quit(nsIAppStartup::eAttemptQuit);
|
||||
if (mQuitForced)
|
||||
{
|
||||
PR_CEnterMonitor(this);
|
||||
mReadyToQuit = PR_TRUE;
|
||||
PR_CNotifyAll(this);
|
||||
PR_CExitMonitor(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIAppStartup> appStartup =
|
||||
do_GetService(NS_APPSTARTUP_CONTRACTID);
|
||||
NS_ENSURE_TRUE(appStartup, );
|
||||
NS_ENSURE_SUCCESS(appStartup->Quit(nsIAppStartup::eAttemptQuit), );
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgShutdownService::SetShutdownListener(nsIWebProgressListener *inListener)
|
||||
|
@ -596,6 +620,27 @@ NS_IMETHODIMP nsMsgShutdownService::Observe(nsISupports *aSubject,
|
|||
const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
// Due to bug 459376 we don't always get quit-application-requested and
|
||||
// quit-application-granted. quit-application-requested is preferred, but if
|
||||
// we don't then we have to hook onto quit-application, but we don't want
|
||||
// to do the checking twice so we set some flags to prevent that.
|
||||
if (!strcmp(aTopic, "quit-application-granted"))
|
||||
{
|
||||
// Quit application has been requested and granted, therefore we will shut
|
||||
// down.
|
||||
mProcessedShutdown = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we've already processed a shutdown notification, no need to do it again.
|
||||
if (!strcmp(aTopic, "quit-application"))
|
||||
{
|
||||
if (mProcessedShutdown)
|
||||
return NS_OK;
|
||||
else
|
||||
mQuitForced = PR_TRUE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
|
||||
NS_ENSURE_STATE(observerService);
|
||||
|
||||
|
@ -624,7 +669,7 @@ NS_IMETHODIMP nsMsgShutdownService::Observe(nsISupports *aSubject,
|
|||
|
||||
listenerEnum->HasMoreElements(&hasMore);
|
||||
}
|
||||
|
||||
|
||||
if (mShutdownTasks.Count() < 1)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -657,13 +702,31 @@ NS_IMETHODIMP nsMsgShutdownService::Observe(nsISupports *aSubject,
|
|||
NS_ENSURE_TRUE(internalDomWin, NS_ERROR_FAILURE); // bail if we don't get a window.
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsPRBool> stopShutdown = do_QueryInterface(aSubject);
|
||||
stopShutdown->SetData(PR_TRUE);
|
||||
|
||||
|
||||
if (!mQuitForced)
|
||||
{
|
||||
nsCOMPtr<nsISupportsPRBool> stopShutdown = do_QueryInterface(aSubject);
|
||||
stopShutdown->SetData(PR_TRUE);
|
||||
}
|
||||
|
||||
mMsgProgress->OpenProgressDialog(internalDomWin, topMsgWindow,
|
||||
"chrome://messenger/content/shutdownWindow.xul",
|
||||
PR_FALSE, nsnull);
|
||||
|
||||
if (mQuitForced)
|
||||
{
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
|
||||
mReadyToQuit = PR_FALSE;
|
||||
while (!mReadyToQuit)
|
||||
{
|
||||
PR_CEnterMonitor(this);
|
||||
// Waiting for 50 milliseconds
|
||||
PR_CWait(this, PR_MicrosecondsToInterval(50000UL));
|
||||
PR_CExitMonitor(this);
|
||||
NS_ProcessPendingEvents(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -700,7 +763,8 @@ NS_IMETHODIMP nsMsgShutdownService::StartShutdownTasks()
|
|||
|
||||
NS_IMETHODIMP nsMsgShutdownService::CancelShutdownTasks()
|
||||
{
|
||||
return AttemptShutdown();
|
||||
AttemptShutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgShutdownService::SetStatusText(const nsAString & inStatusString)
|
||||
|
|
|
@ -122,12 +122,15 @@ public:
|
|||
|
||||
protected:
|
||||
nsresult ProcessNextTask();
|
||||
nsresult AttemptShutdown();
|
||||
void AttemptShutdown();
|
||||
|
||||
private:
|
||||
nsCOMArray<nsIMsgShutdownTask> mShutdownTasks;
|
||||
nsCOMPtr<nsIMsgProgress> mMsgProgress;
|
||||
PRUint32 mTaskIndex;
|
||||
PRPackedBool mProcessedShutdown;
|
||||
PRPackedBool mQuitForced;
|
||||
PRPackedBool mReadyToQuit;
|
||||
};
|
||||
|
||||
#endif /* nsMsgMailSession_h__ */
|
||||
|
|
|
@ -50,8 +50,8 @@ interface nsIMsgFolder;
|
|||
* can be sent by calling sendUnsentMessages.
|
||||
*
|
||||
* Although the service supports passing identities as parameters, until bug
|
||||
* 317803 is fixed, all identities use the same folder, and hence currently it
|
||||
* has no effect.
|
||||
* 317803 is fixed, all identities use the same folder, and hence the option
|
||||
* currently doesn't work.
|
||||
*/
|
||||
[scriptable, uuid(fa324a4b-4b87-4e9a-a3c0-af9071a358df)]
|
||||
interface nsIMsgSendLater : nsIStreamListener
|
||||
|
|
|
@ -133,6 +133,9 @@ nsMsgSendLater::Init()
|
|||
do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = observerService->AddObserver(this, "xpcom-shutdown", PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = observerService->AddObserver(this, "quit-application", PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -140,11 +143,12 @@ nsMsgSendLater::Init()
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Subscribe to the unsent messages folder
|
||||
nsCOMPtr<nsIMsgFolder> unsentFolder;
|
||||
rv = GetUnsentMessagesFolder(nsnull, getter_AddRefs(unsentFolder));
|
||||
// XXX This code should be set up for multiple unsent folders, however we
|
||||
// don't support that at the moment, so for now just assume one folder.
|
||||
rv = GetUnsentMessagesFolder(nsnull, getter_AddRefs(mMessageFolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = unsentFolder->AddFolderListener(this);
|
||||
rv = mMessageFolder->AddFolderListener(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXX may want to send messages X seconds after startup if there are any.
|
||||
|
@ -170,22 +174,34 @@ nsMsgSendLater::Observe(nsISupports *aSubject, const char* aTopic,
|
|||
InternalSendMessages(PR_FALSE, nsnull);
|
||||
}
|
||||
else if (!strcmp(aTopic, "quit-application"))
|
||||
{
|
||||
// If the timer is set, cancel it - we're quitting, the shutdown service
|
||||
// interfaces will sort out sending etc.
|
||||
if (mTimer)
|
||||
mTimer->Cancel();
|
||||
|
||||
mTimerSet = PR_FALSE;
|
||||
}
|
||||
else if (!strcmp(aTopic, "xpcom-shutdown"))
|
||||
{
|
||||
// We're shutting down. Unsubscribe from the unsentFolder notifications
|
||||
// they aren't any use to us now, we don't want to start sending more
|
||||
// messages.
|
||||
nsCOMPtr<nsIMsgFolder> unsentFolder;
|
||||
nsresult rv = GetUnsentMessagesFolder(nsnull, getter_AddRefs(unsentFolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = unsentFolder->RemoveFolderListener(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv;
|
||||
if (mMessageFolder)
|
||||
{
|
||||
rv = mMessageFolder->RemoveFolderListener(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Now remove ourselves from the observer service as well.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = observerService->RemoveObserver(this, "xpcom-shutdown");
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = observerService->RemoveObserver(this, "quit-application");
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -659,6 +675,9 @@ nsMsgSendLater::StartNextMailFileSend()
|
|||
if (!mMessage)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (!mMessageFolder)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
mMessageFolder->GetUriForMsg(mMessage, messageURI);
|
||||
|
||||
rv = nsMsgCreateTempFile("nsqmail.tmp", getter_AddRefs(mTempFile));
|
||||
|
@ -707,13 +726,19 @@ NS_IMETHODIMP
|
|||
nsMsgSendLater::HasUnsentMessages(nsIMsgIdentity *aIdentity, PRBool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIMsgFolder> msgFolder;
|
||||
nsresult rv = GetUnsentMessagesFolder(aIdentity, getter_AddRefs(msgFolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// XXX This code should be set up for multiple unsent folders, however we
|
||||
// don't support that at the moment, so for now just assume one folder.
|
||||
if (!mMessageFolder)
|
||||
{
|
||||
rv = GetUnsentMessagesFolder(nsnull,
|
||||
getter_AddRefs(mMessageFolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
PRInt32 totalMessages;
|
||||
rv = msgFolder->GetTotalMessages(PR_FALSE, &totalMessages);
|
||||
rv = mMessageFolder->GetTotalMessages(PR_FALSE, &totalMessages);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = totalMessages > 0;
|
||||
|
@ -760,9 +785,16 @@ nsMsgSendLater::InternalSendMessages(PRBool aUserInitiated,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = GetUnsentMessagesFolder(aIdentity,
|
||||
getter_AddRefs(mMessageFolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv;
|
||||
|
||||
// XXX This code should be set up for multiple unsent folders, however we
|
||||
// don't support that at the moment, so for now just assume one folder.
|
||||
if (!mMessageFolder)
|
||||
{
|
||||
rv = GetUnsentMessagesFolder(nsnull,
|
||||
getter_AddRefs(mMessageFolder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// ### fix me - if we need to reparse the folder, this will be asynchronous
|
||||
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
||||
|
@ -867,7 +899,11 @@ nsMsgSendLater::DeleteCurrentMessage()
|
|||
if (!msgArray)
|
||||
return NS_ERROR_FACTORY_NOT_LOADED;
|
||||
|
||||
if (!mMessageFolder)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
msgArray->InsertElementAt(mMessage, 0, PR_FALSE);
|
||||
|
||||
nsresult res = mMessageFolder->DeleteMessages(msgArray, nsnull, PR_TRUE, PR_FALSE, nsnull, PR_FALSE /*allowUndo*/);
|
||||
if (NS_FAILED(res))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1283,6 +1319,14 @@ nsMsgSendLater::EndSendMessages(nsresult aStatus, const PRUnichar *aMsg,
|
|||
// Clear out our array of messages.
|
||||
mMessagesToSend.Clear();
|
||||
|
||||
// We don't need to keep hold of the database now we've finished sending.
|
||||
(void)mMessageFolder->SetMsgDatabase(nsnull);
|
||||
|
||||
// or the enumerator, temp file or output stream
|
||||
mEnumerator = nsnull;
|
||||
mTempFile = nsnull;
|
||||
mOutFile = nsnull;
|
||||
|
||||
NOTIFY_LISTENERS(OnStopSending, (aStatus, aMsg, aTotalTried, aSuccessful));
|
||||
|
||||
// If we've got a shutdown listener, notify it that we've finished.
|
||||
|
|
Загрузка…
Ссылка в новой задаче