diff options
Diffstat (limited to 'mailnews/imap/src/nsAutoSyncState.cpp')
-rw-r--r-- | mailnews/imap/src/nsAutoSyncState.cpp | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/mailnews/imap/src/nsAutoSyncState.cpp b/mailnews/imap/src/nsAutoSyncState.cpp new file mode 100644 index 000000000..7b1aeabbe --- /dev/null +++ b/mailnews/imap/src/nsAutoSyncState.cpp @@ -0,0 +1,765 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsAutoSyncState.h" +#include "nsImapMailFolder.h" +#include "nsMsgImapCID.h" +#include "nsIMsgMailNewsUrl.h" +#include "nsMsgKeyArray.h" +#include "nsIMsgWindow.h" +#include "nsIMsgMailSession.h" +#include "nsMsgFolderFlags.h" +#include "nsIAutoSyncManager.h" +#include "nsIAutoSyncMsgStrategy.h" +#include "nsServiceManagerUtils.h" +#include "nsComponentManagerUtils.h" +#include "mozilla/Logging.h" + +using namespace mozilla; + +extern PRLogModuleInfo *gAutoSyncLog; + +MsgStrategyComparatorAdaptor::MsgStrategyComparatorAdaptor(nsIAutoSyncMsgStrategy* aStrategy, + nsIMsgFolder *aFolder, nsIMsgDatabase *aDatabase) : mStrategy(aStrategy), mFolder(aFolder), + mDatabase(aDatabase) +{ +} + +/** @return True if the elements are equals; false otherwise. */ +bool MsgStrategyComparatorAdaptor::Equals(const nsMsgKey& a, const nsMsgKey& b) const +{ + nsCOMPtr<nsIMsgDBHdr> hdrA; + nsCOMPtr<nsIMsgDBHdr> hdrB; + + mDatabase->GetMsgHdrForKey(a, getter_AddRefs(hdrA)); + mDatabase->GetMsgHdrForKey(b, getter_AddRefs(hdrB)); + + if (hdrA && hdrB) + { + nsresult rv = NS_OK; + nsAutoSyncStrategyDecisionType decision = nsAutoSyncStrategyDecisions::Same; + + nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(mFolder); + if (mStrategy) + rv = mStrategy->Sort(folder, hdrA, hdrB, &decision); + + if (NS_SUCCEEDED(rv)) + return (decision == nsAutoSyncStrategyDecisions::Same); + } + + return false; +} + +/** @return True if (a < b); false otherwise. */ +bool MsgStrategyComparatorAdaptor::LessThan(const nsMsgKey& a, const nsMsgKey& b) const +{ + nsCOMPtr<nsIMsgDBHdr> hdrA; + nsCOMPtr<nsIMsgDBHdr> hdrB; + + mDatabase->GetMsgHdrForKey(a, getter_AddRefs(hdrA)); + mDatabase->GetMsgHdrForKey(b, getter_AddRefs(hdrB)); + + if (hdrA && hdrB) + { + nsresult rv = NS_OK; + nsAutoSyncStrategyDecisionType decision = nsAutoSyncStrategyDecisions::Same; + + nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(mFolder); + if (mStrategy) + rv = mStrategy->Sort(folder, hdrA, hdrB, &decision); + + if (NS_SUCCEEDED(rv)) + return (decision == nsAutoSyncStrategyDecisions::Lower); + } + + return false; +} + +nsAutoSyncState::nsAutoSyncState(nsImapMailFolder *aOwnerFolder, PRTime aLastSyncTime) + : mSyncState(stCompletedIdle), mOffset(0U), mLastOffset(0U), mLastServerTotal(0), + mLastServerRecent(0), mLastServerUnseen(0), mLastNextUID(0), + mLastSyncTime(aLastSyncTime), mLastUpdateTime(0UL), mProcessPointer(0U), + mIsDownloadQChanged(false), mRetryCounter(0U) +{ + mOwnerFolder = do_GetWeakReference(static_cast<nsIMsgImapMailFolder*>(aOwnerFolder)); +} + +nsAutoSyncState::~nsAutoSyncState() +{ +} + +// TODO:XXXemre should be implemented when we start +// doing space management +nsresult nsAutoSyncState::ManageStorageSpace() +{ + return NS_OK; +} + +nsresult nsAutoSyncState::PlaceIntoDownloadQ(const nsTArray<nsMsgKey> &aMsgKeyList) +{ + nsresult rv = NS_OK; + if (!aMsgKeyList.IsEmpty()) + { + nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMsgDatabase> database; + rv = folder->GetMsgDatabase(getter_AddRefs(database)); + if (!database) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr<nsIAutoSyncMsgStrategy> msgStrategy; + autoSyncMgr->GetMsgStrategy(getter_AddRefs(msgStrategy)); + + // increase the array size + mDownloadQ.SetCapacity(mDownloadQ.Length() + aMsgKeyList.Length()); + + // remove excluded messages + int32_t elemCount = aMsgKeyList.Length(); + for (int32_t idx = 0; idx < elemCount; idx++) + { + nsCOMPtr<nsIMsgDBHdr> hdr; + bool containsKey; + database->ContainsKey(aMsgKeyList[idx], &containsKey); + if (!containsKey) + continue; + rv = database->GetMsgHdrForKey(aMsgKeyList[idx], getter_AddRefs(hdr)); + if(!hdr) + continue; // can't get message header, continue with the next one + + bool doesFit = true; + rv = autoSyncMgr->DoesMsgFitDownloadCriteria(hdr, &doesFit); + if (NS_SUCCEEDED(rv) && !mDownloadSet.Contains(aMsgKeyList[idx]) && doesFit) + { + bool excluded = false; + if (msgStrategy) + { + rv = msgStrategy->IsExcluded(folder, hdr, &excluded); + + if (NS_SUCCEEDED(rv) && !excluded) + { + mIsDownloadQChanged = true; + mDownloadSet.PutEntry(aMsgKeyList[idx]); + mDownloadQ.AppendElement(aMsgKeyList[idx]); + } + } + } + }//endfor + + if (mIsDownloadQChanged) + { + LogOwnerFolderName("Download Q is created for "); + LogQWithSize(mDownloadQ, 0); + rv = autoSyncMgr->OnDownloadQChanged(this); + } + + } + return rv; +} + +nsresult nsAutoSyncState::SortQueueBasedOnStrategy(nsTArray<nsMsgKey> &aQueue) +{ + nsresult rv; + nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMsgDatabase> database; + rv = folder->GetMsgDatabase(getter_AddRefs(database)); + if (!database) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAutoSyncMsgStrategy> msgStrategy; + rv = autoSyncMgr->GetMsgStrategy(getter_AddRefs(msgStrategy)); + NS_ENSURE_SUCCESS(rv, rv); + + MsgStrategyComparatorAdaptor strategyComp(msgStrategy, folder, database); + aQueue.Sort(strategyComp); + + return rv; +} + +// This method is a hack to prioritize newly inserted messages, +// without changing the size of the queue. It is required since +// we cannot sort ranges in nsTArray. +nsresult nsAutoSyncState::SortSubQueueBasedOnStrategy(nsTArray<nsMsgKey> &aQueue, + uint32_t aStartingOffset) +{ + NS_ASSERTION(aStartingOffset < aQueue.Length(), "*** Starting offset is out of range"); + + // Copy already downloaded messages into a temporary queue, + // we want to exclude them from the sort. + nsTArray<nsMsgKey> tmpQ; + tmpQ.AppendElements(aQueue.Elements(), aStartingOffset); + + // Remove already downloaded messages and sort the resulting queue + aQueue.RemoveElementsAt(0, aStartingOffset); + + nsresult rv = SortQueueBasedOnStrategy(aQueue); + + // copy excluded messages back + aQueue.InsertElementsAt(0, tmpQ); + + return rv; +} + +NS_IMETHODIMP nsAutoSyncState::GetNextGroupOfMessages(uint32_t aSuggestedGroupSizeLimit, + uint32_t *aActualGroupSize, + nsIMutableArray **aMessagesList) +{ + NS_ENSURE_ARG_POINTER(aMessagesList); + NS_ENSURE_ARG_POINTER(aActualGroupSize); + + *aActualGroupSize = 0; + + nsresult rv; + nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMsgDatabase> database; + folder->GetMsgDatabase(getter_AddRefs(database)); + + nsCOMPtr<nsIMutableArray> group = do_CreateInstance(NS_ARRAY_CONTRACTID); + if (database) + { + if (!mDownloadQ.IsEmpty()) + { + // sort the download queue if new items are added since the last time + if (mIsDownloadQChanged) + { + // we want to sort only pending messages. mOffset is + // the position of the first pending message in the download queue + rv = (mOffset > 0) + ? SortSubQueueBasedOnStrategy(mDownloadQ, mOffset) + : SortQueueBasedOnStrategy(mDownloadQ); + + if (NS_SUCCEEDED(rv)) + mIsDownloadQChanged = false; + } + + nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t msgCount = mDownloadQ.Length(); + uint32_t idx = mOffset; + + nsCOMPtr<nsIAutoSyncMsgStrategy> msgStrategy; + autoSyncMgr->GetMsgStrategy(getter_AddRefs(msgStrategy)); + + for (; idx < msgCount; idx++) + { + bool containsKey = false; + database->ContainsKey(mDownloadQ[idx], &containsKey); + if (!containsKey) + { + mDownloadSet.RemoveEntry(mDownloadQ[idx]); + mDownloadQ.RemoveElementAt(idx--); + msgCount--; + continue; + } + nsCOMPtr<nsIMsgDBHdr> qhdr; + database->GetMsgHdrForKey(mDownloadQ[idx], getter_AddRefs(qhdr)); + if(!qhdr) + continue; //maybe deleted, skip it! + + // ensure that we don't have this message body offline already, + // possible if the user explicitly selects this message prior + // to auto-sync kicks in + bool hasMessageOffline; + folder->HasMsgOffline(mDownloadQ[idx], &hasMessageOffline); + if (hasMessageOffline) + continue; + + // this check point allows msg strategy function + // to do last minute decisions based on the current + // state of TB such as the size of the message store etc. + if (msgStrategy) + { + bool excluded = false; + if (NS_SUCCEEDED(msgStrategy->IsExcluded(folder, qhdr, &excluded)) && excluded) + continue; + } + + uint32_t msgSize; + qhdr->GetMessageSize(&msgSize); + // ignore 0 byte messages; the imap parser asserts when we try + // to download them, and there's no point anyway. + if (!msgSize) + continue; + + if (!*aActualGroupSize && msgSize >= aSuggestedGroupSizeLimit) + { + *aActualGroupSize = msgSize; + group->AppendElement(qhdr, false); + idx++; + break; + } + else if ((*aActualGroupSize) + msgSize > aSuggestedGroupSizeLimit) + break; + else + { + group->AppendElement(qhdr, false); + *aActualGroupSize += msgSize; + } + }// endfor + + mLastOffset = mOffset; + mOffset = idx; + } + + LogOwnerFolderName("Next group of messages to be downloaded."); + LogQWithSize(group.get(), 0); + } //endif + + // return it to the caller + NS_IF_ADDREF(*aMessagesList = group); + + return NS_OK; +} + +/** + * Usually called by nsAutoSyncManager when the last sync time is expired. + */ +NS_IMETHODIMP nsAutoSyncState::ProcessExistingHeaders(uint32_t aNumOfHdrsToProcess, uint32_t *aLeftToProcess) +{ + NS_ENSURE_ARG_POINTER(aLeftToProcess); + + nsresult rv; + nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMsgDatabase> database; + rv = folder->GetMsgDatabase(getter_AddRefs(database)); + if (!database) + return NS_ERROR_FAILURE; + + // create a queue to process existing headers for the first time + if (mExistingHeadersQ.IsEmpty()) + { + RefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray; + rv = database->ListAllKeys(keys); + NS_ENSURE_SUCCESS(rv, rv); + keys->Sort(); + mExistingHeadersQ.AppendElements(keys->m_keys); + mProcessPointer = 0; + } + + // process the existing headers and find the messages not downloaded yet + uint32_t lastIdx = mProcessPointer; + nsTArray<nsMsgKey> msgKeys; + uint32_t keyCount = mExistingHeadersQ.Length(); + for (; mProcessPointer < (lastIdx + aNumOfHdrsToProcess) && mProcessPointer < keyCount; mProcessPointer++) + { + bool hasMessageOffline; + folder->HasMsgOffline(mExistingHeadersQ[mProcessPointer], &hasMessageOffline); + if (!hasMessageOffline) + msgKeys.AppendElement(mExistingHeadersQ[mProcessPointer]); + } + if (!msgKeys.IsEmpty()) + { + nsCString folderName; + folder->GetURI(folderName); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, + ("%d messages will be added into the download q of folder %s\n", + msgKeys.Length(), folderName.get())); + + rv = PlaceIntoDownloadQ(msgKeys); + if (NS_FAILED(rv)) + mProcessPointer = lastIdx; + } + + *aLeftToProcess = keyCount - mProcessPointer; + + // cleanup if we are done processing + if (0 == *aLeftToProcess) + { + mLastSyncTime = PR_Now(); + mExistingHeadersQ.Clear(); + mProcessPointer = 0; + folder->SetMsgDatabase(nullptr); + } + + return rv; +} + +void nsAutoSyncState::OnNewHeaderFetchCompleted(const nsTArray<nsMsgKey> &aMsgKeyList) +{ + SetLastUpdateTime(PR_Now()); + if (!aMsgKeyList.IsEmpty()) + PlaceIntoDownloadQ(aMsgKeyList); +} + +NS_IMETHODIMP nsAutoSyncState::UpdateFolder() +{ + nsresult rv; + nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIUrlListener> autoSyncMgrListener = do_QueryInterface(autoSyncMgr, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryReferent(mOwnerFolder, &rv); + SetState(nsAutoSyncState::stUpdateIssued); + return imapFolder->UpdateFolderWithListener(nullptr, autoSyncMgrListener); +} + +NS_IMETHODIMP nsAutoSyncState::OnStartRunningUrl(nsIURI* aUrl) +{ + nsresult rv = NS_OK; + + // if there is a problem to start the download, set rv with the + // corresponding error code. In that case, AutoSyncManager is going to + // set the autosync state to nsAutoSyncState::stReadyToDownload + // to resume downloading another time + + // TODO: is there a way to make sure that download started without + // problem through nsIURI interface? + + nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return autoSyncMgr->OnDownloadStarted(this, rv); +} + +NS_IMETHODIMP nsAutoSyncState::OnStopRunningUrl(nsIURI* aUrl, nsresult aExitCode) +{ + nsresult rv; + nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIAutoSyncManager> autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIUrlListener> autoSyncMgrListener = do_QueryInterface(autoSyncMgr, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + if (mSyncState == stStatusIssued) + { + nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + int32_t serverTotal, serverUnseen, serverRecent, serverNextUID; + imapFolder->GetServerTotal(&serverTotal); + imapFolder->GetServerUnseen(&serverUnseen); + imapFolder->GetServerRecent(&serverRecent); + imapFolder->GetServerNextUID(&serverNextUID); + if (serverNextUID != mLastNextUID || serverTotal != mLastServerTotal || + serverUnseen != mLastServerUnseen || serverRecent != mLastServerRecent) + { + nsCString folderName; + ownerFolder->GetURI(folderName); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, + ("folder %s status changed serverNextUID = %lx lastNextUID = %lx\n", folderName.get(), + serverNextUID, mLastNextUID)); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, + ("serverTotal = %lx lastServerTotal = %lx serverRecent = %lx lastServerRecent = %lx\n", + serverTotal, mLastServerTotal, serverRecent, mLastServerRecent)); + SetServerCounts(serverTotal, serverRecent, serverUnseen, serverNextUID); + SetState(nsAutoSyncState::stUpdateIssued); + return imapFolder->UpdateFolderWithListener(nullptr, autoSyncMgrListener); + } + else + { + ownerFolder->SetMsgDatabase(nullptr); + // nothing more to do. + SetState(nsAutoSyncState::stCompletedIdle); + // autoSyncMgr needs this notification, so manufacture it. + return autoSyncMgrListener->OnStopRunningUrl(nullptr, NS_OK); + } + } + //XXXemre how we recover from this error? + rv = ownerFolder->ReleaseSemaphore(ownerFolder); + NS_ASSERTION(NS_SUCCEEDED(rv), "*** Cannot release folder semaphore"); + + nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(aUrl); + if (mailUrl) + rv = mailUrl->UnRegisterListener(this); + + return autoSyncMgr->OnDownloadCompleted(this, aExitCode); +} + +NS_IMETHODIMP nsAutoSyncState::GetState(int32_t *aState) +{ + NS_ENSURE_ARG_POINTER(aState); + *aState = mSyncState; + return NS_OK; +} + +const char *stateStrings[] = {"idle", "status issued", "update needed", + "update issued", "downloading", + "ready to download"}; + +NS_IMETHODIMP nsAutoSyncState::SetState(int32_t aState) +{ + mSyncState = aState; + if (aState == stCompletedIdle) + { + ResetDownloadQ(); + //tell folder to let go of its cached msg db pointer + nsresult rv; + nsCOMPtr<nsIMsgMailSession> session = + do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv) && session) + { + nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + bool folderOpen; + uint32_t folderFlags; + ownerFolder->GetFlags(&folderFlags); + session->IsFolderOpenInWindow(ownerFolder, &folderOpen); + if (!folderOpen && ! (folderFlags & nsMsgFolderFlags::Inbox)) + ownerFolder->SetMsgDatabase(nullptr); + } + } + nsCString logStr("Sync State set to "); + logStr.Append(stateStrings[aState]); + logStr.Append(" for "); + LogOwnerFolderName(logStr.get()); + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::TryCurrentGroupAgain(uint32_t aRetryCount) +{ + SetState(stReadyToDownload); + + nsresult rv; + if (++mRetryCounter > aRetryCount) + { + ResetRetryCounter(); + rv = NS_ERROR_FAILURE; + } + else + rv = Rollback(); + + return rv; +} + +NS_IMETHODIMP nsAutoSyncState::ResetRetryCounter() +{ + mRetryCounter = 0; + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::GetPendingMessageCount(int32_t *aMsgCount) +{ + NS_ENSURE_ARG_POINTER(aMsgCount); + *aMsgCount = mDownloadQ.Length() - mOffset; + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::GetTotalMessageCount(int32_t *aMsgCount) +{ + NS_ENSURE_ARG_POINTER(aMsgCount); + *aMsgCount = mDownloadQ.Length(); + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::GetOwnerFolder(nsIMsgFolder **aFolder) +{ + NS_ENSURE_ARG_POINTER(aFolder); + + nsresult rv; + nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + NS_IF_ADDREF(*aFolder = ownerFolder); + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::Rollback() +{ + mOffset = mLastOffset; + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::ResetDownloadQ() +{ + mOffset = mLastOffset = 0; + mDownloadSet.Clear(); + mDownloadQ.Clear(); + mDownloadQ.Compact(); + + return NS_OK; +} + +/** + * Tests whether the given folder is owned by the same imap server + * or not. + */ +NS_IMETHODIMP nsAutoSyncState::IsSibling(nsIAutoSyncState *aAnotherStateObj, bool *aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = false; + + nsresult rv; + nsCOMPtr<nsIMsgFolder> folderA, folderB; + + rv = GetOwnerFolder(getter_AddRefs(folderA)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = aAnotherStateObj->GetOwnerFolder(getter_AddRefs(folderB)); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr <nsIMsgIncomingServer> serverA, serverB; + rv = folderA->GetServer(getter_AddRefs(serverA)); + NS_ENSURE_SUCCESS(rv,rv); + rv = folderB->GetServer(getter_AddRefs(serverB)); + NS_ENSURE_SUCCESS(rv,rv); + + bool isSibling; + rv = serverA->Equals(serverB, &isSibling); + + if (NS_SUCCEEDED(rv)) + *aResult = isSibling; + + return rv; +} + + +NS_IMETHODIMP nsAutoSyncState::DownloadMessagesForOffline(nsIArray *aMessagesList) +{ + NS_ENSURE_ARG_POINTER(aMessagesList); + + uint32_t count; + nsresult rv = aMessagesList->GetLength(&count); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsAutoCString messageIds; + nsTArray<nsMsgKey> msgKeys; + + rv = nsImapMailFolder::BuildIdsAndKeyArray(aMessagesList, messageIds, msgKeys); + if (NS_FAILED(rv) || messageIds.IsEmpty()) + return rv; + + // acquire semaphore for offline store. If it fails, we won't download + nsCOMPtr <nsIMsgFolder> folder = do_QueryReferent(mOwnerFolder, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = folder->AcquireSemaphore(folder); + NS_ENSURE_SUCCESS(rv, rv); + + nsCString folderName; + folder->GetURI(folderName); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("downloading %s for %s", messageIds.get(), + folderName.get())); + // start downloading + rv = imapService->DownloadMessagesForOffline(messageIds, + folder, + this, + nullptr); + if (NS_SUCCEEDED(rv)) + SetState(stDownloadInProgress); + + return rv; +} + +NS_IMETHODIMP nsAutoSyncState::GetLastSyncTime(PRTime *aLastSyncTime) +{ + NS_ENSURE_ARG_POINTER(aLastSyncTime); + *aLastSyncTime = mLastSyncTime; + return NS_OK; +} + +void nsAutoSyncState::SetLastSyncTimeInSec(int32_t aLastSyncTime) +{ + mLastSyncTime = ((PRTime)aLastSyncTime * PR_USEC_PER_SEC); +} + + +NS_IMETHODIMP nsAutoSyncState::GetLastUpdateTime(PRTime *aLastUpdateTime) +{ + NS_ENSURE_ARG_POINTER(aLastUpdateTime); + *aLastUpdateTime = mLastUpdateTime; + return NS_OK; +} + +NS_IMETHODIMP nsAutoSyncState::SetLastUpdateTime(PRTime aLastUpdateTime) +{ + mLastUpdateTime = aLastUpdateTime; + return NS_OK; +} + +void nsAutoSyncState::SetServerCounts(int32_t total, int32_t recent, + int32_t unseen, int32_t nextUID) +{ + mLastServerTotal = total; + mLastServerRecent = recent; + mLastServerUnseen = unseen; + mLastNextUID = nextUID; +} + +NS_IMPL_ISUPPORTS(nsAutoSyncState, nsIAutoSyncState, nsIUrlListener) + + +void nsAutoSyncState::LogQWithSize(nsTArray<nsMsgKey>& q, uint32_t toOffset) +{ + nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder); + if (ownerFolder) + { + nsCOMPtr<nsIMsgDatabase> database; + ownerFolder->GetMsgDatabase(getter_AddRefs(database)); + + uint32_t x = q.Length(); + while (x > toOffset && database) + { + x--; + nsCOMPtr<nsIMsgDBHdr> h; + database->GetMsgHdrForKey(q[x], getter_AddRefs(h)); + uint32_t s; + if (h) + { + h->GetMessageSize(&s); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, + ("Elem #%d, size: %u bytes\n", x+1, s)); + } + else + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("unable to get header for key %ul", q[x])); + } + } +} + +void nsAutoSyncState::LogQWithSize(nsIMutableArray *q, uint32_t toOffset) +{ + nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder); + if (ownerFolder) + { + nsCOMPtr<nsIMsgDatabase> database; + ownerFolder->GetMsgDatabase(getter_AddRefs(database)); + + uint32_t x; + q->GetLength(&x); + while (x > toOffset && database) + { + x--; + nsCOMPtr<nsIMsgDBHdr> h; + q->QueryElementAt(x, NS_GET_IID(nsIMsgDBHdr), + getter_AddRefs(h)); + uint32_t s; + if (h) + { + h->GetMessageSize(&s); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, + ("Elem #%d, size: %u bytes\n", x+1, s)); + } + else + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("null header in q at index %ul", x)); + } + } +} + +void nsAutoSyncState::LogOwnerFolderName(const char *s) +{ + nsCOMPtr <nsIMsgFolder> ownerFolder = do_QueryReferent(mOwnerFolder); + if (ownerFolder) + { + nsCString folderName; + ownerFolder->GetURI(folderName); + MOZ_LOG(gAutoSyncLog, LogLevel::Debug, + ("*** %s Folder: %s ***\n", s, folderName.get())); + } +} |