diff options
Diffstat (limited to 'mailnews/mapi/mapihook/src/msgMapiHook.cpp')
-rw-r--r-- | mailnews/mapi/mapihook/src/msgMapiHook.cpp | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/mailnews/mapi/mapihook/src/msgMapiHook.cpp b/mailnews/mapi/mapihook/src/msgMapiHook.cpp new file mode 100644 index 000000000..02696fe94 --- /dev/null +++ b/mailnews/mapi/mapihook/src/msgMapiHook.cpp @@ -0,0 +1,829 @@ +/* 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/. */ + +#define MAPI_STARTUP_ARG "/MAPIStartUp" + +#include <mapidefs.h> +#include <mapi.h> +#include <tchar.h> +#include <direct.h> +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsISupports.h" +#include "nsIPromptService.h" +#include "nsIAppStartup.h" +#include "nsIAppShellService.h" +#include "mozIDOMWindow.h" +#include "nsINativeAppSupport.h" +#include "nsIMsgAccountManager.h" +#include "nsMsgBaseCID.h" +#include "nsIStringBundle.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsStringGlue.h" +#include "nsUnicharUtils.h" +#include "nsIMsgAttachment.h" +#include "nsIMsgCompFields.h" +#include "nsIMsgComposeParams.h" +#include "nsIMsgCompose.h" +#include "nsMsgCompCID.h" +#include "nsIMsgSend.h" +#include "nsIMsgComposeService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIDirectoryService.h" +#include "nsMsgI18N.h" +#include "msgMapi.h" +#include "msgMapiHook.h" +#include "msgMapiSupport.h" +#include "msgMapiMain.h" +#include "nsThreadUtils.h" +#include "nsMsgUtils.h" +#include "nsNetUtil.h" +#include "mozilla/Services.h" +#include "nsIArray.h" +#include "nsArrayUtils.h" +#include "nsEmbedCID.h" +#include "mozilla/Logging.h" + +extern PRLogModuleInfo *MAPI; + +class nsMAPISendListener : public nsIMsgSendListener +{ +public: + + // nsISupports interface + NS_DECL_THREADSAFE_ISUPPORTS + + /* void OnStartSending (in string aMsgID, in uint32_t aMsgSize); */ + NS_IMETHOD OnStartSending(const char *aMsgID, uint32_t aMsgSize) { return NS_OK; } + + /* void OnProgress (in string aMsgID, in uint32_t aProgress, in uint32_t aProgressMax); */ + NS_IMETHOD OnProgress(const char *aMsgID, uint32_t aProgress, uint32_t aProgressMax) { return NS_OK;} + + /* void OnStatus (in string aMsgID, in wstring aMsg); */ + NS_IMETHOD OnStatus(const char *aMsgID, const char16_t *aMsg) { return NS_OK;} + + /* void OnStopSending (in string aMsgID, in nsresult aStatus, in wstring aMsg, in nsIFile returnFile); */ + NS_IMETHOD OnStopSending(const char *aMsgID, nsresult aStatus, const char16_t *aMsg, + nsIFile *returnFile) { + PR_CEnterMonitor(this); + PR_CNotifyAll(this); + m_done = true; + PR_CExitMonitor(this); + return NS_OK ; + } + + /* void OnSendNotPerformed */ + NS_IMETHOD OnSendNotPerformed(const char *aMsgID, nsresult aStatus) + { + return OnStopSending(aMsgID, aStatus, nullptr, nullptr) ; + } + + /* void OnGetDraftFolderURI (); */ + NS_IMETHOD OnGetDraftFolderURI(const char *aFolderURI) {return NS_OK;} + + static nsresult CreateMAPISendListener( nsIMsgSendListener **ppListener); + + bool IsDone() { return m_done ; } + +protected : + nsMAPISendListener() { + m_done = false; + } + + bool m_done; +private: + virtual ~nsMAPISendListener() { } + +}; + + +NS_IMPL_ISUPPORTS(nsMAPISendListener, nsIMsgSendListener) + +nsresult nsMAPISendListener::CreateMAPISendListener( nsIMsgSendListener **ppListener) +{ + NS_ENSURE_ARG_POINTER(ppListener) ; + + *ppListener = new nsMAPISendListener(); + if (! *ppListener) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*ppListener); + return NS_OK; +} + +bool nsMapiHook::isMapiService = false; + +void nsMapiHook::CleanUp() +{ + // This routine will be fully implemented in future + // to cleanup mapi related stuff inside mozilla code. +} + +bool nsMapiHook::DisplayLoginDialog(bool aLogin, char16_t **aUsername, + char16_t **aPassword) +{ + nsresult rv; + bool btnResult = false; + + nsCOMPtr<nsIPromptService> dlgService(do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv) && dlgService) + { + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + if (!bundleService) return false; + + nsCOMPtr<nsIStringBundle> bundle; + rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle)); + if (NS_FAILED(rv) || !bundle) return false; + + nsCOMPtr<nsIStringBundle> brandBundle; + rv = bundleService->CreateBundle( + "chrome://branding/locale/brand.properties", + getter_AddRefs(brandBundle)); + if (NS_FAILED(rv)) return false; + + nsString brandName; + rv = brandBundle->GetStringFromName( + u"brandFullName", + getter_Copies(brandName)); + if (NS_FAILED(rv)) return false; + + nsString loginTitle; + const char16_t *brandStrings[] = { brandName.get() }; + NS_NAMED_LITERAL_STRING(loginTitlePropertyTag, "loginTitle"); + const char16_t *dTitlePropertyTag = loginTitlePropertyTag.get(); + rv = bundle->FormatStringFromName(dTitlePropertyTag, brandStrings, 1, + getter_Copies(loginTitle)); + if (NS_FAILED(rv)) return false; + + if (aLogin) + { + nsString loginText; + rv = bundle->GetStringFromName(u"loginTextwithName", + getter_Copies(loginText)); + if (NS_FAILED(rv) || loginText.IsEmpty()) return false; + + bool dummyValue = false; + rv = dlgService->PromptUsernameAndPassword(nullptr, loginTitle.get(), + loginText.get(), aUsername, aPassword, + nullptr, &dummyValue, &btnResult); + } + else + { + //nsString loginString; + nsString loginText; + const char16_t *userNameStrings[] = { *aUsername }; + + NS_NAMED_LITERAL_STRING(loginTextPropertyTag, "loginText"); + const char16_t *dpropertyTag = loginTextPropertyTag.get(); + rv = bundle->FormatStringFromName(dpropertyTag, userNameStrings, 1, + getter_Copies(loginText)); + if (NS_FAILED(rv)) return false; + + bool dummyValue = false; + rv = dlgService->PromptPassword(nullptr, loginTitle.get(), loginText.get(), + aPassword, nullptr, &dummyValue, &btnResult); + } + } + + return btnResult; +} + +bool nsMapiHook::VerifyUserName(const nsString& aUsername, nsCString& aIdKey) +{ + nsresult rv; + + if (aUsername.IsEmpty()) + return false; + + nsCOMPtr<nsIMsgAccountManager> accountManager(do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) return false; + nsCOMPtr<nsIArray> identities; + rv = accountManager->GetAllIdentities(getter_AddRefs(identities)); + if (NS_FAILED(rv)) return false; + + uint32_t numIndentities = 0; + identities->GetLength(&numIndentities); + + for (uint32_t i = 0; i < numIndentities; i++) + { + nsCOMPtr<nsIMsgIdentity> thisIdentity(do_QueryElementAt(identities, i, &rv)); + if (NS_SUCCEEDED(rv) && thisIdentity) + { + nsCString email; + rv = thisIdentity->GetEmail(email); + if (NS_FAILED(rv)) continue; + + // get the username from the email and compare with the username + int32_t index = email.FindChar('@'); + if (index != -1) + email.SetLength(index); + + if (aUsername.Equals(NS_ConvertASCIItoUTF16(email))) + return NS_SUCCEEDED(thisIdentity->GetKey(aIdKey)); + } + } + + return false; +} + +bool +nsMapiHook::IsBlindSendAllowed() +{ + bool enabled = false; + bool warn = true; + nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefBranch) { + prefBranch->GetBoolPref(PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND, &warn); + prefBranch->GetBoolPref(PREF_MAPI_BLIND_SEND_ENABLED, &enabled); + } + if (!enabled) + return false; + + if (!warn) + return true; // Everything is okay. + + nsresult rv; + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + if (!bundleService) return false; + + nsCOMPtr<nsIStringBundle> bundle; + rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle)); + if (NS_FAILED(rv) || !bundle) return false; + + nsString warningMsg; + rv = bundle->GetStringFromName(u"mapiBlindSendWarning", + getter_Copies(warningMsg)); + if (NS_FAILED(rv)) return false; + + nsString dontShowAgainMessage; + rv = bundle->GetStringFromName(u"mapiBlindSendDontShowAgain", + getter_Copies(dontShowAgainMessage)); + if (NS_FAILED(rv)) return false; + + nsCOMPtr<nsIPromptService> dlgService(do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv) || !dlgService) return false; + + bool continueToWarn = true; + bool okayToContinue = false; + dlgService->ConfirmCheck(nullptr, nullptr, warningMsg.get(), dontShowAgainMessage.get(), &continueToWarn, &okayToContinue); + + if (!continueToWarn && okayToContinue && prefBranch) + prefBranch->SetBoolPref(PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND, false); + + return okayToContinue; +} + +// 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<mozIDOMWindowProxy> 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 + char16_t * password = pMapiConfig->GetPassword(aSession) ; + // password + nsAutoCString 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, nullptr); + 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, nullptr, nullptr, nullptr); + 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 ; +} + +// this is used to populate comp fields with Unicode data +nsresult nsMapiHook::PopulateCompFields(lpnsMapiMessage aMessage, + nsIMsgCompFields * aCompFields) +{ + nsresult rv = NS_OK ; + + if (aMessage->lpOriginator) + aCompFields->SetFrom (NS_ConvertASCIItoUTF16((char *) aMessage->lpOriginator->lpszAddress)); + + nsAutoString To ; + nsAutoString Cc ; + nsAutoString Bcc ; + + NS_NAMED_LITERAL_STRING(Comma, ","); + + if (aMessage->lpRecips) + { + for (int i=0 ; i < (int) aMessage->nRecipCount ; i++) + { + if (aMessage->lpRecips[i].lpszAddress || aMessage->lpRecips[i].lpszName) + { + const char *addressWithoutType = (aMessage->lpRecips[i].lpszAddress) + ? aMessage->lpRecips[i].lpszAddress : aMessage->lpRecips[i].lpszName; + if (!PL_strncasecmp(addressWithoutType, "SMTP:", 5)) + addressWithoutType += 5; + switch (aMessage->lpRecips[i].ulRecipClass) + { + case MAPI_TO : + if (!To.IsEmpty()) + To += Comma; + To.Append(NS_ConvertASCIItoUTF16(addressWithoutType)); + break; + + case MAPI_CC : + if (!Cc.IsEmpty()) + Cc += Comma; + Cc.Append(NS_ConvertASCIItoUTF16(addressWithoutType)); + break; + + case MAPI_BCC : + if (!Bcc.IsEmpty()) + Bcc += Comma; + Bcc.Append(NS_ConvertASCIItoUTF16(addressWithoutType)); + break; + } + } + } + } + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("to: %s cc: %s bcc: %s \n", NS_ConvertUTF16toUTF8(To).get(), NS_ConvertUTF16toUTF8(Cc).get(), NS_ConvertUTF16toUTF8(Bcc).get())); + // set To, Cc, Bcc + aCompFields->SetTo (To) ; + aCompFields->SetCc (Cc) ; + aCompFields->SetBcc (Bcc) ; + + // set subject + if (aMessage->lpszSubject) + aCompFields->SetSubject(NS_ConvertASCIItoUTF16(aMessage->lpszSubject)); + + // handle attachments as File URL + rv = HandleAttachments (aCompFields, aMessage->nFileCount, aMessage->lpFiles, true) ; + if (NS_FAILED(rv)) return rv ; + + // set body + if (aMessage->lpszNoteText) + { + nsString Body; + CopyASCIItoUTF16(aMessage->lpszNoteText, Body); + if (Body.IsEmpty() || Body.Last() != '\n') + Body.AppendLiteral(CRLF); + + // This is needed when Simple MAPI is used without a compose window. + // See bug 1366196. + if (Body.Find("<html>") == kNotFound) + aCompFields->SetForcePlainText(true); + + rv = aCompFields->SetBody(Body) ; + } + return rv ; +} + +nsresult nsMapiHook::HandleAttachments (nsIMsgCompFields * aCompFields, int32_t aFileCount, + lpnsMapiFileDesc aFiles, BOOL aIsUnicode) +{ + nsresult rv = NS_OK ; + + nsAutoCString Attachments ; + nsAutoCString TempFiles ; + + nsCOMPtr <nsIFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ; + if (NS_FAILED(rv) || (!pFile) ) return rv ; + nsCOMPtr <nsIFile> pTempDir = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ; + if (NS_FAILED(rv) || (!pTempDir) ) return rv ; + + for (int i=0 ; i < aFileCount ; i++) + { + if (aFiles[i].lpszPathName) + { + // check if attachment exists + if (aIsUnicode) + pFile->InitWithPath (nsDependentString(aFiles[i].lpszPathName)); + else + pFile->InitWithNativePath (nsDependentCString((const char*)aFiles[i].lpszPathName)); + + bool bExist ; + rv = pFile->Exists(&bExist) ; + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("nsMapiHook::HandleAttachments: filename: %s path: %s exists = %s \n", (const char*)aFiles[i].lpszFileName, (const char*)aFiles[i].lpszPathName, bExist ? "true" : "false")); + if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ; + + //Temp Directory + nsCOMPtr <nsIFile> pTempDir; + NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pTempDir)); + + // create a new sub directory called moz_mapi underneath the temp directory + pTempDir->AppendRelativePath(NS_LITERAL_STRING("moz_mapi")); + pTempDir->Exists (&bExist) ; + if (!bExist) + { + rv = pTempDir->Create(nsIFile::DIRECTORY_TYPE, 777) ; + if (NS_FAILED(rv)) return rv ; + } + + // rename or copy the existing temp file with the real file name + + nsAutoString leafName ; + // convert to Unicode using Platform charset + // leafName already contains a unicode leafName from lpszPathName. If we were given + // a value for lpszFileName, use it. Otherwise stick with leafName + if (aFiles[i].lpszFileName) + { + nsAutoString wholeFileName; + if (aIsUnicode) + wholeFileName.Assign(aFiles[i].lpszFileName); + else + ConvertToUnicode(nsMsgI18NFileSystemCharset(), (char *) aFiles[i].lpszFileName, wholeFileName); + // need to find the last '\' and find the leafname from that. + int32_t lastSlash = wholeFileName.RFindChar(char16_t('\\')); + if (lastSlash != kNotFound) + leafName.Assign(Substring(wholeFileName, lastSlash + 1)); + else + leafName.Assign(wholeFileName); + } + else + pFile->GetLeafName (leafName); + + nsCOMPtr<nsIMsgAttachment> attachment = do_CreateInstance(NS_MSGATTACHMENT_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + attachment->SetName(leafName); + + nsCOMPtr<nsIFile> pTempFile; + rv = pTempDir->Clone(getter_AddRefs(pTempFile)); + if (NS_FAILED(rv) || !pTempFile) + return rv; + + pTempFile->Append(leafName); + pTempFile->Exists(&bExist); + if (bExist) + { + rv = pTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777); + NS_ENSURE_SUCCESS(rv, rv); + pTempFile->Remove(false); // remove so we can copy over it. + pTempFile->GetLeafName(leafName); + } + // copy the file to its new location and file name + pFile->CopyTo(pTempDir, leafName); + // point pFile to the new location of the attachment + pFile->InitWithFile(pTempDir); + pFile->Append(leafName); + + // create MsgCompose attachment object + attachment->SetTemporary(true); // this one is a temp file so set the flag for MsgCompose + + // now set the attachment object + nsAutoCString pURL ; + NS_GetURLSpecFromFile(pFile, pURL); + attachment->SetUrl(pURL); + + // set the file size + int64_t fileSize; + pFile->GetFileSize(&fileSize); + attachment->SetSize(fileSize); + + // add the attachment + rv = aCompFields->AddAttachment (attachment); + if (NS_FAILED(rv)) + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("nsMapiHook::HandleAttachments: AddAttachment rv = %lx\n", rv)); + } + } + return rv ; +} + + +// this is used to convert non Unicode data and then populate comp fields +nsresult nsMapiHook::PopulateCompFieldsWithConversion(lpnsMapiMessage aMessage, + nsIMsgCompFields * aCompFields) +{ + nsresult rv = NS_OK; + + if (aMessage->lpOriginator) + { + nsAutoString From; + From.Append(NS_ConvertASCIItoUTF16((char *) aMessage->lpOriginator->lpszAddress)); + aCompFields->SetFrom (From); + } + + nsAutoString To; + nsAutoString Cc; + nsAutoString Bcc; + NS_NAMED_LITERAL_STRING(Comma, ","); + if (aMessage->lpRecips) + { + for (int i=0 ; i < (int) aMessage->nRecipCount ; i++) + { + if (aMessage->lpRecips[i].lpszAddress || aMessage->lpRecips[i].lpszName) + { + const char *addressWithoutType = (aMessage->lpRecips[i].lpszAddress) + ? aMessage->lpRecips[i].lpszAddress : aMessage->lpRecips[i].lpszName; + if (!PL_strncasecmp(addressWithoutType, "SMTP:", 5)) + addressWithoutType += 5; + + switch (aMessage->lpRecips[i].ulRecipClass) + { + case MAPI_TO : + if (!To.IsEmpty()) + To += Comma ; + To.Append(NS_ConvertASCIItoUTF16(addressWithoutType)); + break ; + + case MAPI_CC : + if (!Cc.IsEmpty()) + Cc += Comma ; + Cc.Append(NS_ConvertASCIItoUTF16(addressWithoutType)); + break ; + + case MAPI_BCC : + if (!Bcc.IsEmpty()) + Bcc += Comma ; + Bcc.Append(NS_ConvertASCIItoUTF16(addressWithoutType)); + break ; + } + } + } + } + + // set To, Cc, Bcc + aCompFields->SetTo (To) ; + aCompFields->SetCc (Cc) ; + aCompFields->SetBcc (Bcc) ; + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("to: %s cc: %s bcc: %s \n", NS_ConvertUTF16toUTF8(To).get(), NS_ConvertUTF16toUTF8(Cc).get(), NS_ConvertUTF16toUTF8(Bcc).get())); + + nsAutoCString platformCharSet; + // set subject + if (aMessage->lpszSubject) + { + nsAutoString Subject ; + if (platformCharSet.IsEmpty()) + platformCharSet.Assign(nsMsgI18NFileSystemCharset()); + rv = ConvertToUnicode(platformCharSet.get(), (char *) aMessage->lpszSubject, Subject); + if (NS_FAILED(rv)) return rv; + aCompFields->SetSubject(Subject); + } + + // handle attachments as File URL + rv = HandleAttachments (aCompFields, aMessage->nFileCount, aMessage->lpFiles, false) ; + if (NS_FAILED(rv)) return rv ; + + // set body + if (aMessage->lpszNoteText) + { + nsAutoString Body ; + if (platformCharSet.IsEmpty()) + platformCharSet.Assign(nsMsgI18NFileSystemCharset()); + rv = ConvertToUnicode(platformCharSet.get(), (char *) aMessage->lpszNoteText, Body); + if (NS_FAILED(rv)) return rv ; + if (Body.IsEmpty() || Body.Last() != '\n') + Body.AppendLiteral(CRLF); + + // This is needed when Simple MAPI is used without a compose window. + // See bug 1366196. + if (Body.Find("<html>") == kNotFound) + aCompFields->SetForcePlainText(true); + + rv = aCompFields->SetBody(Body) ; + } + +#ifdef RAJIV_DEBUG + // testing what all was set in CompFields + printf ("To : %S \n", To.get()) ; + printf ("CC : %S \n", Cc.get() ) ; + printf ("BCC : %S \n", Bcc.get() ) ; +#endif + + return rv ; +} + +// this is used to populate the docs as attachments in the Comp fields for Send Documents +nsresult nsMapiHook::PopulateCompFieldsForSendDocs(nsIMsgCompFields * aCompFields, ULONG aFlags, + LPTSTR aDelimChar, LPTSTR aFilePaths) +{ + nsAutoString strDelimChars ; + nsString strFilePaths; + nsresult rv = NS_OK ; + bool bExist ; + + if (aDelimChar) + strDelimChars.Assign(aDelimChar); + if (aFilePaths) + strFilePaths.Assign(aFilePaths); + + // check for comma in filename + if (strDelimChars.FindChar(',') == kNotFound) // if comma is not in the delimiter specified by user + { + if (strFilePaths.FindChar(',') != kNotFound) // if comma found in filenames return error + return NS_ERROR_FILE_INVALID_PATH; + } + + nsCString Attachments ; + + // only 1 file is to be sent, no delim specified + if (strDelimChars.IsEmpty()) + strDelimChars.AssignLiteral(";"); + + int32_t offset = 0 ; + int32_t FilePathsLen = strFilePaths.Length() ; + if (FilePathsLen) + { + nsAutoString Subject ; + + // multiple files to be sent, delim specified + nsCOMPtr <nsIFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ; + if (NS_FAILED(rv) || (!pFile) ) return rv ; + + char16_t * newFilePaths = (char16_t *) strFilePaths.get() ; + while (offset != kNotFound) + { + //Temp Directory + nsCOMPtr <nsIFile> pTempDir; + NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pTempDir)); + + // if not already existing, create another temp dir for mapi within Win temp dir + // this is windows only so we can do "\\" + pTempDir->AppendRelativePath (NS_LITERAL_STRING("moz_mapi")); + pTempDir->Exists(&bExist) ; + if (!bExist) + { + rv = pTempDir->Create(nsIFile::DIRECTORY_TYPE, 777) ; + if (NS_FAILED(rv)) return rv ; + } + + nsString RemainingPaths ; + RemainingPaths.Assign(newFilePaths) ; + offset = RemainingPaths.Find (strDelimChars) ; + if (offset != kNotFound) + { + RemainingPaths.SetLength (offset) ; + if ((offset + (int32_t)strDelimChars.Length()) < FilePathsLen) + newFilePaths += offset + strDelimChars.Length() ; + else + offset = kNotFound; + FilePathsLen -= offset + strDelimChars.Length(); + } + + if (RemainingPaths[1] != ':' && RemainingPaths[1] != '\\') + { + char cwd[MAX_PATH]; + if (_getdcwd(_getdrive(), cwd, MAX_PATH)) + { + nsAutoString cwdStr; + CopyASCIItoUTF16(cwd, cwdStr); + cwdStr.Append('\\'); + RemainingPaths.Insert(cwdStr, 0); + } + } + + pFile->InitWithPath (RemainingPaths) ; + + rv = pFile->Exists(&bExist) ; + if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ; + + // filename of the file attachment + nsAutoString leafName ; + pFile->GetLeafName (leafName) ; + if(NS_FAILED(rv) || leafName.IsEmpty()) return rv ; + + if (!Subject.IsEmpty()) + Subject.AppendLiteral(", "); + Subject += leafName; + + // create MsgCompose attachment object + nsCOMPtr<nsIMsgAttachment> attachment = do_CreateInstance(NS_MSGATTACHMENT_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsDependentString fileNameNative(leafName.get()); + rv = pFile->CopyTo(pTempDir, fileNameNative); + if (NS_FAILED(rv)) return rv; + + // now turn pTempDir into a full file path to the temp file + pTempDir->Append(fileNameNative); + + // this one is a temp file so set the flag for MsgCompose + attachment->SetTemporary(true); + + // now set the attachment object + nsAutoCString pURL; + NS_GetURLSpecFromFile(pTempDir, pURL); + attachment->SetUrl(pURL); + + // set the file size + int64_t fileSize; + pFile->GetFileSize(&fileSize); + attachment->SetSize(fileSize); + + // add the attachment + rv = aCompFields->AddAttachment (attachment); + if (NS_FAILED(rv)) return rv; + } + + rv = aCompFields->SetBody(Subject) ; + } + + return rv ; +} + +// this used for Send with UI +nsresult nsMapiHook::ShowComposerWindow (unsigned long aSession, nsIMsgCompFields * aCompFields) +{ + nsresult rv = NS_OK ; + + // 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 ; + + // If we found HTML, compose in HTML. + bool forcePlainText; + aCompFields->GetForcePlainText(&forcePlainText); + pMsgComposeParams->SetFormat(forcePlainText ? nsIMsgCompFormat::Default : nsIMsgCompFormat::HTML); + + // populate the compose params + pMsgComposeParams->SetType(nsIMsgCompType::New); + + // Never force to plain text, the default format will take care of that. + // Undo the forcing that happened in PopulateCompFields/PopulateCompFieldsWithConversion. + // See bug 1095629 and bug 1366196. + aCompFields->SetForcePlainText(false); + pMsgComposeParams->SetComposeFields(aCompFields); + pMsgComposeParams->SetSendListener(sendListener); + + /** get the nsIMsgComposeService object to open the compose window **/ + nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ; + if (NS_FAILED(rv)|| (!compService) ) return rv ; + + rv = compService->OpenComposeWindowWithParams(nullptr, pMsgComposeParams) ; + if (NS_FAILED(rv)) return rv ; + + return rv ; +} |