Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,36 @@
#
# 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/.
MIDL_GENERATED_FILES = msgMapi.h msgMapi_p.c msgMapi_i.c dlldata.c
INSTALL_TARGETS += msgmapi
msgmapi_FILES := msgMapi.h
msgmapi_DEST = $(DIST)/include
msgmapi_TARGET := export
SRCDIR_CSRCS = $(addprefix $(srcdir)/,$(CSRCS))
GARBAGE += $(MIDL_GENERATED_FILES) done_gen $(CSRCS) $(SRCDIR_CSRCS)
EMBED_MANIFEST_AT = 2
CSRCS += \
dlldata.c \
msgMapi_i.c \
msgMapi_p.c \
$(NULL)
include $(topsrcdir)/config/rules.mk
$(MIDL_GENERATED_FILES): done_gen
done_gen: msgMapi.idl
$(RM) $(SRCDIR_CSRCS)
$(MIDL) $(MIDL_FLAGS) $(UNICODE_FLAGS) $(srcdir)/msgMapi.idl
touch $@
export:: done_gen

View file

@ -0,0 +1,13 @@
; 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/.
LIBRARY MapiProxy.dll
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
GetProxyDllInfo PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

View file

@ -0,0 +1,6 @@
WIN32_MODULE_FILEVERSION=0,8,0,0
WIN32_MODULE_FILEVERSION_STRING=0.8
WIN32_MODULE_COPYRIGHT=©Thunderbird and Mozilla Developers, according to the MPL 1.1/GPL 2.0/LGPL 2.1 licenses, as applicable.
WIN32_MODULE_COMPANYNAME=Mozilla.org
WIN32_MODULE_TRADEMARKS=Mozilla
WIN32_MODULE_COMMENT=Mozilla Thunderbird Thunderbird MAPI Proxy Dll

View file

@ -0,0 +1,22 @@
# vim: set filetype=python:
# 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/.
SharedLibrary('MapiProxy')
OS_LIBS += [
'rpcrt4',
]
for var in ('REGISTER_PROXY_DLL', 'UNICODE', '_UNICODE'):
DEFINES[var] = True
# This produces a compile warning mozilla-config.h(145): warning C4005: '_WIN32_WINNT': macro redefinition
#DEFINES['_WIN32_WINNT'] = '0x400'
if not CONFIG['MOZ_INCOMPLETE_EXTERNAL_LINKAGE']:
DEFINES['MOZILLA_INTERNAL_API'] = True
DEFFILE = SRCDIR + '/MapiProxy.def'

View file

@ -0,0 +1,93 @@
/* 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/. */
// This idl will be compiled by MIDL. MS-COM is used
// as bridge between MAPI clients and the Mozilla.
import "unknwn.idl";
typedef wchar_t LOGIN_PW_TYPE[256];
typedef struct
{
unsigned long ulReserved;
unsigned long flFlags; /* Flags */
unsigned long nPosition_NotUsed; /* character in text to be replaced by attachment */
LPTSTR lpszPathName; /* Full path name including file name */
LPTSTR lpszFileName; /* Real (original) file name */
unsigned char * lpFileType_NotUsed ;
} nsMapiFileDesc, * lpnsMapiFileDesc;
typedef struct
{
unsigned long ulReserved;
unsigned long ulRecipClass; /* MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG */
LPSTR lpszName; /* Recipient name to display */
LPSTR lpszAddress; /* Recipient email address */
unsigned long ulEIDSize_NotUsed;
unsigned char * lpEntryID_NotUsed ;
} nsMapiRecipDesc, * lpnsMapiRecipDesc;
typedef struct
{
unsigned long ulReserved;
LPSTR lpszSubject; /* Message Subject */
LPSTR lpszNoteText; /* Message Text */
LPSTR lpszMessageType;
LPSTR lpszDateReceived; /* in YYYY/MM/DD HH:MM format */
LPSTR lpszConversationID_NotUsed; /* conversation thread ID */
unsigned long flFlags; /* unread,return receipt */
lpnsMapiRecipDesc lpOriginator; /* Originator descriptor */
unsigned long nRecipCount; /* Number of recipients */
[size_is (nRecipCount)] lpnsMapiRecipDesc lpRecips;/* Recipient descriptors */
unsigned long nFileCount; /* # of file attachments */
[size_is (nFileCount)] lpnsMapiFileDesc lpFiles; /* Attachment descriptors */
} nsMapiMessage, * lpnsMapiMessage;
[
object,
uuid(6EDCD38E-8861-11d5-A3DD-00B0D0F3BAA7),
helpstring("nsIMapi Inteface"),
pointer_default(unique)
]
interface nsIMapi : IUnknown
{
HRESULT Login([in] unsigned long aUIArg, [in, unique] LOGIN_PW_TYPE aLogin,
[in, unique] LOGIN_PW_TYPE aPassWord, [in] unsigned long aFlags,
[out] unsigned long *aSessionId);
HRESULT Initialize();
HRESULT IsValid();
HRESULT IsValidSession([in] unsigned long aSession);
HRESULT SendMail([in] unsigned long aSession, [in, unique] lpnsMapiMessage aMessage,
[in] short aRecipCount, [in, size_is(aRecipCount)] lpnsMapiRecipDesc aRecips,
[in] short aFileCount, [in, size_is(aFileCount)] lpnsMapiFileDesc aFiles,
[in] unsigned long aFlags, [in] unsigned long aReserved) ;
HRESULT SendDocuments( [in] unsigned long aSession,
[in, unique] LPTSTR aDelimChar, [in, unique] LPTSTR aFilePaths,
[in, unique] LPTSTR aFileNames, [in] ULONG aFlags ) ;
HRESULT FindNext( [in] unsigned long aSession, [in] ULONG ulUIParam, [in, unique] LPTSTR lpszMessageType,
[in, unique] LPTSTR lpszSeedMessageID, [in] ULONG flFlags, [in] ULONG ulReserved,
[in] [out] char lpszMessageID[64] ) ;
HRESULT ReadMail( [in] unsigned long lhSession, [in] ULONG ulUIParam, [in, unique] LPTSTR lpszMessageID,
[in] ULONG flFlags, [in] ULONG ulReserved, [out] lpnsMapiMessage *lppMessage);
HRESULT DeleteMail( [in] unsigned long lhSession, [in] ULONG ulUIParam, [in, unique] LPTSTR lpszMessageID,
[in] ULONG flFlags, [in] ULONG ulReserved);
HRESULT SaveMail( [in] unsigned long lhSession, [in] ULONG ulUIParam, [in, unique] lpnsMapiMessage lppMessage,
[in] ULONG flFlags, [in] ULONG ulReserved, [in, unique] LPTSTR lpszMessageID);
HRESULT Logoff (unsigned long aSession);
HRESULT CleanUp();
};

