/* 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/. */ #pragma warning(disable : 4996) // MAPILogoff is deprecated #include #include #include #include "msgMapi.h" // Ensure that our COM structs match MS MAPI structs - thoroughly check each // struct layout This needs that MAPI.h is not used from // https://www.microsoft.com/en-us/download/details.aspx?id=12905 because the // newer MAPI.h is the part of Windows SDK, and it includes MapiFileDescW and // friends. static_assert(sizeof(nsMapiFileDesc) == sizeof(MapiFileDesc), "Size mismatch!"); static_assert(offsetof(nsMapiFileDesc, ulReserved) == offsetof(MapiFileDesc, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDesc, flFlags) == offsetof(MapiFileDesc, flFlags), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDesc, nPosition_NotUsed) == offsetof(MapiFileDesc, nPosition), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDesc, lpszPathName) == offsetof(MapiFileDesc, lpszPathName), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDesc, lpszFileName) == offsetof(MapiFileDesc, lpszFileName), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDesc, lpFileType_NotUsed) == offsetof(MapiFileDesc, lpFileType), "Member offset mismatch!"); static_assert(sizeof(nsMapiRecipDesc) == sizeof(MapiRecipDesc), "Size mismatch!"); static_assert(offsetof(nsMapiRecipDesc, ulReserved) == offsetof(MapiRecipDesc, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDesc, ulRecipClass) == offsetof(MapiRecipDesc, ulRecipClass), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDesc, lpszName) == offsetof(MapiRecipDesc, lpszName), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDesc, lpszAddress) == offsetof(MapiRecipDesc, lpszAddress), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDesc, ulEIDSize_NotUsed) == offsetof(MapiRecipDesc, ulEIDSize), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDesc, lpEntryID_NotUsed) == offsetof(MapiRecipDesc, lpEntryID), "Member offset mismatch!"); static_assert(sizeof(nsMapiMessage) == sizeof(MapiMessage), "Size mismatch!"); static_assert(offsetof(nsMapiMessage, ulReserved) == offsetof(MapiMessage, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpszSubject) == offsetof(MapiMessage, lpszSubject), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpszNoteText) == offsetof(MapiMessage, lpszNoteText), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpszMessageType) == offsetof(MapiMessage, lpszMessageType), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpszDateReceived) == offsetof(MapiMessage, lpszDateReceived), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpszConversationID_NotUsed) == offsetof(MapiMessage, lpszConversationID), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, flFlags) == offsetof(MapiMessage, flFlags), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpOriginator) == offsetof(MapiMessage, lpOriginator), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, nRecipCount) == offsetof(MapiMessage, nRecipCount), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpRecips) == offsetof(MapiMessage, lpRecips), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, nFileCount) == offsetof(MapiMessage, nFileCount), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessage, lpFiles) == offsetof(MapiMessage, lpFiles), "Member offset mismatch!"); static_assert(sizeof(nsMapiFileDescW) == sizeof(MapiFileDescW), "Size mismatch!"); static_assert(offsetof(nsMapiFileDescW, ulReserved) == offsetof(MapiFileDescW, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDescW, flFlags) == offsetof(MapiFileDescW, flFlags), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDescW, nPosition_NotUsed) == offsetof(MapiFileDescW, nPosition), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDescW, lpszPathName) == offsetof(MapiFileDescW, lpszPathName), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDescW, lpszFileName) == offsetof(MapiFileDescW, lpszFileName), "Member offset mismatch!"); static_assert(offsetof(nsMapiFileDescW, lpFileType_NotUsed) == offsetof(MapiFileDescW, lpFileType), "Member offset mismatch!"); static_assert(sizeof(nsMapiRecipDescW) == sizeof(MapiRecipDescW), "Size mismatch!"); static_assert(offsetof(nsMapiRecipDescW, ulReserved) == offsetof(MapiRecipDescW, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDescW, ulRecipClass) == offsetof(MapiRecipDescW, ulRecipClass), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDescW, lpszName) == offsetof(MapiRecipDescW, lpszName), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDescW, lpszAddress) == offsetof(MapiRecipDescW, lpszAddress), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDescW, ulEIDSize_NotUsed) == offsetof(MapiRecipDescW, ulEIDSize), "Member offset mismatch!"); static_assert(offsetof(nsMapiRecipDescW, lpEntryID_NotUsed) == offsetof(MapiRecipDescW, lpEntryID), "Member offset mismatch!"); static_assert(sizeof(nsMapiMessageW) == sizeof(MapiMessageW), "Size mismatch!"); static_assert(offsetof(nsMapiMessageW, ulReserved) == offsetof(MapiMessageW, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpszSubject) == offsetof(MapiMessageW, lpszSubject), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, ulReserved) == offsetof(MapiMessageW, ulReserved), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpszSubject) == offsetof(MapiMessageW, lpszSubject), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpszNoteText) == offsetof(MapiMessageW, lpszNoteText), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpszMessageType) == offsetof(MapiMessageW, lpszMessageType), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpszDateReceived) == offsetof(MapiMessageW, lpszDateReceived), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpszConversationID_NotUsed) == offsetof(MapiMessageW, lpszConversationID), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, flFlags) == offsetof(MapiMessageW, flFlags), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpOriginator) == offsetof(MapiMessageW, lpOriginator), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, nRecipCount) == offsetof(MapiMessageW, nRecipCount), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpRecips) == offsetof(MapiMessageW, lpRecips), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, nFileCount) == offsetof(MapiMessageW, nFileCount), "Member offset mismatch!"); static_assert(offsetof(nsMapiMessageW, lpFiles) == offsetof(MapiMessageW, lpFiles), "Member offset mismatch!"); #define MAX_RECIPS 2000 #define MAX_FILES 100 #define MAX_NAME_LEN 256 #define MAX_PW_LEN 256 #define MAX_MSGINFO_LEN 512 #define MAX_POINTERS 32 const CLSID CLSID_CMapiImp = {0x29f458be, 0x8866, 0x11d5, {0xa3, 0xdd, 0x0, 0xb0, 0xd0, 0xf3, 0xba, 0xa7}}; const IID IID_nsIMapi = {0x6EDCD38E, 0x8861, 0x11d5, {0xA3, 0xDD, 0x00, 0xB0, 0xD0, 0xF3, 0xBA, 0xA7}}; DWORD tId = 0; #define MAPI_MESSAGE_TYPE 0 #define MAPI_RECIPIENT_TYPE 1 typedef struct { LPVOID lpMem; UCHAR memType; } memTrackerType; // this can't be right. memTrackerType memArray[MAX_POINTERS]; // // For remembering memory...how ironic. // void SetPointerArray(LPVOID ptr, BYTE type) { int i; for (i = 0; i < MAX_POINTERS; i++) { if (memArray[i].lpMem == NULL) { memArray[i].lpMem = ptr; memArray[i].memType = type; break; } } } BOOL WINAPI DllMain(HINSTANCE aInstance, DWORD aReason, LPVOID aReserved) { switch (aReason) { case DLL_PROCESS_ATTACH: tId = TlsAlloc(); if (tId == 0xFFFFFFFF) return FALSE; break; case DLL_PROCESS_DETACH: TlsFree(tId); break; } return TRUE; } BOOL InitMozillaReference(nsIMapi** aRetValue) { // Check whether this thread has a valid Interface // by looking into thread-specific-data variable *aRetValue = (nsIMapi*)TlsGetValue(tId); // Check whether the pointer actually resolves to // a valid method call; otherwise mozilla is not running if ((*aRetValue) && (*aRetValue)->IsValid() == S_OK) return TRUE; HRESULT hRes = ::CoInitialize(NULL); hRes = ::CoCreateInstance(CLSID_CMapiImp, NULL, CLSCTX_LOCAL_SERVER, IID_nsIMapi, (LPVOID*)aRetValue); if (hRes == S_OK && (*aRetValue)->Initialize() == S_OK) if (TlsSetValue(tId, (LPVOID)(*aRetValue))) return TRUE; // Either CoCreate or TlsSetValue failed; so return FALSE if ((*aRetValue)) (*aRetValue)->Release(); ::CoUninitialize(); return FALSE; } ///////////////////////////////////////////////////////////////////////////// // The MAPILogon function begins a Simple MAPI session, loading the default // message store and address book providers ///////////////////////////////////////////////////////////////////////////// ULONG FAR PASCAL MAPILogon(ULONG aUIParam, LPSTR aProfileName, LPSTR aPassword, FLAGS aFlags, ULONG aReserved, LPLHANDLE aSession) { HRESULT hr = 0; ULONG nSessionId = 0; nsIMapi* pNsMapi = NULL; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; hr = pNsMapi->Login(aUIParam, aProfileName, aPassword, aFlags, &nSessionId); if (hr == S_OK) (*aSession) = (LHANDLE)nSessionId; else return nSessionId; return SUCCESS_SUCCESS; } ULONG FAR PASCAL MAPILogoff(LHANDLE aSession, ULONG aUIParam, FLAGS aFlags, ULONG aReserved) { nsIMapi* pNsMapi = (nsIMapi*)TlsGetValue(tId); if (pNsMapi != NULL) { if (pNsMapi->Logoff((ULONG)aSession) == S_OK) pNsMapi->Release(); pNsMapi = NULL; } TlsSetValue(tId, NULL); ::CoUninitialize(); return SUCCESS_SUCCESS; } ULONG FAR PASCAL MAPISendMail(LHANDLE lhSession, ULONG ulUIParam, nsMapiMessage* lpMessage, FLAGS flFlags, ULONG ulReserved) { HRESULT hr = 0; BOOL bTempSession = FALSE; nsIMapi* pNsMapi = NULL; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; if (lpMessage->nRecipCount > MAX_RECIPS) return MAPI_E_TOO_MANY_RECIPIENTS; if (lpMessage->nFileCount > MAX_FILES) return MAPI_E_TOO_MANY_FILES; if ((!(flFlags & MAPI_DIALOG)) && (lpMessage->lpRecips == NULL)) return MAPI_E_UNKNOWN_RECIPIENT; if (!lhSession || pNsMapi->IsValidSession(lhSession) != S_OK) { FLAGS LoginFlag = flFlags & (MAPI_LOGON_UI | MAPI_NEW_SESSION); hr = MAPILogon(ulUIParam, nullptr, nullptr, LoginFlag, 0, &lhSession); if (hr != SUCCESS_SUCCESS) return MAPI_E_LOGIN_FAILURE; bTempSession = TRUE; } hr = pNsMapi->SendMail(lhSession, lpMessage, flFlags, ulReserved); // we are seeing a problem when using Word, although we return success from // the MAPI support MS COM interface in mozilla, we are getting this error // here. This is a temporary hack !! if (hr == (HRESULT)0x800703e6) hr = SUCCESS_SUCCESS; if (bTempSession) MAPILogoff(lhSession, ulUIParam, 0, 0); return hr; } ULONG FAR PASCAL MAPISendMailW(LHANDLE lhSession, ULONG ulUIParam, nsMapiMessageW* lpMessage, FLAGS flFlags, ULONG ulReserved) { HRESULT hr = 0; BOOL bTempSession = FALSE; nsIMapi* pNsMapi = nullptr; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; if (lpMessage->nRecipCount > MAX_RECIPS) return MAPI_E_TOO_MANY_RECIPIENTS; if (lpMessage->nFileCount > MAX_FILES) return MAPI_E_TOO_MANY_FILES; if ((!(flFlags & MAPI_DIALOG)) && (lpMessage->lpRecips == nullptr)) return MAPI_E_UNKNOWN_RECIPIENT; if (!lhSession || pNsMapi->IsValidSession(lhSession) != S_OK) { FLAGS LoginFlag = flFlags & (MAPI_LOGON_UI | MAPI_NEW_SESSION); hr = MAPILogon(ulUIParam, nullptr, nullptr, LoginFlag, 0, &lhSession); if (hr != SUCCESS_SUCCESS) return MAPI_E_LOGIN_FAILURE; bTempSession = TRUE; } hr = pNsMapi->SendMailW(lhSession, lpMessage, flFlags, ulReserved); // we are seeing a problem when using Word, although we return success from // the MAPI support MS COM interface in mozilla, we are getting this error // here. This is a temporary hack !! if (hr == (HRESULT)0x800703e6) hr = SUCCESS_SUCCESS; if (bTempSession) MAPILogoff(lhSession, ulUIParam, 0, 0); return hr; } ULONG FAR PASCAL MAPISendDocuments(ULONG ulUIParam, LPSTR lpszDelimChar, LPSTR lpszFilePaths, LPSTR lpszFileNames, ULONG ulReserved) { LHANDLE lhSession; nsIMapi* pNsMapi = NULL; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; unsigned long result = MAPILogon(ulUIParam, nullptr, nullptr, MAPI_LOGON_UI, 0, &lhSession); if (result != SUCCESS_SUCCESS) return MAPI_E_LOGIN_FAILURE; HRESULT hr; hr = pNsMapi->SendDocuments(lhSession, lpszDelimChar, lpszFilePaths, lpszFileNames, ulReserved); MAPILogoff(lhSession, ulUIParam, 0, 0); return hr; } ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession, ULONG ulUIParam, const LPSTR lpszMessageType, const LPSTR lpszSeedMessageID, FLAGS flFlags, ULONG ulReserved, unsigned char lpszMessageID[64]) { nsIMapi* pNsMapi = NULL; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; if (lhSession == 0) return MAPI_E_INVALID_SESSION; return pNsMapi->FindNext(lhSession, ulUIParam, lpszMessageType, lpszSeedMessageID, flFlags, ulReserved, lpszMessageID); } ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageID, FLAGS flFlags, ULONG ulReserved, nsMapiMessage** lppMessage) { nsIMapi* pNsMapi = NULL; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; if (lhSession == 0) return MAPI_E_INVALID_SESSION; return pNsMapi->ReadMail(lhSession, ulUIParam, lpszMessageID, flFlags, ulReserved, lppMessage); } ULONG FAR PASCAL MAPISaveMail(LHANDLE lhSession, ULONG ulUIParam, lpnsMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved, LPSTR lpszMessageID) { nsIMapi* pNsMapi = NULL; if (lhSession == 0) return MAPI_E_INVALID_SESSION; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; return MAPI_E_FAILURE; } ULONG FAR PASCAL MAPIDeleteMail(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszMessageID, FLAGS flFlags, ULONG ulReserved) { nsIMapi* pNsMapi = NULL; if (lhSession == 0) return MAPI_E_INVALID_SESSION; if (!InitMozillaReference(&pNsMapi)) return MAPI_E_FAILURE; return pNsMapi->DeleteMail(lhSession, ulUIParam, lpszMessageID, flFlags, ulReserved); } ULONG FAR PASCAL MAPIAddress(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszCaption, ULONG nEditFields, LPSTR lpszLabels, ULONG nRecips, lpMapiRecipDesc lpRecips, FLAGS flFlags, ULONG ulReserved, LPULONG lpnNewRecips, lpMapiRecipDesc FAR* lppNewRecips) { return MAPI_E_NOT_SUPPORTED; } ULONG FAR PASCAL MAPIDetails(LHANDLE lhSession, ULONG ulUIParam, lpMapiRecipDesc lpRecip, FLAGS flFlags, ULONG ulReserved) { return MAPI_E_NOT_SUPPORTED; } ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession, ULONG ulUIParam, LPSTR lpszName, FLAGS flFlags, ULONG ulReserved, lpMapiRecipDesc FAR* lppRecip) { char* lpszRecipName = new char[(strlen((const char*)lpszName) + 1)]; if (lpszRecipName == NULL) return MAPI_E_INSUFFICIENT_MEMORY; char* lpszRecipAddress = new char[(strlen((const char*)lpszName) + 6)]; if (!lpszRecipAddress) { delete[] lpszRecipName; return MAPI_E_INSUFFICIENT_MEMORY; } strcpy(lpszRecipName, (const char*)lpszName); strcpy(lpszRecipAddress, (const char*)lpszName); (*lppRecip) = (lpMapiRecipDesc FAR)malloc(sizeof(MapiRecipDesc)); if (!(*lppRecip)) { delete[] lpszRecipName; delete[] lpszRecipAddress; return MAPI_E_INSUFFICIENT_MEMORY; } (*lppRecip)->ulRecipClass = 1; (*lppRecip)->lpszName = lpszRecipName; (*lppRecip)->lpszAddress = lpszRecipAddress; (*lppRecip)->ulEIDSize = 0; (*lppRecip)->lpEntryID = 0; return SUCCESS_SUCCESS; } void FreeMAPIRecipient(lpMapiRecipDesc pv); void FreeMAPIMessage(lpMapiMessage pv); ULONG FAR PASCAL MAPIFreeBuffer(LPVOID pv) { int i; if (!pv) return S_OK; for (i = 0; i < MAX_POINTERS; i++) { if (pv == memArray[i].lpMem) { if (memArray[i].memType == MAPI_MESSAGE_TYPE) { FreeMAPIMessage((MapiMessage*)pv); memArray[i].lpMem = NULL; } else if (memArray[i].memType == MAPI_RECIPIENT_TYPE) { FreeMAPIRecipient((MapiRecipDesc*)pv); memArray[i].lpMem = NULL; } } } pv = NULL; return S_OK; } ULONG FAR PASCAL GetMapiDllVersion() { return 94; } void FreeMAPIFile(lpMapiFileDesc pv) { if (!pv) return; if (pv->lpszPathName != NULL) free(pv->lpszPathName); if (pv->lpszFileName != NULL) free(pv->lpszFileName); } void FreeMAPIMessage(lpMapiMessage pv) { ULONG i; if (!pv) return; if (pv->lpszSubject != NULL) free(pv->lpszSubject); if (pv->lpszNoteText) free(pv->lpszNoteText); if (pv->lpszMessageType) free(pv->lpszMessageType); if (pv->lpszDateReceived) free(pv->lpszDateReceived); if (pv->lpszConversationID) free(pv->lpszConversationID); if (pv->lpOriginator) FreeMAPIRecipient(pv->lpOriginator); for (i = 0; i < pv->nRecipCount; i++) { if (&(pv->lpRecips[i]) != NULL) { FreeMAPIRecipient(&(pv->lpRecips[i])); } } if (pv->lpRecips != NULL) { free(pv->lpRecips); } for (i = 0; i < pv->nFileCount; i++) { if (&(pv->lpFiles[i]) != NULL) { FreeMAPIFile(&(pv->lpFiles[i])); } } if (pv->lpFiles != NULL) { free(pv->lpFiles); } free(pv); pv = NULL; } void FreeMAPIRecipient(lpMapiRecipDesc pv) { if (!pv) return; if (pv->lpszName != NULL) free(pv->lpszName); if (pv->lpszAddress != NULL) free(pv->lpszAddress); if (pv->lpEntryID != NULL) free(pv->lpEntryID); }