/* 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 hdrA; nsCOMPtr 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 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 hdrA; nsCOMPtr 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 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(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 &aMsgKeyList) { nsresult rv = NS_OK; if (!aMsgKeyList.IsEmpty()) { nsCOMPtr folder = do_QueryReferent(mOwnerFolder, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr database; rv = folder->GetMsgDatabase(getter_AddRefs(database)); if (!database) return NS_ERROR_FAILURE; nsCOMPtr autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr 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 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 &aQueue) { nsresult rv; nsCOMPtr folder = do_QueryReferent(mOwnerFolder, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr database; rv = folder->GetMsgDatabase(getter_AddRefs(database)); if (!database) return NS_ERROR_FAILURE; nsCOMPtr autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr 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 &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 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 folder = do_QueryReferent(mOwnerFolder, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr database; folder->GetMsgDatabase(getter_AddRefs(database)); nsCOMPtr 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 autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); uint32_t msgCount = mDownloadQ.Length(); uint32_t idx = mOffset; nsCOMPtr 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 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 folder = do_QueryReferent(mOwnerFolder, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr 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 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 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 &aMsgKeyList) { SetLastUpdateTime(PR_Now()); if (!aMsgKeyList.IsEmpty()) PlaceIntoDownloadQ(aMsgKeyList); } NS_IMETHODIMP nsAutoSyncState::UpdateFolder() { nsresult rv; nsCOMPtr autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr autoSyncMgrListener = do_QueryInterface(autoSyncMgr, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr 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 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 ownerFolder = do_QueryReferent(mOwnerFolder, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr autoSyncMgr = do_GetService(NS_AUTOSYNCMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr autoSyncMgrListener = do_QueryInterface(autoSyncMgr, &rv); NS_ENSURE_SUCCESS(rv, rv); if (mSyncState == stStatusIssued) { nsCOMPtr 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 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 session = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && session) { nsCOMPtr 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 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 folderA, folderB; rv = GetOwnerFolder(getter_AddRefs(folderA)); NS_ENSURE_SUCCESS(rv,rv); rv = aAnotherStateObj->GetOwnerFolder(getter_AddRefs(folderB)); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr 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 imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv,rv); nsAutoCString messageIds; nsTArray 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 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& q, uint32_t toOffset) { nsCOMPtr ownerFolder = do_QueryReferent(mOwnerFolder); if (ownerFolder) { nsCOMPtr database; ownerFolder->GetMsgDatabase(getter_AddRefs(database)); uint32_t x = q.Length(); while (x > toOffset && database) { x--; nsCOMPtr 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 ownerFolder = do_QueryReferent(mOwnerFolder); if (ownerFolder) { nsCOMPtr database; ownerFolder->GetMsgDatabase(getter_AddRefs(database)); uint32_t x; q->GetLength(&x); while (x > toOffset && database) { x--; nsCOMPtr 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 ownerFolder = do_QueryReferent(mOwnerFolder); if (ownerFolder) { nsCString folderName; ownerFolder->GetURI(folderName); MOZ_LOG(gAutoSyncLog, LogLevel::Debug, ("*** %s Folder: %s ***\n", s, folderName.get())); } }