diff options
Diffstat (limited to 'mailnews/mapi/mapihook/src/msgMapiImp.cpp')
-rw-r--r-- | mailnews/mapi/mapihook/src/msgMapiImp.cpp | 878 |
1 files changed, 878 insertions, 0 deletions
diff --git a/mailnews/mapi/mapihook/src/msgMapiImp.cpp b/mailnews/mapi/mapihook/src/msgMapiImp.cpp new file mode 100644 index 000000000..9139d68c6 --- /dev/null +++ b/mailnews/mapi/mapihook/src/msgMapiImp.cpp @@ -0,0 +1,878 @@ +/* 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/. */ + +#include <mapidefs.h> +#include <mapi.h> +#include "msgMapi.h" +#include "msgMapiImp.h" +#include "msgMapiFactory.h" +#include "msgMapiMain.h" + +#include "nsIMsgCompFields.h" +#include "msgMapiHook.h" +#include "nsStringGlue.h" +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsMsgCompCID.h" +#include "nsIMsgDatabase.h" +#include "nsMsgFolderFlags.h" +#include "nsIMsgHdr.h" +#include "MailNewsTypes.h" +#include "nsMsgBaseCID.h" +#include "nsIMsgAccountManager.h" +#include "nsIMsgFolder.h" +#include "nsIMsgImapMailFolder.h" +#include <time.h> +#include "nsIInputStream.h" +#include "nsILineInputStream.h" +#include "nsISeekableStream.h" +#include "nsIFile.h" +#include "nsIFileStreams.h" +#include "nsNetCID.h" +#include "nsMsgMessageFlags.h" +#include "mozilla/mailnews/MimeHeaderParser.h" +#include "mozilla/Logging.h" + +using namespace mozilla::mailnews; + +PRLogModuleInfo *MAPI; + +CMapiImp::CMapiImp() +: m_cRef(1) +{ + m_Lock = PR_NewLock(); + if (!MAPI) + MAPI = PR_NewLogModule("MAPI"); +} + +CMapiImp::~CMapiImp() +{ + if (m_Lock) + PR_DestroyLock(m_Lock); +} + +STDMETHODIMP CMapiImp::QueryInterface(const IID& aIid, void** aPpv) +{ + if (aIid == IID_IUnknown) + { + *aPpv = static_cast<nsIMapi*>(this); + } + else if (aIid == IID_nsIMapi) + { + *aPpv = static_cast<nsIMapi*>(this); + } + else + { + *aPpv = nullptr; + return E_NOINTERFACE; + } + + reinterpret_cast<IUnknown*>(*aPpv)->AddRef(); + return S_OK; +} + +STDMETHODIMP_(ULONG) CMapiImp::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) CMapiImp::Release() +{ + int32_t temp = --m_cRef; + if (m_cRef == 0) + { + delete this; + return 0; + } + + return temp; +} + +STDMETHODIMP CMapiImp::IsValid() +{ + return S_OK; +} + +STDMETHODIMP CMapiImp::IsValidSession(unsigned long aSession) +{ + nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration(); + if (pConfig && pConfig->IsSessionValid(aSession)) + return S_OK; + + return E_FAIL; +} + +STDMETHODIMP CMapiImp::Initialize() +{ + HRESULT hr = E_FAIL; + + if (!m_Lock) + return E_FAIL; + + PR_Lock(m_Lock); + + // Initialize MAPI Configuration + + nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration(); + if (pConfig != nullptr) + hr = S_OK; + + PR_Unlock(m_Lock); + + return hr; +} + +STDMETHODIMP CMapiImp::Login(unsigned long aUIArg, LOGIN_PW_TYPE aLogin, LOGIN_PW_TYPE aPassWord, + unsigned long aFlags, unsigned long *aSessionId) +{ + HRESULT hr = E_FAIL; + bool bNewSession = false; + nsCString id_key; + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::Login using flags %d\n", aFlags)); + if (aFlags & MAPI_NEW_SESSION) + bNewSession = true; + + // Check For Profile Name + if (aLogin != nullptr && aLogin[0] != '\0') + { + if (!nsMapiHook::VerifyUserName(nsString(aLogin), id_key)) + { + *aSessionId = MAPI_E_LOGIN_FAILURE; + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::Login failed for username %s\n", aLogin)); + NS_ASSERTION(false, "failed verifying user name"); + return hr; + } + } + else + { + // get default account + nsresult rv; + nsCOMPtr <nsIMsgAccountManager> accountManager = + do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,MAPI_E_LOGIN_FAILURE); + nsCOMPtr <nsIMsgAccount> account; + nsCOMPtr <nsIMsgIdentity> identity; + rv = accountManager->GetDefaultAccount(getter_AddRefs(account)); + NS_ENSURE_SUCCESS(rv,MAPI_E_LOGIN_FAILURE); + rv = account->GetDefaultIdentity(getter_AddRefs(identity)); + NS_ENSURE_SUCCESS(rv,MAPI_E_LOGIN_FAILURE); + if (!identity) + return MAPI_E_LOGIN_FAILURE; + identity->GetKey(id_key); + } + + // finally register(create) the session. + uint32_t nSession_Id; + int16_t nResult = 0; + + nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration(); + if (pConfig != nullptr) + nResult = pConfig->RegisterSession(aUIArg, wwc(aLogin), wwc(aPassWord), + (aFlags & MAPI_FORCE_DOWNLOAD), bNewSession, + &nSession_Id, id_key.get()); + switch (nResult) + { + case -1 : + { + *aSessionId = MAPI_E_TOO_MANY_SESSIONS; + return hr; + } + case 0 : + { + *aSessionId = MAPI_E_INSUFFICIENT_MEMORY; + return hr; + } + default : + { + *aSessionId = nSession_Id; + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::Login succeeded\n")); + break; + } + } + + return S_OK; +} + +STDMETHODIMP CMapiImp::SendMail( unsigned long aSession, lpnsMapiMessage aMessage, + short aRecipCount, lpnsMapiRecipDesc aRecips , short aFileCount, lpnsMapiFileDesc aFiles , + unsigned long aFlags, unsigned long aReserved) +{ + nsresult rv = NS_OK ; + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::SendMail using flags %d\n", aFlags)); + // Assign the pointers in the aMessage struct to the array of Recips and Files + // received here from MS COM. These are used in BlindSendMail and ShowCompWin fns + aMessage->lpRecips = aRecips ; + aMessage->lpFiles = aFiles ; + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::SendMail flags=%x subject: %s sender: %s\n", + aFlags, (char *) aMessage->lpszSubject, (aMessage->lpOriginator) ? aMessage->lpOriginator->lpszAddress : "")); + + /** create nsIMsgCompFields obj and populate it **/ + nsCOMPtr<nsIMsgCompFields> pCompFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ; + if (NS_FAILED(rv) || (!pCompFields) ) return MAPI_E_INSUFFICIENT_MEMORY ; + + if (aFlags & MAPI_UNICODE) + rv = nsMapiHook::PopulateCompFields(aMessage, pCompFields) ; + else + rv = nsMapiHook::PopulateCompFieldsWithConversion(aMessage, pCompFields) ; + + if (NS_SUCCEEDED (rv)) + { + // see flag to see if UI needs to be brought up + if (!(aFlags & MAPI_DIALOG)) + { + rv = nsMapiHook::BlindSendMail(aSession, pCompFields); + } + else + { + rv = nsMapiHook::ShowComposerWindow(aSession, pCompFields); + } + } + + return nsMAPIConfiguration::GetMAPIErrorFromNSError (rv) ; +} + + +STDMETHODIMP CMapiImp::SendDocuments( unsigned long aSession, LPTSTR aDelimChar, + LPTSTR aFilePaths, LPTSTR aFileNames, ULONG aFlags) +{ + nsresult rv = NS_OK ; + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::SendDocument using flags %d\n", aFlags)); + /** create nsIMsgCompFields obj and populate it **/ + nsCOMPtr<nsIMsgCompFields> pCompFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ; + if (NS_FAILED(rv) || (!pCompFields) ) return MAPI_E_INSUFFICIENT_MEMORY ; + + if (aFilePaths) + { + rv = nsMapiHook::PopulateCompFieldsForSendDocs(pCompFields, aFlags, aDelimChar, aFilePaths) ; + } + + if (NS_SUCCEEDED (rv)) + rv = nsMapiHook::ShowComposerWindow(aSession, pCompFields); + else + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::SendDocument error rv = %lx, paths = %s names = %s\n", rv, aFilePaths, aFileNames)); + + return nsMAPIConfiguration::GetMAPIErrorFromNSError (rv) ; +} + +nsresult CMapiImp::GetDefaultInbox(nsIMsgFolder **inboxFolder) +{ + // get default account + nsresult rv; + nsCOMPtr <nsIMsgAccountManager> accountManager = + do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr <nsIMsgAccount> account; + rv = accountManager->GetDefaultAccount(getter_AddRefs(account)); + NS_ENSURE_SUCCESS(rv,rv); + + // get incoming server + nsCOMPtr <nsIMsgIncomingServer> server; + rv = account->GetIncomingServer(getter_AddRefs(server)); + NS_ENSURE_SUCCESS(rv,rv); + + nsCString type; + rv = server->GetType(type); + NS_ENSURE_SUCCESS(rv,rv); + + // we only care about imap and pop3 + if (type.EqualsLiteral("imap") || type.EqualsLiteral("pop3")) + { + // imap and pop3 account should have an Inbox + nsCOMPtr<nsIMsgFolder> rootMsgFolder; + rv = server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder)); + NS_ENSURE_SUCCESS(rv,rv); + + if (!rootMsgFolder) + return NS_ERROR_FAILURE; + + rootMsgFolder->GetFolderWithFlags(nsMsgFolderFlags::Inbox, inboxFolder); + if (!*inboxFolder) + return NS_ERROR_FAILURE; + + } + return NS_OK; +} + +//***************************************************************************** +// Encapsulate the XP DB stuff required to enumerate messages + +class MsgMapiListContext +{ +public: + MsgMapiListContext () {} + ~MsgMapiListContext (); + + nsresult OpenDatabase (nsIMsgFolder *folder); + + nsMsgKey GetNext (); + nsresult MarkRead (nsMsgKey key, bool read); + + lpnsMapiMessage GetMessage (nsMsgKey, unsigned long flFlags); + bool IsIMAPHost(void); + bool DeleteMessage(nsMsgKey key); + +protected: + + char *ConvertDateToMapiFormat (time_t); + char *ConvertBodyToMapiFormat (nsIMsgDBHdr *hdr); + void ConvertRecipientsToMapiFormat(const nsCOMArray<msgIAddressObject> &ourRecips, + lpnsMapiRecipDesc mapiRecips, + int mapiRecipClass); + + nsCOMPtr <nsIMsgFolder> m_folder; + nsCOMPtr <nsIMsgDatabase> m_db; + nsCOMPtr <nsISimpleEnumerator> m_msgEnumerator; +}; + + +LONG CMapiImp::InitContext(unsigned long session, MsgMapiListContext **listContext) +{ + nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ; + if (!pMapiConfig) + return MAPI_E_FAILURE ; // get the singelton obj + *listContext = (MsgMapiListContext *) pMapiConfig->GetMapiListContext(session); + // This is the first message + if (!*listContext) + { + nsCOMPtr <nsIMsgFolder> inboxFolder; + nsresult rv = GetDefaultInbox(getter_AddRefs(inboxFolder)); + if (NS_FAILED(rv)) + { + NS_ASSERTION(false, "in init context, no inbox"); + return(MAPI_E_NO_MESSAGES); + } + + *listContext = new MsgMapiListContext; + if (!*listContext) + return MAPI_E_INSUFFICIENT_MEMORY; + + rv = (*listContext)->OpenDatabase(inboxFolder); + if (NS_FAILED(rv)) + { + pMapiConfig->SetMapiListContext(session, NULL); + delete *listContext; + NS_ASSERTION(false, "in init context, unable to open db"); + return MAPI_E_NO_MESSAGES; + } + else + pMapiConfig->SetMapiListContext(session, *listContext); + } + return SUCCESS_SUCCESS; +} + +STDMETHODIMP CMapiImp::FindNext(unsigned long aSession, unsigned long ulUIParam, LPTSTR lpszMessageType, + LPTSTR lpszSeedMessageID, unsigned long flFlags, unsigned long ulReserved, + unsigned char lpszMessageID[64]) + +{ + // + // If this is true, then this is the first call to this FindNext function + // and we should start the enumeration operation. + // + + *lpszMessageID = '\0'; + nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ; + if (!pMapiConfig) + { + NS_ASSERTION(false, "failed to get config in findnext"); + return MAPI_E_FAILURE ; // get the singelton obj + } + MsgMapiListContext *listContext; + LONG ret = InitContext(aSession, &listContext); + if (ret != SUCCESS_SUCCESS) + { + NS_ASSERTION(false, "init context failed"); + return ret; + } + NS_ASSERTION(listContext, "initContext returned null context"); + if (listContext) + { +// NS_ASSERTION(false, "find next init context succeeded"); + nsMsgKey nextKey = listContext->GetNext(); + if (nextKey == nsMsgKey_None) + { + pMapiConfig->SetMapiListContext(aSession, NULL); + delete listContext; + return(MAPI_E_NO_MESSAGES); + } + +// TRACE("MAPI: ProcessMAPIFindNext() Found message id = %d\n", nextKey); + + sprintf((char *) lpszMessageID, "%d", nextKey); + } + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::FindNext returning key %s\n", (char *) lpszMessageID)); + return(SUCCESS_SUCCESS); +} + +STDMETHODIMP CMapiImp::ReadMail(unsigned long aSession, unsigned long ulUIParam, LPTSTR lpszMessageID, + unsigned long flFlags, unsigned long ulReserved, lpnsMapiMessage *lppMessage) +{ + nsresult irv; + nsAutoCString keyString((char *) lpszMessageID); + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("CMapiImp::ReadMail asking for key %s\n", (char *) lpszMessageID)); + nsMsgKey msgKey = keyString.ToInteger(&irv); + if (NS_FAILED(irv)) + { + NS_ASSERTION(false, "invalid lpszMessageID"); + return MAPI_E_INVALID_MESSAGE; + } + MsgMapiListContext *listContext; + LONG ret = InitContext(aSession, &listContext); + if (ret != SUCCESS_SUCCESS) + { + NS_ASSERTION(false, "init context failed in ReadMail"); + return ret; + } + *lppMessage = listContext->GetMessage (msgKey, flFlags); + NS_ASSERTION(*lppMessage, "get message failed"); + + return (*lppMessage) ? SUCCESS_SUCCESS : E_FAIL; +} + + +STDMETHODIMP CMapiImp::DeleteMail(unsigned long aSession, unsigned long ulUIParam, LPTSTR lpszMessageID, + unsigned long flFlags, unsigned long ulReserved) +{ + nsresult irv; + nsAutoCString keyString((char *) lpszMessageID); + nsMsgKey msgKey = keyString.ToInteger(&irv); + // XXX Why do we return success on failure? + if (NS_FAILED(irv)) + return SUCCESS_SUCCESS; + MsgMapiListContext *listContext; + LONG ret = InitContext(aSession, &listContext); + if (ret != SUCCESS_SUCCESS) + return ret; + return (listContext->DeleteMessage(msgKey)) ? SUCCESS_SUCCESS : MAPI_E_INVALID_MESSAGE; +} + +STDMETHODIMP CMapiImp::SaveMail(unsigned long aSession, unsigned long ulUIParam, lpnsMapiMessage lppMessage, + unsigned long flFlags, unsigned long ulReserved, LPTSTR lpszMessageID) +{ + MsgMapiListContext *listContext; + LONG ret = InitContext(aSession, &listContext); + if (ret != SUCCESS_SUCCESS) + return ret; + return S_OK; +} + + +STDMETHODIMP CMapiImp::Logoff (unsigned long aSession) +{ + nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration(); + + if (pConfig->UnRegisterSession((uint32_t)aSession)) + return S_OK; + + return E_FAIL; +} + +STDMETHODIMP CMapiImp::CleanUp() +{ + nsMapiHook::CleanUp(); + return S_OK; +} + + +#define MAX_NAME_LEN 256 + + +MsgMapiListContext::~MsgMapiListContext () +{ + if (m_db) + m_db->Close(false); +} + + +nsresult MsgMapiListContext::OpenDatabase (nsIMsgFolder *folder) +{ + nsresult dbErr = NS_ERROR_FAILURE; + if (folder) + { + m_folder = folder; + dbErr = folder->GetMsgDatabase(getter_AddRefs(m_db)); + if (m_db) + dbErr = m_db->EnumerateMessages(getter_AddRefs(m_msgEnumerator)); + } + return dbErr; +} + +bool +MsgMapiListContext::IsIMAPHost(void) +{ + if (!m_folder) + return FALSE; + nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(m_folder); + + return imapFolder != nullptr; +} + +nsMsgKey MsgMapiListContext::GetNext () +{ + nsMsgKey key = nsMsgKey_None; + bool keepTrying = TRUE; + +// NS_ASSERTION (m_msgEnumerator && m_db, "need enumerator and db"); + if (m_msgEnumerator && m_db) + { + + do + { + keepTrying = FALSE; + nsCOMPtr <nsISupports> hdrISupports; + nsCOMPtr <nsIMsgDBHdr> msgHdr; + if (NS_SUCCEEDED(m_msgEnumerator->GetNext(getter_AddRefs(hdrISupports))) && hdrISupports) + { + msgHdr = do_QueryInterface(hdrISupports); + msgHdr->GetMessageKey(&key); + + // Check here for IMAP message...if not, just return... + if (!IsIMAPHost()) + return key; + + // If this is an IMAP message, we have to make sure we have a valid + // body to work with. + uint32_t flags = 0; + + (void) msgHdr->GetFlags(&flags); + if (flags & nsMsgMessageFlags::Offline) + return key; + + // Ok, if we get here, we have an IMAP message without a body! + // We need to keep trying by calling the GetNext member recursively... + keepTrying = TRUE; + } + } while (keepTrying); + } + + return key; +} + + +nsresult MsgMapiListContext::MarkRead (nsMsgKey key, bool read) +{ + nsresult err = NS_ERROR_FAILURE; + NS_ASSERTION(m_db, "no db"); + if (m_db) + err = m_db->MarkRead (key, read, nullptr); + return err; +} + + +lpnsMapiMessage MsgMapiListContext::GetMessage (nsMsgKey key, unsigned long flFlags) +{ + lpnsMapiMessage message = (lpnsMapiMessage) CoTaskMemAlloc (sizeof(nsMapiMessage)); + memset(message, 0, sizeof(nsMapiMessage)); + if (message) + { + nsCString subject; + nsCString author; + nsCOMPtr <nsIMsgDBHdr> msgHdr; + + nsresult rv = m_db->GetMsgHdrForKey (key, getter_AddRefs(msgHdr)); + if (msgHdr) + { + msgHdr->GetSubject (getter_Copies(subject)); + message->lpszSubject = (char *) CoTaskMemAlloc(subject.Length() + 1); + strcpy((char *) message->lpszSubject, subject.get()); + uint32_t date; + (void) msgHdr->GetDateInSeconds(&date); + message->lpszDateReceived = ConvertDateToMapiFormat (date); + + // Pull out the flags info + // anything to do with MAPI_SENT? Since we're only reading the Inbox, I guess not + uint32_t ourFlags; + (void) msgHdr->GetFlags(&ourFlags); + if (!(ourFlags & nsMsgMessageFlags::Read)) + message->flFlags |= MAPI_UNREAD; + if (ourFlags & (nsMsgMessageFlags::MDNReportNeeded | nsMsgMessageFlags::MDNReportSent)) + message->flFlags |= MAPI_RECEIPT_REQUESTED; + + // Pull out the author/originator info + message->lpOriginator = (lpnsMapiRecipDesc) CoTaskMemAlloc (sizeof(nsMapiRecipDesc)); + memset(message->lpOriginator, 0, sizeof(nsMapiRecipDesc)); + if (message->lpOriginator) + { + msgHdr->GetAuthor (getter_Copies(author)); + ConvertRecipientsToMapiFormat(EncodedHeader(author), + message->lpOriginator, MAPI_ORIG); + } + // Pull out the To/CC info + nsCString recipients, ccList; + msgHdr->GetRecipients(getter_Copies(recipients)); + msgHdr->GetCcList(getter_Copies(ccList)); + + nsCOMArray<msgIAddressObject> parsedToRecips = EncodedHeader(recipients); + nsCOMArray<msgIAddressObject> parsedCCRecips = EncodedHeader(ccList); + uint32_t numToRecips = parsedToRecips.Length(); + uint32_t numCCRecips = parsedCCRecips.Length(); + + message->lpRecips = (lpnsMapiRecipDesc) CoTaskMemAlloc ((numToRecips + numCCRecips) * sizeof(MapiRecipDesc)); + memset(message->lpRecips, 0, (numToRecips + numCCRecips) * sizeof(MapiRecipDesc)); + if (message->lpRecips) + { + ConvertRecipientsToMapiFormat(parsedToRecips, message->lpRecips, + MAPI_TO); + ConvertRecipientsToMapiFormat(parsedCCRecips, + &message->lpRecips[numToRecips], MAPI_CC); + } + + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("MsgMapiListContext::GetMessage flags=%x subject %s date %s sender %s\n", + flFlags, (char *) message->lpszSubject,(char *) message->lpszDateReceived, author.get()) ); + + // Convert any body text that we have locally + if (!(flFlags & MAPI_ENVELOPE_ONLY)) + message->lpszNoteText = (char *) ConvertBodyToMapiFormat (msgHdr); + + } + if (! (flFlags & (MAPI_PEEK | MAPI_ENVELOPE_ONLY))) + m_db->MarkRead(key, true, nullptr); + } + return message; +} + + +char *MsgMapiListContext::ConvertDateToMapiFormat (time_t ourTime) +{ + char *date = (char*) CoTaskMemAlloc(32); + if (date) + { + // MAPI time format is YYYY/MM/DD HH:MM + // Note that we're not using XP_StrfTime because that localizes the time format, + // and the way I read the MAPI spec is that their format is canonical, not localized. + struct tm *local = localtime (&ourTime); + if (local) + strftime (date, 32, "%Y/%m/%d %I:%M", local); //use %H if hours should be 24 hour format + } + return date; +} + + +void MsgMapiListContext::ConvertRecipientsToMapiFormat( + const nsCOMArray<msgIAddressObject> &recipients, + lpnsMapiRecipDesc mapiRecips, int mapiRecipClass) +{ + nsTArray<nsCString> names, addresses; + ExtractAllAddresses(recipients, UTF16ArrayAdapter<>(names), + UTF16ArrayAdapter<>(addresses)); + + size_t numAddresses = names.Length(); + for (size_t i = 0; i < numAddresses; i++) + { + if (!names[i].IsEmpty()) + { + mapiRecips[i].lpszName = (char *) CoTaskMemAlloc(names[i].Length() + 1); + if (mapiRecips[i].lpszName) + strcpy((char *)mapiRecips[i].lpszName, names[i].get()); + } + if (!addresses[i].IsEmpty()) + { + mapiRecips[i].lpszName = (char *) CoTaskMemAlloc(addresses[i].Length() + 1); + if (mapiRecips[i].lpszName) + strcpy((char *)mapiRecips[i].lpszName, addresses[i].get()); + } + mapiRecips[i].ulRecipClass = mapiRecipClass; + } +} + + +char *MsgMapiListContext::ConvertBodyToMapiFormat (nsIMsgDBHdr *hdr) +{ + const int kBufLen = 64000; // I guess we only return the first 64K of a message. +#define EMPTY_MESSAGE_LINE(buf) (buf[0] == '\r' || buf[0] == '\n' || buf[0] == '\0') + + nsCOMPtr <nsIMsgFolder> folder; + hdr->GetFolder(getter_AddRefs(folder)); + if (!folder) + return nullptr; + + nsCOMPtr <nsIInputStream> inputStream; + nsCOMPtr <nsIFile> localFile; + folder->GetFilePath(getter_AddRefs(localFile)); + + nsresult rv; + nsCOMPtr<nsIFileInputStream> fileStream = do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, nullptr); + + rv = fileStream->Init(localFile, PR_RDONLY, 0664, false); //just have to read the messages + inputStream = do_QueryInterface(fileStream); + + if (inputStream) + { + nsCOMPtr <nsILineInputStream> fileLineStream = do_QueryInterface(inputStream); + if (!fileLineStream) + return nullptr; + // ### really want to skip past headers... + uint64_t messageOffset; + uint32_t lineCount; + hdr->GetMessageOffset(&messageOffset); + hdr->GetLineCount(&lineCount); + nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(inputStream); + seekableStream->Seek(PR_SEEK_SET, messageOffset); + bool hasMore = true; + nsAutoCString curLine; + nsresult rv = NS_OK; + while (hasMore) // advance past message headers + { + nsresult rv = fileLineStream->ReadLine(curLine, &hasMore); + if (NS_FAILED(rv) || EMPTY_MESSAGE_LINE(curLine)) + break; + } + uint32_t msgSize; + hdr->GetMessageSize(&msgSize); + if (msgSize > kBufLen) + msgSize = kBufLen - 1; + // this is too big, since it includes the msg hdr size...oh well + char *body = (char*) CoTaskMemAlloc (msgSize + 1); + + if (!body) + return nullptr; + int32_t bytesCopied = 0; + for (hasMore = TRUE; lineCount > 0 && hasMore && NS_SUCCEEDED(rv); lineCount--) + { + rv = fileLineStream->ReadLine(curLine, &hasMore); + if (NS_FAILED(rv)) + break; + curLine.Append(CRLF); + // make sure we have room left + if (bytesCopied + curLine.Length() < msgSize) + { + strcpy(body + bytesCopied, curLine.get()); + bytesCopied += curLine.Length(); + } + } + MOZ_LOG(MAPI, mozilla::LogLevel::Debug, ("ConvertBodyToMapiFormat size=%x allocated size %x body = %100.100s\n", + bytesCopied, msgSize + 1, (char *) body) ); + body[bytesCopied] = '\0'; // rhp - fix last line garbage... + return body; + } + return nullptr; +} + + +//***************************************************************************** +// MSGMAPI API implementation + + + +static void msg_FreeMAPIFile(lpMapiFileDesc f) +{ + if (f) + { + CoTaskMemFree(f->lpszPathName); + CoTaskMemFree(f->lpszFileName); + } +} + +static void msg_FreeMAPIRecipient(lpMapiRecipDesc rd) +{ + if (rd) + { + if (rd->lpszName) + CoTaskMemFree(rd->lpszName); + if (rd->lpszAddress) + CoTaskMemFree(rd->lpszAddress); + // CoTaskMemFree(rd->lpEntryID); + } +} + +extern "C" void MSG_FreeMapiMessage (lpMapiMessage msg) +{ + ULONG i; + + if (msg) + { + CoTaskMemFree(msg->lpszSubject); + CoTaskMemFree(msg->lpszNoteText); + CoTaskMemFree(msg->lpszMessageType); + CoTaskMemFree(msg->lpszDateReceived); + CoTaskMemFree(msg->lpszConversationID); + + if (msg->lpOriginator) + msg_FreeMAPIRecipient(msg->lpOriginator); + + for (i=0; i<msg->nRecipCount; i++) + if (&(msg->lpRecips[i]) != nullptr) + msg_FreeMAPIRecipient(&(msg->lpRecips[i])); + + CoTaskMemFree(msg->lpRecips); + + for (i=0; i<msg->nFileCount; i++) + if (&(msg->lpFiles[i]) != nullptr) + msg_FreeMAPIFile(&(msg->lpFiles[i])); + + CoTaskMemFree(msg->lpFiles); + + CoTaskMemFree(msg); + } +} + + +extern "C" bool MsgMarkMapiMessageRead (nsIMsgFolder *folder, nsMsgKey key, bool read) +{ + bool success = FALSE; + MsgMapiListContext *context = new MsgMapiListContext(); + if (context) + { + if (NS_SUCCEEDED(context->OpenDatabase(folder))) + { + if (NS_SUCCEEDED(context->MarkRead (key, read))) + success = TRUE; + } + delete context; + } + return success; +} + +bool +MsgMapiListContext::DeleteMessage(nsMsgKey key) +{ + if (!m_db) + return FALSE; + + if ( !IsIMAPHost() ) + { + return NS_SUCCEEDED((m_db->DeleteMessages(1, &key, nullptr))); + } +#if 0 + else if ( m_folder->GetIMAPFolderInfoMail() ) + { + AutoTArray<nsMsgKey, 1> messageKeys; + messageKeys.AppendElement(key); + + (m_folder->GetIMAPFolderInfoMail())->DeleteSpecifiedMessages(pane, messageKeys, nsMsgKey_None); + m_db->DeleteMessage(key, nullptr, FALSE); + return TRUE; + } +#endif + else + { + return FALSE; + } +} + +/* Return TRUE on success, FALSE on failure */ +extern "C" bool MSG_DeleteMapiMessage(nsIMsgFolder *folder, nsMsgKey key) +{ + bool success = FALSE; + MsgMapiListContext *context = new MsgMapiListContext(); + if (context) + { + if (NS_SUCCEEDED(context->OpenDatabase(folder))) + { + success = context->DeleteMessage(key); + } + + delete context; + } + + return success; +} + |