View file

@ -0,0 +1,11 @@
# vim: set filetype=python:
# 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/.
DIRS += [
'public',
'build',
'src',
]

View file

@ -0,0 +1,11 @@
# vim: set filetype=python:
# 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/.
XPIDL_SOURCES += [
'nsIMapiSupport.idl',
]
XPIDL_MODULE = 'mapihook'

View file

@ -0,0 +1,44 @@
/* 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 "nsISupports.idl"
/**
* This interface provides support for registering Mozilla as a COM component
* for extending the use of Mail/News through Simple MAPI.
*
*/
[noscript, uuid(2907B676-C4BD-49af-880A-E27A0616291E)]
interface nsIMapiSupport : nsISupports {
/** Initiates MAPI support
*/
void initializeMAPISupport();
/** Shuts down the MAPI support
*/
void shutdownMAPISupport();
/** registerServer - register the mapi DLL with the desktop
* Typically called by the window shell service when we are
* made the default mail app
*/
void registerServer();
/** unRegisterServer - unregister the mapi DLL with the desktop
* Typically called by the window shell service when we are
* removed as the default mail app.
*/
void unRegisterServer();
};
%{C++
#define NS_IMAPISUPPORT_CONTRACTID "@mozilla.org/mapisupport;1"
#define NS_IMAPISUPPORT_CLASSNAME "Mozilla MAPI Support"
%}

View file

@ -0,0 +1,6 @@
#
# 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/.
CSRCS += ../build/msgMapi_i.c

View file

