NS_IMETHODIMP nsMessengerBootstrap::OpenMessengerWindowWithUri(const char *windowType, const char * aFolderURI, nsMsgKey aMessageKey) { bool standAloneMsgWindow = false; nsCAutoString chromeUrl("chrome://messenger/content/"); if (windowType && !strcmp(windowType, "mail:messageWindow")) { chromeUrl.Append("messageWindow.xul"); standAloneMsgWindow = true; } nsCOMPtr<nsISupportsArray> argsArray; nsresult rv = NS_NewISupportsArray(getter_AddRefs(argsArray)); NS_ENSURE_SUCCESS(rv, rv); // create scriptable versions of our strings that we can store in our nsISupportsArray.... if (aFolderURI) { if (standAloneMsgWindow) { nsCOMPtr <nsIMsgFolder> folder; rv = GetExistingFolder(nsDependentCString(aFolderURI), getter_AddRefs(folder)); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString msgUri; folder->GetBaseMessageURI(msgUri); nsCOMPtr<nsISupportsCString> scriptableMsgURI (do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableMsgURI, NS_ERROR_FAILURE); msgUri.Append('#'); msgUri.AppendInt(aMessageKey, 10); scriptableMsgURI->SetData(msgUri); argsArray->AppendElement(scriptableMsgURI); } nsCOMPtr<nsISupportsCString> scriptableFolderURI (do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableFolderURI, NS_ERROR_FAILURE); scriptableFolderURI->SetData(nsDependentCString(aFolderURI)); argsArray->AppendElement(scriptableFolderURI); if (!standAloneMsgWindow) { nsCOMPtr<nsISupportsPRUint32> scriptableMessageKey (do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID)); NS_ENSURE_TRUE(scriptableMessageKey, NS_ERROR_FAILURE); scriptableMessageKey->SetData(aMessageKey); argsArray->AppendElement(scriptableMessageKey); } } nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); // we need to use the "mailnews.reuse_thread_window2" pref // to determine if we should open a new window, or use an existing one. nsCOMPtr<nsIDOMWindow> newWindow; return wwatch->OpenWindow(0, chromeUrl.get(), "_blank", "chrome,all,dialog=no", argsArray, getter_AddRefs(newWindow)); }
NS_IMETHODIMP nsSpamSettings::OnStopRunningUrl(nsIURI* aURL, nsresult exitCode) { nsCString junkFolderURI; nsresult rv = GetSpamFolderURI(getter_Copies(junkFolderURI)); NS_ENSURE_SUCCESS(rv,rv); if (junkFolderURI.IsEmpty()) return NS_ERROR_UNEXPECTED; // when we get here, the folder should exist. nsCOMPtr <nsIMsgFolder> junkFolder; rv = GetExistingFolder(junkFolderURI, getter_AddRefs(junkFolder)); NS_ENSURE_SUCCESS(rv,rv); if (!junkFolder) return NS_ERROR_UNEXPECTED; rv = junkFolder->SetFlag(nsMsgFolderFlags::Junk); NS_ENSURE_SUCCESS(rv,rv); return rv; }
nsresult nsSpamSettings::UpdateJunkFolderState() { nsresult rv; // if the spam folder uri changed on us, we need to unset the junk flag // on the old spam folder nsCString newJunkFolderURI; rv = GetSpamFolderURI(getter_Copies(newJunkFolderURI)); NS_ENSURE_SUCCESS(rv, rv); if (!mCurrentJunkFolderURI.IsEmpty() && !mCurrentJunkFolderURI.Equals(newJunkFolderURI)) { nsCOMPtr<nsIMsgFolder> oldJunkFolder; rv = GetExistingFolder(mCurrentJunkFolderURI, getter_AddRefs(oldJunkFolder)); if (NS_SUCCEEDED(rv) && oldJunkFolder) { // remove the nsMsgFolderFlags::Junk on the old junk folder // XXX TODO // JUNK MAIL RELATED // (in ClearFlag?) we need to make sure that this folder // is not the junk folder for another account // the same goes for set flag. have fun with all that. oldJunkFolder->ClearFlag(nsMsgFolderFlags::Junk); } } mCurrentJunkFolderURI = newJunkFolderURI; // only try to create the junk folder if we are moving junk // and we have a non-empty uri if (mMoveOnSpam && !mCurrentJunkFolderURI.IsEmpty()) { // as the url listener, the spam settings will set the nsMsgFolderFlags::Junk folder flag // on the junk mail folder, after it is created rv = GetOrCreateFolder(mCurrentJunkFolderURI, this); } return rv; }
// This is the function that looks for the first folder to purge. It also // applies retention settings to any folder that hasn't had retention settings // applied in mMinDelayBetweenPurges minutes (default, 8 hours). // However, if we've spent more than .5 seconds in this loop, don't // apply any more retention settings because it might lock up the UI. // This might starve folders later on in the hierarchy, since we always // start at the top, but since we also apply retention settings when you // open a folder, or when you compact all folders, I think this will do // for now, until we have a cleanup on shutdown architecture. nsresult nsMsgPurgeService::PerformPurge() { PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("performing purge")); nsresult rv; nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv,rv); bool keepApplyingRetentionSettings = true; nsCOMPtr<nsISupportsArray> allServers; rv = accountManager->GetAllServers(getter_AddRefs(allServers)); if (NS_SUCCEEDED(rv) && allServers) { PRUint32 numServers; rv = allServers->Count(&numServers); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%d servers", numServers)); nsCOMPtr<nsIMsgFolder> folderToPurge; PRIntervalTime startTime = PR_IntervalNow(); PRInt32 purgeIntervalToUse; PRTime oldestPurgeTime = 0; // we're going to pick the least-recently purged folder // apply retention settings to folders that haven't had retention settings // applied in mMinDelayBetweenPurges minutes (default 8 hours) // Because we get last purge time from the folder cache, // this code won't open db's for folders until it decides it needs // to apply retention settings, and since nsIMsgFolder::ApplyRetentionSettings // will close any db's it opens, this code won't leave db's open. for (PRUint32 serverIndex=0; serverIndex < numServers; serverIndex++) { nsCOMPtr <nsIMsgIncomingServer> server = do_QueryElementAt(allServers, serverIndex, &rv); if (NS_SUCCEEDED(rv) && server) { if (keepApplyingRetentionSettings) { nsCOMPtr <nsIMsgFolder> rootFolder; rv = server->GetRootFolder(getter_AddRefs(rootFolder)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr <nsISupportsArray> childFolders = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = rootFolder->ListDescendents(childFolders); PRUint32 cnt = 0; childFolders->Count(&cnt); nsCOMPtr<nsISupports> supports; nsCOMPtr<nsIUrlListener> urlListener; nsCOMPtr<nsIMsgFolder> childFolder; for (PRUint32 index = 0; index < cnt; index++) { childFolder = do_QueryElementAt(childFolders, index); if (childFolder) { PRUint32 folderFlags; (void) childFolder->GetFlags(&folderFlags); if (folderFlags & nsMsgFolderFlags::Virtual) continue; PRTime curFolderLastPurgeTime = 0; nsCString curFolderLastPurgeTimeString, curFolderUri; rv = childFolder->GetStringProperty("LastPurgeTime", curFolderLastPurgeTimeString); if (NS_FAILED(rv)) continue; // it is ok to fail, go on to next folder if (!curFolderLastPurgeTimeString.IsEmpty()) { PRInt64 theTime; PR_ParseTimeString(curFolderLastPurgeTimeString.get(), PR_FALSE, &theTime); curFolderLastPurgeTime = theTime; } childFolder->GetURI(curFolderUri); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("%s curFolderLastPurgeTime=%s (if blank, then never)", curFolderUri.get(), curFolderLastPurgeTimeString.get())); // check if this folder is due to purge // has to have been purged at least mMinDelayBetweenPurges minutes ago // we don't want to purge the folders all the time - once a day is good enough PRInt64 minDelayBetweenPurges(mMinDelayBetweenPurges); PRInt64 microSecondsPerMinute(60000000); PRTime nextPurgeTime = curFolderLastPurgeTime + (minDelayBetweenPurges * microSecondsPerMinute); if (nextPurgeTime < PR_Now()) { PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("purging %s", curFolderUri.get())); childFolder->ApplyRetentionSettings(); } PRIntervalTime elapsedTime; LL_SUB(elapsedTime, PR_IntervalNow(), startTime); // check if more than 500 milliseconds have elapsed in this purge process if (PR_IntervalToMilliseconds(elapsedTime) > 500) { keepApplyingRetentionSettings = PR_FALSE; break; } } } } nsCString type; nsresult rv = server->GetType(type); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString contractid(NS_MSGPROTOCOLINFO_CONTRACTID_PREFIX); contractid.Append(type); nsCOMPtr<nsIMsgProtocolInfo> protocolInfo = do_GetService(contractid.get(), &rv); NS_ENSURE_SUCCESS(rv, PR_FALSE); nsCString realHostName; server->GetRealHostName(realHostName); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s (%s)", serverIndex, realHostName.get(), type.get())); nsCOMPtr <nsISpamSettings> spamSettings; rv = server->GetSpamSettings(getter_AddRefs(spamSettings)); NS_ENSURE_SUCCESS(rv, rv); PRInt32 spamLevel; spamSettings->GetLevel(&spamLevel); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] spamLevel=%d (if 0, don't purge)", serverIndex, spamLevel)); if (!spamLevel) continue; // check if we are set up to purge for this server // if not, skip it. bool purgeSpam; spamSettings->GetPurge(&purgeSpam); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purgeSpam=%s (if false, don't purge)", serverIndex, purgeSpam ? "true" : "false")); if (!purgeSpam) continue; // check if the spam folder uri is set for this server // if not skip it. nsCString junkFolderURI; rv = spamSettings->GetSpamFolderURI(getter_Copies(junkFolderURI)); NS_ENSURE_SUCCESS(rv,rv); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] junkFolderURI=%s (if empty, don't purge)", serverIndex, junkFolderURI.get())); if (junkFolderURI.IsEmpty()) continue; // if the junk folder doesn't exist // because the folder pane isn't built yet, for example // skip this account nsCOMPtr<nsIMsgFolder> junkFolder; GetExistingFolder(junkFolderURI, getter_AddRefs(junkFolder)); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s exists? %s (if doesn't exist, don't purge)", serverIndex, junkFolderURI.get(), junkFolder ? "true" : "false")); if (!junkFolder) continue; PRTime curJunkFolderLastPurgeTime = 0; nsCString curJunkFolderLastPurgeTimeString; rv = junkFolder->GetStringProperty("curJunkFolderLastPurgeTime", curJunkFolderLastPurgeTimeString); if (NS_FAILED(rv)) continue; // it is ok to fail, junk folder may not exist if (!curJunkFolderLastPurgeTimeString.IsEmpty()) { PRInt64 theTime; PR_ParseTimeString(curJunkFolderLastPurgeTimeString.get(), PR_FALSE, &theTime); curJunkFolderLastPurgeTime = theTime; } PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] %s curJunkFolderLastPurgeTime=%s (if blank, then never)", serverIndex, junkFolderURI.get(), curJunkFolderLastPurgeTimeString.get())); // check if this account is due to purge // has to have been purged at least mMinDelayBetweenPurges minutes ago // we don't want to purge the folders all the time PRTime nextPurgeTime = curJunkFolderLastPurgeTime + mMinDelayBetweenPurges * 60000000 /* convert mMinDelayBetweenPurges to into microseconds */; if (nextPurgeTime < PR_Now()) { PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge greater than min delay", serverIndex)); nsCOMPtr <nsIMsgIncomingServer> junkFolderServer; rv = junkFolder->GetServer(getter_AddRefs(junkFolderServer)); NS_ENSURE_SUCCESS(rv,rv); bool serverBusy = false; bool serverRequiresPassword = true; bool passwordPromptRequired; bool canSearchMessages = false; junkFolderServer->GetPasswordPromptRequired(&passwordPromptRequired); junkFolderServer->GetServerBusy(&serverBusy); junkFolderServer->GetServerRequiresPasswordForBiff(&serverRequiresPassword); junkFolderServer->GetCanSearchMessages(&canSearchMessages); // Make sure we're logged on before doing the search (assuming we need to be) // and make sure the server isn't already in the middle of downloading new messages // and make sure a search isn't already going on PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (search in progress? %s)", serverIndex, mSearchSession ? "true" : "false")); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (server busy? %s)", serverIndex, serverBusy ? "true" : "false")); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (serverRequiresPassword? %s)", serverIndex, serverRequiresPassword ? "true" : "false")); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] (passwordPromptRequired? %s)", serverIndex, passwordPromptRequired ? "true" : "false")); if (canSearchMessages && !mSearchSession && !serverBusy && (!serverRequiresPassword || !passwordPromptRequired)) { PRInt32 purgeInterval; spamSettings->GetPurgeInterval(&purgeInterval); if ((oldestPurgeTime == 0) || (curJunkFolderLastPurgeTime < oldestPurgeTime)) { PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] purging! searching for messages older than %d days", serverIndex, purgeInterval)); oldestPurgeTime = curJunkFolderLastPurgeTime; purgeIntervalToUse = purgeInterval; folderToPurge = junkFolder; // if we've never purged this folder, do it... if (curJunkFolderLastPurgeTime == 0) break; } } else { NS_ASSERTION(canSearchMessages, "unexpected, you should be able to search"); PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] not a good time for this server, try again later", serverIndex)); } } else { PR_LOG(MsgPurgeLogModule, PR_LOG_ALWAYS, ("[%d] last purge too recent", serverIndex)); } } } if (folderToPurge) rv = SearchFolderToPurge(folderToPurge, purgeIntervalToUse); } // set up timer to check accounts again SetupNextPurge(); return rv; }
void nsImapOfflineSync::ProcessCopyOperation(nsIMsgOfflineImapOperation *currentOp) { nsTArray<nsMsgKey> matchingFlagKeys; PRUint32 currentKeyIndex = m_KeyIndex; nsCString copyDestination; currentOp->GetCopyDestination(0, getter_Copies(copyDestination)); PRBool copyMatches = PR_TRUE; do { // loop for all messsages with the same destination if (copyMatches) { nsMsgKey curKey; currentOp->GetMessageKey(&curKey); matchingFlagKeys.AppendElement(curKey); currentOp->SetPlayingBack(PR_TRUE); m_currentOpsToClear.AppendObject(currentOp); } currentOp = nsnull; if (++currentKeyIndex < m_CurrentKeys.Length()) { nsCString nextDestination; nsresult rv = m_currentDB->GetOfflineOpForKey(m_CurrentKeys[currentKeyIndex], PR_FALSE, ¤tOp); copyMatches = PR_FALSE; if (NS_SUCCEEDED(rv) && currentOp) { nsOfflineImapOperationType opType; currentOp->GetOperation(&opType); if (opType & nsIMsgOfflineImapOperation::kMsgCopy) { currentOp->GetCopyDestination(0, getter_Copies(nextDestination)); copyMatches = copyDestination.Equals(nextDestination); } } } } while (currentOp); nsCAutoString uids; nsCOMPtr<nsIMsgFolder> destFolder; GetExistingFolder(copyDestination, getter_AddRefs(destFolder)); // if the dest folder doesn't really exist, these operations are // going to fail, so clear them out and move on. if (!destFolder) { NS_ERROR("trying to playing back copy to non-existent folder"); ClearCurrentOps(); ProcessNextOperation(); return; } nsresult rv; nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(m_currentFolder); if (imapFolder && DestFolderOnSameServer(destFolder)) { rv = imapFolder->ReplayOfflineMoveCopy(matchingFlagKeys.Elements(), matchingFlagKeys.Length(), PR_FALSE, destFolder, this, m_window); } else { nsCOMPtr<nsIMutableArray> messages(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv)); if (messages && NS_SUCCEEDED(rv)) { for (PRUint32 keyIndex = 0; keyIndex < matchingFlagKeys.Length(); keyIndex++) { nsCOMPtr<nsIMsgDBHdr> mailHdr = nsnull; rv = m_currentFolder->GetMessageHeader(matchingFlagKeys.ElementAt(keyIndex), getter_AddRefs(mailHdr)); if (NS_SUCCEEDED(rv) && mailHdr) { messages->AppendElement(mailHdr, PR_FALSE); } } nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv); if (copyService) copyService->CopyMessages(m_currentFolder, messages, destFolder, PR_FALSE, this, m_window, PR_FALSE); } } }
void nsImapOfflineSync::ProcessMoveOperation(nsIMsgOfflineImapOperation *op) { nsTArray<nsMsgKey> matchingFlagKeys; PRUint32 currentKeyIndex = m_KeyIndex; nsCString moveDestination; op->GetDestinationFolderURI(getter_Copies(moveDestination)); PRBool moveMatches = PR_TRUE; nsCOMPtr <nsIMsgOfflineImapOperation> currentOp = op; do { // loop for all messsages with the same destination if (moveMatches) { nsMsgKey curKey; currentOp->GetMessageKey(&curKey); matchingFlagKeys.AppendElement(curKey); currentOp->SetPlayingBack(PR_TRUE); m_currentOpsToClear.AppendObject(currentOp); } currentOp = nsnull; if (++currentKeyIndex < m_CurrentKeys.Length()) { nsCString nextDestination; nsresult rv = m_currentDB->GetOfflineOpForKey(m_CurrentKeys[currentKeyIndex], PR_FALSE, getter_AddRefs(currentOp)); moveMatches = PR_FALSE; if (NS_SUCCEEDED(rv) && currentOp) { nsOfflineImapOperationType opType; currentOp->GetOperation(&opType); if (opType & nsIMsgOfflineImapOperation::kMsgMoved) { currentOp->GetDestinationFolderURI(getter_Copies(nextDestination)); moveMatches = moveDestination.Equals(nextDestination); } } } } while (currentOp); nsCOMPtr<nsIMsgFolder> destFolder; GetExistingFolder(moveDestination, getter_AddRefs(destFolder)); // if the dest folder doesn't really exist, these operations are // going to fail, so clear them out and move on. if (!destFolder) { NS_ERROR("trying to playing back move to non-existent folder"); ClearCurrentOps(); ProcessNextOperation(); return; } nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(m_currentFolder); if (imapFolder && DestFolderOnSameServer(destFolder)) { imapFolder->ReplayOfflineMoveCopy(matchingFlagKeys.Elements(), matchingFlagKeys.Length(), PR_TRUE, destFolder, this, m_window); } else { nsresult rv; nsCOMPtr<nsIMutableArray> messages(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { for (PRUint32 keyIndex = 0; keyIndex < matchingFlagKeys.Length(); keyIndex++) { nsCOMPtr<nsIMsgDBHdr> mailHdr = nsnull; rv = m_currentFolder->GetMessageHeader(matchingFlagKeys.ElementAt(keyIndex), getter_AddRefs(mailHdr)); if (NS_SUCCEEDED(rv) && mailHdr) { PRUint32 msgSize; // in case of a move, the header has already been deleted, // so we've really got a fake header. We need to get its flags and // size from the offline op to have any chance of doing the move. mailHdr->GetMessageSize(&msgSize); if (!msgSize) { imapMessageFlagsType newImapFlags; PRUint32 msgFlags = 0; op->GetMsgSize(&msgSize); op->GetNewFlags(&newImapFlags); // first three bits are the same msgFlags |= (newImapFlags & 0x07); if (newImapFlags & kImapMsgForwardedFlag) msgFlags |= nsMsgMessageFlags::Forwarded; mailHdr->SetFlags(msgFlags); mailHdr->SetMessageSize(msgSize); } messages->AppendElement(mailHdr, PR_FALSE); } } nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv); if (copyService) copyService->CopyMessages(m_currentFolder, messages, destFolder, PR_TRUE, this, m_window, PR_FALSE); } } }