// this is used for Send without UI nsresult nsMapiHook::BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields) { nsresult rv = NS_OK ; if (!IsBlindSendAllowed()) return NS_ERROR_FAILURE; /** create nsIMsgComposeParams obj and other fields to populate it **/ nsCOMPtr<nsIDOMWindow> hiddenWindow; // get parent window nsCOMPtr<nsIAppShellService> appService = do_GetService( "@mozilla.org/appshell/appShellService;1", &rv); if (NS_FAILED(rv)|| (!appService) ) return rv ; rv = appService->GetHiddenDOMWindow(getter_AddRefs(hiddenWindow)); if ( NS_FAILED(rv) ) return rv ; // smtp password and Logged in used IdKey from MapiConfig (session obj) nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ; if (!pMapiConfig) return NS_ERROR_FAILURE ; // get the singelton obj PRUnichar * password = pMapiConfig->GetPassword(aSession) ; // password nsCAutoString smtpPassword; LossyCopyUTF16toASCII(password, smtpPassword); // Id key nsCString MsgIdKey; pMapiConfig->GetIdKey(aSession, MsgIdKey); // get the MsgIdentity for the above key using AccountManager nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ; if (NS_FAILED(rv) || (!accountManager) ) return rv ; nsCOMPtr <nsIMsgIdentity> pMsgId ; rv = accountManager->GetIdentity (MsgIdKey, getter_AddRefs(pMsgId)) ; if (NS_FAILED(rv) ) return rv ; // create a send listener to get back the send status nsCOMPtr <nsIMsgSendListener> sendListener ; rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; if (NS_FAILED(rv) || (!sendListener) ) return rv; // create the compose params object nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv)); if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ; // populate the compose params bool forcePlainText; aCompFields->GetForcePlainText(&forcePlainText); pMsgComposeParams->SetType(nsIMsgCompType::New); pMsgComposeParams->SetFormat(forcePlainText ? nsIMsgCompFormat::PlainText : nsIMsgCompFormat::HTML); pMsgComposeParams->SetIdentity(pMsgId); pMsgComposeParams->SetComposeFields(aCompFields); pMsgComposeParams->SetSendListener(sendListener) ; pMsgComposeParams->SetSmtpPassword(smtpPassword.get()); // create the nsIMsgCompose object to send the object nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv)); if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ; /** initialize nsIMsgCompose, Send the message, wait for send completion response **/ rv = pMsgCompose->Initialize(pMsgComposeParams, hiddenWindow, nsnull); if (NS_FAILED(rv)) return rv ; // If we're in offline mode, we'll need to queue it for later. No point in trying to send it. return pMsgCompose->SendMsg(WeAreOffline() ? nsIMsgSend::nsMsgQueueForLater : nsIMsgSend::nsMsgDeliverNow, pMsgId, nsnull, nsnull, nsnull); if (NS_FAILED(rv)) return rv ; // assign to interface pointer from nsCOMPtr to facilitate typecast below nsIMsgSendListener * pSendListener = sendListener ; // we need to wait here to make sure that we return only after send is completed // so we will have a event loop here which will process the events till the Send IsDone. nsCOMPtr<nsIThread> thread(do_GetCurrentThread()); while ( !((nsMAPISendListener *) pSendListener)->IsDone() ) { PR_CEnterMonitor(pSendListener); PR_CWait(pSendListener, PR_MicrosecondsToInterval(1000UL)); PR_CExitMonitor(pSendListener); NS_ProcessPendingEvents(thread); } return rv ; }
NS_IMETHODIMP nsImapOfflineTxn::RedoTransaction(void) { nsresult rv; nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv); if (NS_FAILED(rv) || !srcFolder) return rv; nsCOMPtr <nsIMsgOfflineImapOperation> op; nsCOMPtr <nsIDBFolderInfo> folderInfo; nsCOMPtr <nsIMsgDatabase> srcDB; nsCOMPtr <nsIMsgDatabase> destDB; rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB)); NS_ENSURE_SUCCESS(rv, rv); nsMsgKey hdrKey = nsMsgKey_None; switch (m_opType) { case nsIMsgOfflineImapOperation::kMsgMoved: case nsIMsgOfflineImapOperation::kMsgCopy: for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { nsMsgKey hdrKey; m_srcHdrs[i]->GetMessageKey(&hdrKey); rv = srcDB->GetOfflineOpForKey(hdrKey, false, getter_AddRefs(op)); if (NS_SUCCEEDED(rv) && op) { nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv); if (dstFolder) { nsCString folderURI; dstFolder->GetURI(folderURI); if (m_opType == nsIMsgOfflineImapOperation::kMsgMoved) op->SetDestinationFolderURI(folderURI.get()); // offline move if (m_opType == nsIMsgOfflineImapOperation::kMsgCopy) { op->SetOperation(nsIMsgOfflineImapOperation::kMsgMoved); op->AddMessageCopyOperation(folderURI.get()); // offline copy } dstFolder->SummaryChanged(); } } else if (!WeAreOffline()) { // couldn't find offline op - it must have been played back already // so we should redo the transaction online. return nsImapMoveCopyMsgTxn::RedoTransaction(); } } break; case nsIMsgOfflineImapOperation::kAddedHeader: { nsCOMPtr<nsIMsgFolder> dstFolder = do_QueryReferent(m_dstFolder, &rv); rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(destDB)); NS_ENSURE_SUCCESS(rv, rv); for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { nsCOMPtr<nsIMsgDBHdr> restoreHdr; nsMsgKey msgKey; m_srcHdrs[i]->GetMessageKey(&msgKey); destDB->CopyHdrFromExistingHdr (msgKey, m_srcHdrs[i], true, getter_AddRefs(restoreHdr)); rv = destDB->GetOfflineOpForKey(msgKey, true, getter_AddRefs(op)); if (NS_SUCCEEDED(rv) && op) { nsCString folderURI; srcFolder->GetURI(folderURI); op->SetSourceFolderURI(folderURI.get()); } } dstFolder->SummaryChanged(); destDB->Close(true); } break; case nsIMsgOfflineImapOperation::kDeletedMsg: for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { nsMsgKey msgKey; m_srcHdrs[i]->GetMessageKey(&msgKey); srcDB->DeleteMessage(msgKey, nullptr, true); } break; case nsIMsgOfflineImapOperation::kMsgMarkedDeleted: for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { nsMsgKey msgKey; m_srcHdrs[i]->GetMessageKey(&msgKey); srcDB->MarkImapDeleted(msgKey, true, nullptr); } break; case nsIMsgOfflineImapOperation::kFlagsChanged: for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { nsMsgKey msgKey; m_srcHdrs[i]->GetMessageKey(&msgKey); rv = srcDB->GetOfflineOpForKey(msgKey, true, getter_AddRefs(op)); if (NS_SUCCEEDED(rv) && op) { imapMessageFlagsType newMsgFlags; op->GetNewFlags(&newMsgFlags); if (m_addFlags) op->SetFlagOperation(newMsgFlags | m_flags); else op->SetFlagOperation(newMsgFlags & ~m_flags); } } break; default: break; } srcDB->Close(true); srcDB = nullptr; srcFolder->SummaryChanged(); return NS_OK; }
// Open the database and find the key for the offline operation that we want to // undo, then remove it from the database, we also hold on to this // data for a redo operation. NS_IMETHODIMP nsImapOfflineTxn::UndoTransaction(void) { nsresult rv; nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv); if (NS_FAILED(rv) || !srcFolder) return rv; nsCOMPtr <nsIMsgOfflineImapOperation> op; nsCOMPtr <nsIDBFolderInfo> folderInfo; nsCOMPtr <nsIMsgDatabase> srcDB; nsCOMPtr <nsIMsgDatabase> destDB; nsMsgKey hdrKey = nsMsgKey_None; if (m_header) m_header->GetMessageKey(&hdrKey); rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB)); NS_ENSURE_SUCCESS(rv, rv); switch (m_opType) { case nsIMsgOfflineImapOperation::kMsgMoved: case nsIMsgOfflineImapOperation::kMsgCopy: case nsIMsgOfflineImapOperation::kAddedHeader: case nsIMsgOfflineImapOperation::kFlagsChanged: { rv = srcDB->GetOfflineOpForKey(hdrKey, PR_FALSE, getter_AddRefs(op)); PRBool offlineOpPlayedBack = PR_TRUE; if (NS_SUCCEEDED(rv) && op) { op->GetPlayingBack(&offlineOpPlayedBack); srcDB->RemoveOfflineOp(op); op = nsnull; } if (!WeAreOffline() && offlineOpPlayedBack) { // couldn't find offline op - it must have been played back already // so we should undo the transaction online. return nsImapMoveCopyMsgTxn::UndoTransaction(); } if (m_header && (m_opType == nsIMsgOfflineImapOperation::kAddedHeader)) { nsCOMPtr <nsIMsgDBHdr> mailHdr; nsMsgKey msgKey; m_header->GetMessageKey(&msgKey); rv = srcDB->GetMsgHdrForKey(msgKey, getter_AddRefs(mailHdr)); if (mailHdr) srcDB->DeleteHeader(mailHdr, nsnull, PR_TRUE, PR_FALSE); } break; } case nsIMsgOfflineImapOperation::kDeletedMsg: { nsMsgKey msgKey; m_header->GetMessageKey(&msgKey); nsCOMPtr<nsIMsgDBHdr> undeletedHdr; m_srcHdrs->QueryElementAt(0, NS_GET_IID(nsIMsgDBHdr), getter_AddRefs(undeletedHdr)); if (undeletedHdr) { nsCOMPtr<nsIMsgDBHdr> newHdr; srcDB->CopyHdrFromExistingHdr (msgKey, undeletedHdr, PR_TRUE, getter_AddRefs(newHdr)); } srcDB->Close(PR_TRUE); srcFolder->SummaryChanged(); } break; case nsIMsgOfflineImapOperation::kMsgMarkedDeleted: srcDB->MarkImapDeleted(hdrKey, PR_FALSE, nsnull); break; default: break; } srcDB->Close(PR_TRUE); srcFolder->SummaryChanged(); return NS_OK; }
// Open the database and find the key for the offline operation that we want to // undo, then remove it from the database, we also hold on to this // data for a redo operation. NS_IMETHODIMP nsImapOfflineTxn::UndoTransaction(void) { nsresult rv; nsCOMPtr<nsIMsgFolder> srcFolder = do_QueryReferent(m_srcFolder, &rv); if (NS_FAILED(rv) || !srcFolder) return rv; nsCOMPtr <nsIMsgOfflineImapOperation> op; nsCOMPtr <nsIDBFolderInfo> folderInfo; nsCOMPtr <nsIMsgDatabase> srcDB; nsCOMPtr <nsIMsgDatabase> destDB; rv = srcFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(srcDB)); NS_ENSURE_SUCCESS(rv, rv); switch (m_opType) { case nsIMsgOfflineImapOperation::kMsgMoved: case nsIMsgOfflineImapOperation::kMsgCopy: case nsIMsgOfflineImapOperation::kAddedHeader: case nsIMsgOfflineImapOperation::kFlagsChanged: case nsIMsgOfflineImapOperation::kDeletedMsg: { if (m_srcHdrs.Count() == 0) { NS_ASSERTION(false, "No msg header to apply undo."); break; } nsCOMPtr<nsIMsgDBHdr> firstHdr = m_srcHdrs[0]; nsMsgKey hdrKey; firstHdr->GetMessageKey(&hdrKey); rv = srcDB->GetOfflineOpForKey(hdrKey, false, getter_AddRefs(op)); bool offlineOpPlayedBack = true; if (NS_SUCCEEDED(rv) && op) { op->GetPlayingBack(&offlineOpPlayedBack); srcDB->RemoveOfflineOp(op); op = nullptr; } if (!WeAreOffline() && offlineOpPlayedBack) { // couldn't find offline op - it must have been played back already // so we should undo the transaction online. return nsImapMoveCopyMsgTxn::UndoTransaction(); } if (!firstHdr) break; nsMsgKey msgKey; if (m_opType == nsIMsgOfflineImapOperation::kAddedHeader) { for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { m_srcHdrs[i]->GetMessageKey(&msgKey); nsCOMPtr<nsIMsgDBHdr> mailHdr; rv = srcDB->GetMsgHdrForKey(msgKey, getter_AddRefs(mailHdr)); if (mailHdr) srcDB->DeleteHeader(mailHdr, nullptr, false, false); } srcDB->Commit(true); } else if (m_opType == nsIMsgOfflineImapOperation::kDeletedMsg) { for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { nsCOMPtr<nsIMsgDBHdr> undeletedHdr = m_srcHdrs[i]; m_srcHdrs[i]->GetMessageKey(&msgKey); if (undeletedHdr) { nsCOMPtr<nsIMsgDBHdr> newHdr; srcDB->CopyHdrFromExistingHdr (msgKey, undeletedHdr, true, getter_AddRefs(newHdr)); } } srcDB->Close(true); srcFolder->SummaryChanged(); } break; } case nsIMsgOfflineImapOperation::kMsgMarkedDeleted: { nsMsgKey msgKey; for (int32_t i = 0; i < m_srcHdrs.Count(); i++) { m_srcHdrs[i]->GetMessageKey(&msgKey); srcDB->MarkImapDeleted(msgKey, false, nullptr); } } break; default: break; } srcDB->Close(true); srcFolder->SummaryChanged(); return NS_OK; }
nsresult nsMsgSendLater::InternalSendMessages(bool aUserInitiated, nsIMsgIdentity *aIdentity) { if (WeAreOffline()) return NS_MSG_ERROR_OFFLINE; // Protect against being called whilst we're already sending. if (mSendingMessages) { NS_ERROR("nsMsgSendLater is already sending messages\n"); return NS_ERROR_FAILURE; } 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(nullptr, getter_AddRefs(mMessageFolder)); NS_ENSURE_SUCCESS(rv, rv); } nsCOMPtr<nsIMsgDatabase> unsentDB; // Remember these in case we need to reparse the db. mUserInitiated = aUserInitiated; mIdentity = aIdentity; rv = ReparseDBIfNeeded(this); NS_ENSURE_SUCCESS(rv, rv); mIdentity = nullptr; // don't hold onto the identity since we're a service. nsCOMPtr<nsISimpleEnumerator> enumerator; rv = mMessageFolder->GetMessages(getter_AddRefs(enumerator)); NS_ENSURE_SUCCESS(rv, rv); // copy all the elements in the enumerator into our isupports array.... nsCOMPtr<nsISupports> currentItem; nsCOMPtr<nsIMsgDBHdr> messageHeader; bool hasMoreElements = false; while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && hasMoreElements) { rv = enumerator->GetNext(getter_AddRefs(currentItem)); if (NS_SUCCEEDED(rv)) { messageHeader = do_QueryInterface(currentItem, &rv); if (NS_SUCCEEDED(rv)) { if (aUserInitiated) // If the user initiated the send, add all messages mMessagesToSend.AppendObject(messageHeader); else { // Else just send those that are NOT marked as Queued. uint32_t flags; rv = messageHeader->GetFlags(&flags); if (NS_SUCCEEDED(rv) && !(flags & nsMsgMessageFlags::Queued)) mMessagesToSend.AppendObject(messageHeader); } } } } // Now get an enumerator for our array. rv = NS_NewArrayEnumerator(getter_AddRefs(mEnumerator), mMessagesToSend); NS_ENSURE_SUCCESS(rv, rv); // We're now sending messages so its time to signal that and reset our counts. mSendingMessages = true; mTotalSentSuccessfully = 0; mTotalSendCount = 0; // Notify the listeners that we are starting a send. NotifyListenersOnStartSending(mMessagesToSend.Count()); return StartNextMailFileSend(NS_OK); }