@ -0,0 +1,291 @@
/* 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/. */
#undef _UNICODE
#undef UNICODE
#include <objbase.h>
#include "nsStringGlue.h"
#include "Registry.h"
#define MAPI_PROXY_DLL_NAME "MapiProxy.dll"
#define MAPI_STARTUP_ARG " /MAPIStartUp"
#define MAX_SIZE 2048
// Size of a CLSID as a string
const int CLSID_STRING_SIZE = 39;
// Proxy/Stub Dll Routines
typedef HRESULT (__stdcall ProxyServer)();
// Convert a CLSID to a char string.
BOOL CLSIDtochar(const CLSID& clsid, char* szCLSID,
int length)
{
LPOLESTR wszCLSID = NULL;
// Get CLSID
HRESULT hr = StringFromCLSID(clsid, &wszCLSID);
if (FAILED(hr))
return FALSE;
// Covert from wide characters to non-wide.
wcstombs(szCLSID, wszCLSID, length);
// Free memory.
CoTaskMemFree(wszCLSID);
return TRUE;
}
// Create a key and set its value.
BOOL setKeyAndValue(nsAutoCString keyName, const char* subKey,
const char* theValue)
{
HKEY hKey;
BOOL retValue = TRUE;
nsAutoCString theKey(keyName);
if (subKey != NULL)
{
theKey += "\\";
theKey += subKey;
}
// Create and open key and subkey.
long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, theKey.get(),
0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (lResult != ERROR_SUCCESS)
return FALSE ;
// Set the Value.
if (theValue != NULL)
{
lResult = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)theValue,
strlen(theValue)+1);
if (lResult != ERROR_SUCCESS)
retValue = FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
// Delete a key and all of its descendents.
LONG recursiveDeleteKey(HKEY hKeyParent, // Parent of key to delete
const char* lpszKeyChild) // Key to delete
{
// Open the child.
HKEY hKeyChild ;
LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
KEY_ALL_ACCESS, &hKeyChild) ;
if (lRes != ERROR_SUCCESS)
{
return lRes ;
}
// Enumerate all of the decendents of this child.
FILETIME time ;
char szBuffer[MAX_SIZE] ;
DWORD dwSize = MAX_SIZE ;
while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
NULL, NULL, &time) == S_OK)
{
// Delete the decendents of this child.
lRes = recursiveDeleteKey(hKeyChild, szBuffer) ;
if (lRes != ERROR_SUCCESS)
{
// Cleanup before exiting.
RegCloseKey(hKeyChild) ;
return lRes;
}
dwSize = MAX_SIZE;
}
// Close the child.
RegCloseKey(hKeyChild) ;
// Delete this child.
return RegDeleteKey(hKeyParent, lpszKeyChild) ;
}
void RegisterProxy()
{
HINSTANCE h = NULL;
ProxyServer *RegisterFunc = NULL;
char szModule[MAX_SIZE];
char *pTemp = NULL;
HMODULE hModule = GetModuleHandle(NULL);
DWORD dwResult = ::GetModuleFileName(hModule, szModule,
sizeof(szModule)/sizeof(char));
if (dwResult == 0)
return;
pTemp = strrchr(szModule, '\\');
if (pTemp == NULL)
return;
*pTemp = '\0';
nsAutoCString proxyPath(szModule);
proxyPath += "\\";
proxyPath += MAPI_PROXY_DLL_NAME;
h = LoadLibrary(proxyPath.get());
if (h == NULL)
return;
RegisterFunc = (ProxyServer *) GetProcAddress(h, "DllRegisterServer");
if (RegisterFunc)
RegisterFunc();
FreeLibrary(h);
}
void UnRegisterProxy()
{
HINSTANCE h = NULL;
ProxyServer *UnRegisterFunc = NULL;
char szModule[MAX_SIZE];
char *pTemp = NULL;
HMODULE hModule = GetModuleHandle(NULL);
DWORD dwResult = ::GetModuleFileName(hModule, szModule,
sizeof(szModule)/sizeof(char));
if (dwResult == 0)
return;
pTemp = strrchr(szModule, '\\');
if (pTemp == NULL)
return;
*pTemp = '\0';
nsAutoCString proxyPath(szModule);
proxyPath += "\\";
proxyPath += MAPI_PROXY_DLL_NAME;
h = LoadLibrary(proxyPath.get());
if (h == NULL)
return;
UnRegisterFunc = (ProxyServer *) GetProcAddress(h, "DllUnregisterServer");
if (UnRegisterFunc)
UnRegisterFunc();
FreeLibrary(h);
}
// Register the component in the registry.
HRESULT RegisterServer(const CLSID& clsid, // Class ID
const char* szFriendlyName, // Friendly Name
const char* szVerIndProgID, // Programmatic
const char* szProgID) // IDs
{
HMODULE hModule = GetModuleHandle(NULL);
char szModuleName[MAX_SIZE];
char szCLSID[CLSID_STRING_SIZE];
nsAutoCString independentProgId(szVerIndProgID);
nsAutoCString progId(szProgID);
DWORD dwResult = ::GetModuleFileName(hModule, szModuleName,
sizeof(szModuleName)/sizeof(char));
if (dwResult == 0)
return S_FALSE;
nsAutoCString moduleName(szModuleName);
nsAutoCString registryKey("CLSID\\");
moduleName += MAPI_STARTUP_ARG;
// Convert the CLSID into a char.
if (!CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)))
return S_FALSE;
registryKey += szCLSID;
// Add the CLSID to the registry.
if (!setKeyAndValue(registryKey, NULL, szFriendlyName))
return S_FALSE;
if (!setKeyAndValue(registryKey, "LocalServer32", moduleName.get()))
return S_FALSE;
// Add the ProgID subkey under the CLSID key.
if (!setKeyAndValue(registryKey, "ProgID", szProgID))
return S_FALSE;
// Add the version-independent ProgID subkey under CLSID key.
if (!setKeyAndValue(registryKey, "VersionIndependentProgID", szVerIndProgID))
return S_FALSE;
// Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
if (!setKeyAndValue(independentProgId, NULL, szFriendlyName))
return S_FALSE;
if (!setKeyAndValue(independentProgId, "CLSID", szCLSID))
return S_FALSE;
if (!setKeyAndValue(independentProgId, "CurVer", szProgID))
return S_FALSE;
// Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
if (!setKeyAndValue(progId, NULL, szFriendlyName))
return S_FALSE;
if (!setKeyAndValue(progId, "CLSID", szCLSID))
return S_FALSE;
RegisterProxy();
return S_OK;
}
LONG UnregisterServer(const CLSID& clsid, // Class ID
const char* szVerIndProgID, // Programmatic
const char* szProgID) // IDs
{
LONG lResult = S_OK;
// Convert the CLSID into a char.
char szCLSID[CLSID_STRING_SIZE];
if (!CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)))
return S_FALSE;
UnRegisterProxy();
nsAutoCString registryKey("CLSID\\");
registryKey += szCLSID;
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, registryKey.get());
if (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND)
return lResult;
registryKey += "\\LocalServer32";
// Delete only the path for this server.
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, registryKey.get());
if (lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND)
return lResult;
// Delete the version-independent ProgID Key.
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID);
if (lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND)
return lResult;
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID);
return lResult;
}

