/* 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 #include #include #include #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 dlgService(do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv) && dlgService) { nsCOMPtr bundleService = mozilla::services::GetStringBundleService(); if (!bundleService) return false; nsCOMPtr bundle; rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle)); if (NS_FAILED(rv) || !bundle) return false; nsCOMPtr 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 accountManager(do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv)); if (NS_FAILED(rv)) return false; nsCOMPtr 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 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 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 bundleService = mozilla::services::GetStringBundleService(); if (!bundleService) return false; nsCOMPtr 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 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 hiddenWindow; // get parent window nsCOMPtr 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 accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ; if (NS_FAILED(rv) || (!accountManager) ) return rv ; nsCOMPtr 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 sendListener ; rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; if (NS_FAILED(rv) || (!sendListener) ) return rv; // create the compose params object nsCOMPtr 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 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 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("") == 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 pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ; if (NS_FAILED(rv) || (!pFile) ) return rv ; nsCOMPtr 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 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 attachment = do_CreateInstance(NS_MSGATTACHMENT_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); attachment->SetName(leafName); nsCOMPtr 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("") == 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 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 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 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 sendListener ; rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; if (NS_FAILED(rv) || (!sendListener) ) return rv ; // create the compose params object nsCOMPtr 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 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 ; }