summaryrefslogtreecommitdiffstats
path: root/mailnews/mapi/mapihook/src/msgMapiHook.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/mapi/mapihook/src/msgMapiHook.cpp')
-rw-r--r--mailnews/mapi/mapihook/src/msgMapiHook.cpp829
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 ;
+}