View file

@ -0,0 +1,23 @@
/* 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/. */
#ifndef _REGISTRY_H_
#define _REGISTRY_H_
#include <objbase.h>
// This function will register a component in the Registry.
HRESULT RegisterServer(const CLSID& clsid,
const char* szFriendlyName,
const char* szVerIndProgID,
const char* szProgID) ;
// This function will unregister a component.
HRESULT UnregisterServer(const CLSID& clsid,
const char* szVerIndProgID,
const char* szProgID) ;
#endif

View file

@ -0,0 +1,25 @@
# vim: set filetype=python:
# 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/.
SOURCES += [
'msgMapiFactory.cpp',
'msgMapiHook.cpp',
'msgMapiImp.cpp',
'msgMapiMain.cpp',
'msgMapiSupport.cpp',
'Registry.cpp',
]
if CONFIG['MOZ_INCOMPLETE_EXTERNAL_LINKAGE']:
XPCOMBinaryComponent('msgMapi')
else:
FINAL_LIBRARY = 'xul'
OS_LIBS += [
'ole32',
]
DEFINES['UNICODE'] = True
DEFINES['_UNICODE'] = True

View file

@ -0,0 +1,85 @@
/* 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/. */
#undef UNICODE
#undef _UNICODE
#include "msgMapiFactory.h"
#include "msgMapiImp.h"
#include "msgMapi.h"
CMapiFactory ::CMapiFactory()
: m_cRef(1)
{
}
CMapiFactory::~CMapiFactory()
{
}
STDMETHODIMP CMapiFactory::QueryInterface(const IID& aIid, void** aPpv)
{
if ((aIid == IID_IUnknown) || (aIid == IID_IClassFactory))
{
*aPpv = static_cast<IClassFactory*>(this);
}
else
{
*aPpv = nullptr;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*aPpv)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CMapiFactory::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CMapiFactory::Release()
{
int32_t temp = --m_cRef;
if (m_cRef == 0)
{
delete this;
return 0;
}
return temp;
}
STDMETHODIMP CMapiFactory::CreateInstance(IUnknown* aUnknownOuter,
const IID& aIid,
void** aPpv)
{
// Cannot aggregate.
if (aUnknownOuter != nullptr)
{
return CLASS_E_NOAGGREGATION ;
}
// Create component.
CMapiImp* pImp = new CMapiImp();
if (pImp == nullptr)
{
return E_OUTOFMEMORY ;
}
// Get the requested interface.
HRESULT hr = pImp->QueryInterface(aIid, aPpv);
// Release the IUnknown pointer.
// (If QueryInterface failed, component will delete itself.)
pImp->Release();
return hr;
}
STDMETHODIMP CMapiFactory::LockServer(BOOL aLock)
{
return S_OK ;
}

View file

@ -0,0 +1,39 @@
/* 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/. */
#ifndef MSG_MAPI_FACTORY_H
#define MSG_MAPI_FACTORY_H
#include <windows.h>
#include <objbase.h>
#include "nspr.h"
#include "nsISupportsImpl.h" // ThreadSafeAutoRefCnt
#include <stdint.h>
class CMapiFactory : public IClassFactory
{
public :
// IUnknown
STDMETHODIMP QueryInterface (REFIID aIid, void** aPpv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IClassFactory
STDMETHODIMP CreateInstance (LPUNKNOWN aUnkOuter, REFIID aIid, void **aPpv);
STDMETHODIMP LockServer (BOOL aLock);
CMapiFactory ();
private:
mozilla::ThreadSafeAutoRefCnt m_cRef;
~CMapiFactory ();
};
#endif // MSG_MAPI_FACTORY_H

View file

@ -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 ;
}

View file

@ -0,0 +1,33 @@
/* 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/. */
#ifndef MSG_MAPI_HOOK_H_
#define MSG_MAPI_HOOK_H_
#include "prtypes.h"
class nsMapiHook
{
public :
static bool DisplayLoginDialog(bool aLogin, char16_t **aUsername,
char16_t **aPassword);
static bool VerifyUserName(const nsString& aUsername, nsCString& aIdKey);
static bool IsBlindSendAllowed () ;
static nsresult BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields) ;
static nsresult ShowComposerWindow (unsigned long aSession, nsIMsgCompFields * aCompFields) ;
static nsresult PopulateCompFields(lpnsMapiMessage aMessage, nsIMsgCompFields * aCompFields) ;
static nsresult PopulateCompFieldsWithConversion(lpnsMapiMessage aMessage,
nsIMsgCompFields * aCompFields) ;
static nsresult PopulateCompFieldsForSendDocs(nsIMsgCompFields * aCompFields,
ULONG aFlags, LPTSTR aDelimChar, LPTSTR aFilePaths) ;
static nsresult HandleAttachments (nsIMsgCompFields * aCompFields, int32_t aFileCount,
lpnsMapiFileDesc aFiles, BOOL aIsUnicode) ;
static void CleanUp();
static bool isMapiService;
};
#endif // MSG_MAPI_HOOK_H_

View file

@ -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;
}

View file

@ -0,0 +1,77 @@
/* 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/. */
#ifndef MSG_MAPI_IMP_H
#define MSG_MAPI_IMP_H
#include <windows.h>
#include <mapi.h>
#include "msgMapi.h"
#include "nspr.h"
#include "nscore.h"
#include "nsISupportsImpl.h" // ThreadSafeAutoRefCnt
class nsIMsgFolder;
class MsgMapiListContext;
const CLSID CLSID_CMapiImp = {0x29f458be, 0x8866, 0x11d5, {0xa3, 0xdd, 0x0, 0xb0, 0xd0, 0xf3, 0xba, 0xa7}};
// this class implements the MS COM interface nsIMapi that provides the methods
// called by mapi32.dll to perform the mail operations as specified by MAPI.
// These class methods in turn use the Mozilla Mail XPCOM interfaces to do so.
class CMapiImp : public nsIMapi
{
public :
// IUnknown
STDMETHODIMP QueryInterface(const IID& aIid, void** aPpv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// Interface INsMapi
STDMETHODIMP Login(unsigned long aUIArg, LOGIN_PW_TYPE aLogin,
LOGIN_PW_TYPE aPassWord, unsigned long aFlags,
unsigned long *aSessionId);
STDMETHODIMP SendMail( unsigned long aSession, lpnsMapiMessage aMessage,
short aRecipCount, lpnsMapiRecipDesc aRecips ,
short aFileCount, lpnsMapiFileDesc aFiles ,
unsigned long aFlags, unsigned long aReserved) ;
STDMETHODIMP SendDocuments( unsigned long aSession, LPTSTR aDelimChar,
LPTSTR aFilePaths, LPTSTR aFileNames, ULONG aFlags);
STDMETHODIMP FindNext( unsigned long aSession, unsigned long ulUIParam, LPTSTR lpszMessageType,
LPTSTR lpszSeedMessageID, unsigned long flFlags, unsigned long ulReserved,
unsigned char lpszMessageID[64] );
STDMETHODIMP ReadMail(unsigned long lhSession, unsigned long ulUIParam, LPTSTR lpszMessageID,
unsigned long flFlags, unsigned long ulReserved, lpnsMapiMessage *lppMessage);
STDMETHODIMP DeleteMail(unsigned long lhSession, unsigned long ulUIParam, LPTSTR lpszMessageID,
unsigned long flFlags, unsigned long ulReserved);
STDMETHODIMP SaveMail(unsigned long lhSession, unsigned long ulUIParam, lpnsMapiMessage lppMessage,
unsigned long flFlags, unsigned long ulReserved, LPTSTR lpszMessageID);
STDMETHODIMP Initialize();
STDMETHODIMP IsValid();
STDMETHODIMP IsValidSession(unsigned long aSession);
STDMETHODIMP Logoff (unsigned long aSession);
STDMETHODIMP CleanUp();
CMapiImp();
~CMapiImp();
LONG InitContext(unsigned long session, MsgMapiListContext **listContext);
nsresult GetDefaultInbox(nsIMsgFolder **inboxFolder);
private :
PRLock *m_Lock;
mozilla::ThreadSafeAutoRefCnt m_cRef;
};
#endif // MSG_MAPI_IMP_H

View file

@ -0,0 +1,306 @@
/* 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 "msgCore.h"
#include "nsComposeStrings.h"
#include "msgMapiMain.h"
#include "nsIServiceManager.h"
#include "nsCOMPtr.h"
nsMAPIConfiguration *nsMAPIConfiguration::m_pSelfRef = nullptr;
uint32_t nsMAPIConfiguration::session_generator = 0;
uint32_t nsMAPIConfiguration::sessionCount = 0;
nsMAPIConfiguration *nsMAPIConfiguration::GetMAPIConfiguration()
{
if (m_pSelfRef == nullptr)
m_pSelfRef = new nsMAPIConfiguration();
return m_pSelfRef;
}
nsMAPIConfiguration::nsMAPIConfiguration()
: m_nMaxSessions(MAX_SESSIONS)
{
m_Lock = PR_NewLock();
}
nsMAPIConfiguration::~nsMAPIConfiguration()
{
if (m_Lock)
PR_DestroyLock(m_Lock);
}
void nsMAPIConfiguration::OpenConfiguration()
{
// No. of max. sessions is set to MAX_SESSIONS. In future
// if it is decided to have configuration (registry)
// parameter, this function can be used to set the
// max sessions;
return;
}
int16_t nsMAPIConfiguration::RegisterSession(uint32_t aHwnd,
const char16_t *aUserName, const char16_t *aPassword,
bool aForceDownLoad, bool aNewSession,
uint32_t *aSession, const char *aIdKey)
{
int16_t nResult = 0;
uint32_t n_SessionId = 0;
PR_Lock(m_Lock);
// Check whether max sessions is exceeded
if (sessionCount >= m_nMaxSessions)
{
PR_Unlock(m_Lock);
return -1;
}
if (aUserName != nullptr && aUserName[0] != '\0')
m_ProfileMap.Get(nsDependentString(aUserName), &n_SessionId);
// try to share a session; if not create a session
if (n_SessionId > 0)
{
nsMAPISession *pTemp = nullptr;
m_SessionMap.Get(n_SessionId, &pTemp);
if (pTemp != nullptr)
{
pTemp->IncrementSession();
*aSession = n_SessionId;
nResult = 1;
}
}
else if (aNewSession || n_SessionId == 0) // checking for n_SessionId is a concession
{
// create a new session; if new session is specified OR there is no session
nsMAPISession *pTemp = nullptr;
pTemp = new nsMAPISession(aHwnd, aUserName,
aPassword, aForceDownLoad, aIdKey);
if (pTemp != nullptr)
{
session_generator++;
// I don't think there will be (2 power 32) sessions alive
// in a cycle. This is an assumption
if (session_generator == 0)
session_generator++;
m_SessionMap.Put(session_generator, pTemp);
if (aUserName != nullptr && aUserName[0] != '\0')
m_ProfileMap.Put(nsDependentString(aUserName), session_generator);
*aSession = session_generator;
sessionCount++;
nResult = 1;
}
}
PR_Unlock(m_Lock);
return nResult;
}
bool nsMAPIConfiguration::UnRegisterSession(uint32_t aSessionID)
{
bool bResult = false;
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsMAPISession *pTemp = nullptr;
m_SessionMap.Get(aSessionID, &pTemp);
if (pTemp != nullptr)
{
if (pTemp->DecrementSession() == 0)
{
if (pTemp->m_pProfileName.get() != nullptr)
m_ProfileMap.Remove(pTemp->m_pProfileName);
m_SessionMap.Remove(aSessionID);
sessionCount--;
bResult = true;
}
}
}
PR_Unlock(m_Lock);
return bResult;
}
bool nsMAPIConfiguration::IsSessionValid(uint32_t aSessionID)
{
if (aSessionID == 0)
return false;
bool retValue = false;
PR_Lock(m_Lock);
retValue = m_SessionMap.Get(aSessionID, NULL);
PR_Unlock(m_Lock);
return retValue;
}
char16_t *nsMAPIConfiguration::GetPassword(uint32_t aSessionID)
{
char16_t *pResult = nullptr;
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsMAPISession *pTemp = nullptr;
m_SessionMap.Get(aSessionID, &pTemp);
if (pTemp)
pResult = pTemp->GetPassword();
}
PR_Unlock(m_Lock);
return pResult;
}
void *nsMAPIConfiguration::GetMapiListContext(uint32_t aSessionID)
{
void *pResult = nullptr;
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsMAPISession *pTemp = nullptr;
m_SessionMap.Get(aSessionID, &pTemp);
if (pTemp)
pResult = pTemp->GetMapiListContext();
}
PR_Unlock(m_Lock);
return pResult;
}
void nsMAPIConfiguration::SetMapiListContext(uint32_t aSessionID, void *mapiListContext)
{
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsMAPISession *pTemp = nullptr;
m_SessionMap.Get(aSessionID, &pTemp);
if (pTemp)
pTemp->SetMapiListContext(mapiListContext);
}
PR_Unlock(m_Lock);
}
void nsMAPIConfiguration::GetIdKey(uint32_t aSessionID, nsCString& aKey)
{
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsMAPISession *pTemp = nullptr;
m_SessionMap.Get(aSessionID, &pTemp);
if (pTemp)
pTemp->GetIdKey(aKey);
}
PR_Unlock(m_Lock);
return;
}
// util func
HRESULT nsMAPIConfiguration::GetMAPIErrorFromNSError (nsresult res)
{
HRESULT hr = SUCCESS_SUCCESS;
if (NS_SUCCEEDED (res)) return hr;
// if failure return the related MAPI failure code
switch (res)
{
case NS_MSG_NO_RECIPIENTS :
hr = MAPI_E_BAD_RECIPTYPE;
break;
case NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS :
hr = MAPI_E_INVALID_RECIPS;
break;
case NS_ERROR_SMTP_AUTH_FAILURE :
case NS_ERROR_SMTP_AUTH_GSSAPI :
case NS_ERROR_SMTP_AUTH_MECH_NOT_SUPPORTED :
case NS_ERROR_SMTP_AUTH_NOT_SUPPORTED :
case NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_NO_SSL :
case NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_SSL :
case NS_ERROR_SMTP_AUTH_CHANGE_PLAIN_TO_ENCRYPT :
hr = MAPI_E_LOGIN_FAILURE;
break;
case NS_MSG_UNABLE_TO_OPEN_FILE :
case NS_MSG_UNABLE_TO_OPEN_TMP_FILE :
case NS_MSG_COULDNT_OPEN_FCC_FOLDER :
case NS_ERROR_FILE_INVALID_PATH :
hr = MAPI_E_ATTACHMENT_OPEN_FAILURE;
break;
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST :
hr = MAPI_E_ATTACHMENT_NOT_FOUND;
break;
case NS_MSG_CANCELLING :
hr = MAPI_E_USER_ABORT;
break;
case NS_MSG_ERROR_WRITING_FILE :
case NS_MSG_UNABLE_TO_SAVE_TEMPLATE :
case NS_MSG_UNABLE_TO_SAVE_DRAFT :
hr = MAPI_E_ATTACHMENT_WRITE_FAILURE;
break;
default:
hr = MAPI_E_FAILURE;
break;
}
return hr;
}
nsMAPISession::nsMAPISession(uint32_t aHwnd, const char16_t *aUserName,
const char16_t *aPassword,
bool aForceDownLoad, const char *aKey)
: m_bIsForcedDownLoad(aForceDownLoad),
m_hAppHandle(aHwnd),
m_nShared(1),
m_pIdKey(aKey)
{
m_listContext = NULL;
m_pProfileName.Assign(aUserName);
m_pPassword.Assign(aPassword);
}
nsMAPISession::~nsMAPISession()
{
}
uint32_t nsMAPISession::IncrementSession()
{
return ++m_nShared;
}
uint32_t nsMAPISession::DecrementSession()
{
return --m_nShared;
}
uint32_t nsMAPISession::GetSessionCount()
{
return m_nShared;
}
char16_t *nsMAPISession::GetPassword()
{
return (char16_t *)m_pPassword.get();
}
void nsMAPISession::GetIdKey(nsCString& aKey)
{
aKey = m_pIdKey;
return;
}

View file

@ -0,0 +1,86 @@
/* 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/. */
#ifndef MSG_MAPI_MAIN_H_
#define NSG_MAPI_MAIN_H_
#define MAX_NAME_LEN 256
#define MAX_PW_LEN 256
#define MAX_SESSIONS 50
#define MAPI_SENDCOMPLETE_EVENT "SendCompletionEvent"
#define MAPI_PROPERTIES_CHROME "chrome://messenger-mapi/locale/mapi.properties"
#define PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND "mapi.blind-send.warn"
#define PREF_MAPI_BLIND_SEND_ENABLED "mapi.blind-send.enabled"
#include "nspr.h"
#include "nsDataHashtable.h"
#include "nsClassHashtable.h"
#include "nsStringGlue.h"
class nsMAPISession;
class nsMAPIConfiguration
{
private :
static uint32_t session_generator;
static uint32_t sessionCount;
static nsMAPIConfiguration *m_pSelfRef;
PRLock *m_Lock;
uint32_t m_nMaxSessions;
nsDataHashtable<nsStringHashKey, uint32_t> m_ProfileMap;
nsClassHashtable<nsUint32HashKey, nsMAPISession> m_SessionMap;
nsMAPIConfiguration();
~nsMAPIConfiguration();
public :
static nsMAPIConfiguration *GetMAPIConfiguration();
void OpenConfiguration();
int16_t RegisterSession(uint32_t aHwnd, const char16_t *aUserName, \
const char16_t *aPassword, bool aForceDownLoad, \
bool aNewSession, uint32_t *aSession, const char *aIdKey);
bool IsSessionValid(uint32_t aSessionID);
bool UnRegisterSession(uint32_t aSessionID);
char16_t *GetPassword(uint32_t aSessionID);
void GetIdKey(uint32_t aSessionID, nsCString& aKey);
void *GetMapiListContext(uint32_t aSessionID);
void SetMapiListContext(uint32_t aSessionID, void *mapiListContext);
// a util func
static HRESULT GetMAPIErrorFromNSError (nsresult res) ;
};
class nsMAPISession
{
friend class nsMAPIConfiguration;
private :
bool m_bIsForcedDownLoad;
bool m_bApp_or_Service;
uint32_t m_hAppHandle;
uint32_t m_nShared;
nsCString m_pIdKey;
nsString m_pProfileName;
nsString m_pPassword;
int32_t m_messageIndex;
void *m_listContext; // used by findNext
public :
nsMAPISession(uint32_t aHwnd, const char16_t *aUserName, \
const char16_t *aPassword, \
bool aForceDownLoad, const char *aKey);
uint32_t IncrementSession();
uint32_t DecrementSession();
uint32_t GetSessionCount();
char16_t *nsMAPISession::GetPassword();
void GetIdKey(nsCString& aKey);
~nsMAPISession();
// For enumerating Messages...
void SetMapiListContext( void *listContext) { m_listContext = listContext; }
void *GetMapiListContext( ) { return m_listContext; }
};
#endif // MSG_MAPI_MAIN_H_

View file

@ -0,0 +1,151 @@
/* 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 "nsCOMPtr.h"
#include "objbase.h"
#include "nsISupports.h"
#include "mozilla/ModuleUtils.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#include "nsIAppStartupNotifier.h"
#include "nsIServiceManager.h"
#include "nsIComponentManager.h"
#include "nsICategoryManager.h"
#include "Registry.h"
#include "msgMapiSupport.h"
#include "msgMapiImp.h"
/** Implementation of the nsIMapiSupport interface.
* Use standard implementation of nsISupports stuff.
*/
NS_IMPL_ISUPPORTS(nsMapiSupport, nsIMapiSupport, nsIObserver)
NS_IMETHODIMP
nsMapiSupport::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
{
nsresult rv = NS_OK ;
if (!strcmp(aTopic, "profile-after-change"))
return InitializeMAPISupport();
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
return ShutdownMAPISupport();
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
NS_ENSURE_TRUE(observerService, NS_ERROR_UNEXPECTED);
rv = observerService->AddObserver(this,"profile-after-change", false);
if (NS_FAILED(rv)) return rv;
rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (NS_FAILED(rv)) return rv;
return rv;
}
nsMapiSupport::nsMapiSupport()
: m_dwRegister(0),
m_nsMapiFactory(nullptr)
{
}
nsMapiSupport::~nsMapiSupport()
{
}
NS_IMETHODIMP
nsMapiSupport::InitializeMAPISupport()
{
::OleInitialize(nullptr) ;
if (m_nsMapiFactory == nullptr) // No Registering if already done. Sanity Check!!
{
m_nsMapiFactory = new CMapiFactory();
if (m_nsMapiFactory != nullptr)
{
HRESULT hr = ::CoRegisterClassObject(CLSID_CMapiImp, \
m_nsMapiFactory, \
CLSCTX_LOCAL_SERVER, \
REGCLS_MULTIPLEUSE, \
&m_dwRegister);
if (FAILED(hr))
{
m_nsMapiFactory->Release() ;
m_nsMapiFactory = nullptr;
return NS_ERROR_FAILURE;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsMapiSupport::ShutdownMAPISupport()
{
if (m_dwRegister != 0)
::CoRevokeClassObject(m_dwRegister);
if (m_nsMapiFactory != nullptr)
{
m_nsMapiFactory->Release();
m_nsMapiFactory = nullptr;
}
::OleUninitialize();
return NS_OK ;
}
NS_IMETHODIMP
nsMapiSupport::RegisterServer()
{
// TODO: Figure out what kind of error propogation to pass back
::RegisterServer(CLSID_CMapiImp, "Mozilla MAPI", "MozillaMapi", "MozillaMapi.1");
return NS_OK;
}
NS_IMETHODIMP
nsMapiSupport::UnRegisterServer()
{
// TODO: Figure out what kind of error propogation to pass back
::UnregisterServer(CLSID_CMapiImp, "MozillaMapi", "MozillaMapi.1");
return NS_OK;
}
NS_DEFINE_NAMED_CID(NS_IMAPISUPPORT_CID);
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMapiSupport)
static const mozilla::Module::CategoryEntry kMAPICategories[] = {
{ APPSTARTUP_CATEGORY, "Mapi Support", "service," NS_IMAPISUPPORT_CONTRACTID, },
{ NULL }
};
const mozilla::Module::CIDEntry kMAPICIDs[] = {
{ &kNS_IMAPISUPPORT_CID, false, NULL, nsMapiSupportConstructor },
{ NULL }
};
const mozilla::Module::ContractIDEntry kMAPIContracts[] = {
{ NS_IMAPISUPPORT_CONTRACTID, &kNS_IMAPISUPPORT_CID },
{ NULL }
};
static const mozilla::Module kMAPIModule = {
mozilla::Module::kVersion,
kMAPICIDs,
kMAPIContracts,
kMAPICategories
};
NSMODULE_DEFN(msgMapiModule) = &kMAPIModule;

View file

@ -0,0 +1,34 @@
/* 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/. */
#ifndef MSG_MAPI_SUPPORT_H_
#define MSG_MAPI_SUPPORT_H_
#include "nsIObserver.h"
#include "nsIMapiSupport.h"
#include "msgMapiFactory.h"
#define NS_IMAPISUPPORT_CID \
{0x8967fed2, 0xc8bb, 0x11d5, \
{ 0xa3, 0xe9, 0x00, 0xb0, 0xd0, 0xf3, 0xba, 0xa7 }}
class nsMapiSupport : public nsIMapiSupport,
public nsIObserver
{
public :
nsMapiSupport();
// Declare all interface methods we must implement.
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIMAPISUPPORT
private :
~nsMapiSupport();
DWORD m_dwRegister;
CMapiFactory *m_nsMapiFactory;
};
#endif // MSG_MAPI_SUPPORT_H_