Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

705 lines
18 KiB

/*
Copyright (c) 2000 Microsoft Corporation
Module Name:
smapi.cpp
Abstract:
CSMapi object. Used to support our simple MAPI functions.
Revision History:
created steveshi 08/23/00
*/
#include "stdafx.h"
#include "Rcbdyctl.h"
#include "smapi.h"
#include "mapix.h"
#include "utils.h"
#define C_OEAPP TEXT("Outlook Express")
#define F_ISOE 0x1
#define F_ISCONFIG 0x2
#define LEN_MSOE_DLL 9 // length of "\\msoe.dll"
#define LEN_HMMAPI_DLL 11 // length of "\\hmmapi.dll"
BOOL GetMAPIDefaultProfile(TCHAR*, DWORD*);
#define E_FUNC_NOTFOUND 1000 //Userdefined error no.
// Csmapi
Csmapi::~Csmapi()
{
if (m_bLogonOK)
Logoff();
if (m_hLib)
FreeLibrary(m_hLib);
}
STDMETHODIMP Csmapi::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_Ismapi
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
BOOL Csmapi::IsOEConfig()
{
CRegKey cOE;
LONG lRet;
BOOL bRet = FALSE;
TCHAR szBuf[MAX_PATH];
DWORD dwCount = MAX_PATH -1 ;
lRet = cOE.Open(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Account Manager"), KEY_READ);
if(lRet == ERROR_SUCCESS)
{
lRet = cOE.QueryValue(szBuf, TEXT("Default Mail Account"), &dwCount);
if (lRet == ERROR_SUCCESS)
{
TCHAR szActs[MAX_PATH];
CRegKey cOEAcct;
wsprintf(szActs, TEXT("Accounts\\%s"), szBuf);
lRet = cOEAcct.Open((HKEY)cOE, szActs, KEY_READ);
if (lRet == ERROR_SUCCESS)
{
bRet = TRUE;
cOEAcct.Close();
}
}
cOE.Close();
}
return bRet;
}
HRESULT Csmapi::get_Reload(LONG* pVal)
{
if (!pVal)
return E_POINTER;
HRESULT hr = S_OK;
CComBSTR bstrName, bstrOldName;
*pVal = 0; // assume failed for some reason;
if(m_bLogonOK)
{
Logoff();
}
if (m_hLib)
{
FreeLibrary(m_hLib);
m_lpfnMapiFreeBuf = NULL;
m_lpfnMapiAddress = NULL;
m_hLib = NULL;
}
if (m_szSmapiName[0] != _T('\0'))
bstrOldName = m_szSmapiName;
m_lOEFlag = 0;
hr = get_SMAPIClientName(&bstrName);
if (FAILED(hr) || bstrName.Length() == 0)
{
*pVal = 0; // failed for some reason
goto done;
}
if (bstrOldName.Length() > 0 && wcscmp(bstrOldName,bstrName) != 0)
{
*pVal = 1; // Email client get changed.
}
else
{
*pVal = -1; // succeed.
}
done:
return S_OK;
}
HRESULT Csmapi::get_SMAPIClientName(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
HRESULT hr = S_OK;
CRegKey cKey;
LONG lRet;
DWORD dwCount = sizeof(m_szSmapiName)/sizeof(m_szSmapiName[0]) -1;
// Get default email client
if (m_hLib) // Already initialized.
goto done;
#ifndef _WIN64 // WIN32. We use only OE on Win64.
lRet = cKey.Open(HKEY_LOCAL_MACHINE, TEXT("Software\\Clients\\Mail"), KEY_READ);
if (lRet != ERROR_SUCCESS)
goto done;
lRet = cKey.QueryValue(m_szSmapiName, NULL, &dwCount); // get default value
if (lRet == ERROR_SUCCESS)
{
// Is the email client Smapi compliant?
// 1. get it's dllpath
CRegKey cMail;
lRet = cMail.Open((HKEY)cKey, m_szSmapiName, KEY_READ);
if (lRet == ERROR_SUCCESS)
{
dwCount = sizeof(m_szDllPath)/sizeof(m_szDllPath[0]) - 1;
lRet = cMail.QueryValue(m_szDllPath, TEXT("DLLPath"), &dwCount);
if (lRet == ERROR_SUCCESS)
{
LONG len = lstrlen(m_szDllPath);
if ( !(len > LEN_MSOE_DLL && // no need to check OE
lstrcmpi(&m_szDllPath[len - LEN_MSOE_DLL], TEXT("\\msoe.dll")) == 0) &&
!(len > LEN_HMMAPI_DLL && // We don't want HMMAPI either
_tcsicmp(&m_szDllPath[len - LEN_HMMAPI_DLL], TEXT("\\hmmapi.dll")) == 0))
{
HMODULE hLib = LoadLibrary(m_szDllPath);
if (hLib != NULL)
{
if (GetProcAddress(hLib, "MAPILogon"))
{
m_hLib = hLib; // OK, this is the email program that we want.
}
}
}
cMail.Close();
}
}
cKey.Close();
}
#endif
if (m_hLib == NULL) // Need to use OE
{
m_szSmapiName[0] = TEXT('\0'); // in case OE is not available.
m_hLib = LoadOE();
}
done:
*pVal = (BSTR)CComBSTR(m_szSmapiName).Copy();
return hr;
}
HMODULE Csmapi::LoadOE()
{
LONG lRet;
HKEY hKey, hSubKey;
DWORD dwIndex = 0;
TCHAR szName[MAX_PATH];
TCHAR szBuf[MAX_PATH];
TCHAR szDll[MAX_PATH];
DWORD dwName, dwBuf;
FILETIME ft;
HMODULE hLib = NULL;
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\Clients\\Mail"),
0,
KEY_ENUMERATE_SUB_KEYS,
&hKey);
if (lRet == ERROR_SUCCESS)
{
dwName = sizeof(szName) / sizeof(szName[0]);
while(ERROR_SUCCESS == RegEnumKeyEx(hKey,
dwIndex++, // subkey index
&szName[0], // subkey name
&dwName, // size of subkey buffer
NULL,
NULL,
NULL,
&ft))
{
// get dll path.
lRet = RegOpenKeyEx(hKey, szName, 0, KEY_QUERY_VALUE, &hSubKey);
if (lRet == ERROR_SUCCESS)
{
dwBuf = sizeof(szBuf);
lRet = RegQueryValueEx(hSubKey, // handle to key
TEXT("DllPath"),
NULL,
NULL,
(BYTE*)&szBuf[0], // data buffer
&dwBuf);
if (lRet == ERROR_SUCCESS)
{
// is it msoe.dll?
lRet = lstrlen(szBuf);
if (lRet > LEN_MSOE_DLL &&
lstrcmpi(&szBuf[lRet - LEN_MSOE_DLL], TEXT("\\msoe.dll")) == 0)
{
// Resolve environment variable.
lRet = sizeof(m_szDllPath) / sizeof(m_szDllPath[0]);
dwBuf = ExpandEnvironmentStrings(szBuf, m_szDllPath, lRet);
if (dwBuf > (DWORD)lRet)
{
// TODO: Need to handle this case
}
else if (dwBuf == 0)
{
// TODO: Failed.
}
else if ((hLib = LoadLibrary(m_szDllPath)))
{
lstrcpy(m_szSmapiName, szName);
m_lOEFlag = F_ISOE | (IsOEConfig() ? F_ISCONFIG : 0);
}
break;
}
}
RegCloseKey(hSubKey);
}
dwName = sizeof(szName) / sizeof(szName[0]);
}
RegCloseKey(hKey);
}
return hLib;
}
HRESULT Csmapi::get_IsSMAPIClient_OE(LONG *pVal)
{
if (!pVal)
return E_POINTER;
HRESULT hr = S_OK;
CComBSTR bstrTest;
get_SMAPIClientName(&bstrTest);
*pVal = m_lOEFlag;
return hr;
}
/******************************************
Func:
Logon
Abstract:
Simple MAPI logon wrapper
Params:
None
*******************************************/
STDMETHODIMP Csmapi::Logon(ULONG *plReg)
{
if (!plReg)
return E_POINTER;
HRESULT hr = E_FAIL;
*plReg = 0;
USES_CONVERSION;
ULONG err = 0;
// Check Win.ini MAPI == 1 ?
if (m_bLogonOK)
{
hr = S_OK;
*plReg = 0;
goto done;
}
// Load MAPI32.DLL
if (!m_hLib)
{
LONG lError;
get_Reload(&lError);
if (lError == 0) // failed.
{
*plReg = 1;
goto done;
}
}
if (m_hLib != NULL)
{
LPMAPILOGON lpfnMapiLogon = (LPMAPILOGON)GetProcAddress(m_hLib, "MAPILogon");
if (lpfnMapiLogon == NULL)
goto done;
// 1st, is there any existing session that I can use?
err = lpfnMapiLogon(
0L,
NULL,
NULL,
0 ,
0,
&m_lhSession);
if (err != SUCCESS_SUCCESS)
{
// OK. I need a new session.
// Get default profile from registry
//
TCHAR szProfile[256];
DWORD dwCount = 255;
szProfile[0]= TEXT('\0');
::GetMAPIDefaultProfile((TCHAR*)szProfile, &dwCount);
err = lpfnMapiLogon(
0L,
T2A(szProfile),
NULL,
MAPI_LOGON_UI ,
0,
&m_lhSession);
if (err != SUCCESS_SUCCESS)
{
PopulateAndThrowErrorInfo(err);
goto done;
}
}
// err == SUCCESS_SUCCESS
m_bLogonOK = TRUE;
*plReg = 1;
hr = S_OK;
}
done:
return hr;
}
/******************************************
Func:
Logoff
Abstract:
Simple MAPI logoff wrapper
Params:
*******************************************/
STDMETHODIMP Csmapi::Logoff()
{
if (m_bLogonOK)
{
LPMAPILOGOFF lpfnMapiLogOff = (LPMAPILOGOFF)GetProcAddress(m_hLib, "MAPILogoff");
if (lpfnMapiLogOff)
lpfnMapiLogOff (m_lhSession, 0, 0, 0);
m_bLogonOK = FALSE;
}
return S_OK;
}
/******************************************
Func:
SendMail
Abstract:
Simple MAPI MAPISendMail wrapper. It always take the attachment file from m_bstrXMLFile member variable.
Params:
*plStatus: 1(Succeed)/others(Fail)
*******************************************/
STDMETHODIMP Csmapi::SendMail(LONG* plStatus)
{
if (!plStatus)
return E_POINTER;
HRESULT hr = E_FAIL;
ULONG err = 0;
ULONG cRecip = 0;
MapiRecipDesc *pMapiRecipDesc = NULL;
USES_CONVERSION;
*plStatus = 0;
if (!m_bLogonOK) // Logon problem !
return S_FALSE;
LPMAPISENDMAIL lpfnMapiSendMail = (LPMAPISENDMAIL)GetProcAddress(m_hLib, "MAPISendMail");
if (lpfnMapiSendMail == NULL)
return E_FAIL;
// Since we don't resolve name before, we need to resolve name here
// Even if the name list comes form AddressBook, some name list was not resolved
// in address book.
MapiFileDesc attachment = {0, // ulReserved, must be 0
0, // no flags; this is a data file
(ULONG)-1, // position not specified
W2A(m_bstrXMLFile), // pathname
NULL, //"RcBuddy.MsRcIncident", // original filename
NULL}; // MapiFileTagExt unused
// Create a blank message. Most members are set to NULL or 0 because
// MAPISendMail will let the user set them.
MapiMessage note = {0, // reserved, must be 0
W2A(m_bstrSubject),
W2A(m_bstrBody),
NULL, // NULL = interpersonal message
NULL, // no date; MAPISendMail ignores it
NULL, // no conversation ID
0, // no flags, MAPISendMail ignores it
NULL, // no originator, this is ignored too
cRecip, // # of recipients
NULL, //pMapiRecipDesc, // recipient array
1, // one attachment
&attachment}; // the attachment structure
//Next, the client calls the MAPISendMail function and
//stores the return status so it can detect whether the call succeeded.
err = lpfnMapiSendMail (m_lhSession, // use implicit session.
0L, // ulUIParam; 0 is always valid
&note, // the message being sent
MAPI_DIALOG, // Use MapiMessge recipients
0L); // reserved; must be 0
if (err == SUCCESS_SUCCESS )
{
*plStatus = 1;
hr = S_OK;
}
else
{
PopulateAndThrowErrorInfo(err);
}
// remove array allocated inside BuildMapiRecipDesc with 'new' command
if (pMapiRecipDesc)
delete pMapiRecipDesc;
return hr;
}
/******************************************
Func:
get_Subject
Abstract:
Return the Subject line information.
Params:
*pVal: returned string
*******************************************/
STDMETHODIMP Csmapi::get_Subject(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
//GET_BSTR(pVal, m_bstrSubject);
*pVal = m_bstrSubject.Copy();
return S_OK;
}
/******************************************
Func:
put_Subject
Abstract:
Set the Subject line information.
Params:
newVal: new string
*******************************************/
STDMETHODIMP Csmapi::put_Subject(BSTR newVal)
{
m_bstrSubject = newVal;
return S_OK;
}
/******************************************
Func:
get_Body
Abstract:
Get the Body message
Params:
*pVal: body message string
*******************************************/
STDMETHODIMP Csmapi::get_Body(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
//GET_BSTR(pVal, m_bstrBody);
*pVal = m_bstrBody.Copy();
return S_OK;
}
/******************************************
Func:
put_Body
Abstract:
Set the Body message
Params:
newVal: new body message string
*******************************************/
STDMETHODIMP Csmapi::put_Body(BSTR newVal)
{
m_bstrBody = newVal;
return S_OK;
}
/******************************************
Func:
get_AttachedXMLFile
Abstract:
get Attachment file info.
Params:
*pVal: attachment file pathname.
*******************************************/
STDMETHODIMP Csmapi::get_AttachedXMLFile(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
//GET_BSTR(pVal, m_bstrXMLFile);
*pVal = m_bstrXMLFile.Copy();
return S_OK;
}
/******************************************
Func:
put_AttachedXMLFile
Abstract:
set Attachment file info.
Params:
newVal: attachment file pathname.
*******************************************/
STDMETHODIMP Csmapi::put_AttachedXMLFile(BSTR newVal)
{
m_bstrXMLFile = newVal;
return S_OK;
}
/* ----------------------------------------------------------- */
/* Internal Helper functions */
/* ----------------------------------------------------------- */
/******************************************
Func:
MAPIFreeBuffer
Abstract:
MAPIFreeBuffer wrapper.
Params:
*p: buffer pointer will be deleted.
*******************************************/
void Csmapi::MAPIFreeBuffer( MapiRecipDesc* p )
{
if (m_lpfnMapiFreeBuf == NULL && m_hLib)
{
m_lpfnMapiFreeBuf = (LPMAPIFREEBUFFER)GetProcAddress(m_hLib, "MAPIFreeBuffer");
}
if (!m_lpfnMapiFreeBuf)
return;
m_lpfnMapiFreeBuf(p);
}
/******************************************
Func:
GetMAPIDefaultProfile
Abstract:
get default profile string from Registry
Params:
*pProfile: profile string buffer.
*pdwCount: # of char of profile string
*******************************************/
BOOL GetMAPIDefaultProfile(TCHAR* pProfile, DWORD* pdwCount)
{
CRegKey cKey;
LONG lRet;
BOOL bRet = FALSE;
lRet = cKey.Open(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles"), KEY_READ);
if (lRet == ERROR_SUCCESS)
{
lRet = cKey.QueryValue(pProfile, TEXT("DefaultProfile"), pdwCount);
if (lRet == ERROR_SUCCESS)
{
bRet = TRUE;
}
cKey.Close();
}
return bRet;
}
void Csmapi::PopulateAndThrowErrorInfo(ULONG err)
{
UINT uID = 0;
switch (err)
{
case E_FUNC_NOTFOUND:
uID = IDS_E_FUNC_NOTFOUND;
break;
case MAPI_E_FAILURE :
uID = IDS_MAPI_E_FAILURE;
break;
case MAPI_E_INSUFFICIENT_MEMORY :
uID = IDS_MAPI_E_INSUFFICIENT_MEMORY;
break;
case MAPI_E_LOGIN_FAILURE :
uID = IDS_MAPI_E_LOGIN_FAILURE;
break;
case MAPI_E_TOO_MANY_SESSIONS :
uID = IDS_MAPI_E_TOO_MANY_SESSIONS;
break;
case MAPI_E_USER_ABORT :
uID = IDS_MAPI_E_USER_ABORT;
break;
case MAPI_E_INVALID_SESSION :
uID = IDS_MAPI_E_INVALID_SESSION;
break;
case MAPI_E_INVALID_EDITFIELDS :
uID = IDS_MAPI_E_INVALID_EDITFIELDS;
break;
case MAPI_E_INVALID_RECIPS :
uID = IDS_MAPI_E_INVALID_RECIPS;
break;
case MAPI_E_NOT_SUPPORTED :
uID = IDS_MAPI_E_NOT_SUPPORTED;
break;
case MAPI_E_AMBIGUOUS_RECIPIENT :
uID = IDS_MAPI_E_AMBIGUOUS_RECIPIENT;
break;
case MAPI_E_ATTACHMENT_NOT_FOUND :
uID = IDS_MAPI_E_ATTACHMENT_NOT_FOUND;
break;
case MAPI_E_ATTACHMENT_OPEN_FAILURE :
uID = IDS_MAPI_E_ATTACHMENT_OPEN_FAILURE;
break;
case MAPI_E_BAD_RECIPTYPE :
uID = IDS_MAPI_E_BAD_RECIPTYPE;
break;
case MAPI_E_TEXT_TOO_LARGE :
uID = IDS_MAPI_E_TEXT_TOO_LARGE;
break;
case MAPI_E_TOO_MANY_FILES :
uID = IDS_MAPI_E_TOO_MANY_FILES;
break;
case MAPI_E_TOO_MANY_RECIPIENTS :
uID = IDS_MAPI_E_TOO_MANY_RECIPIENTS;
break;
case MAPI_E_UNKNOWN_RECIPIENT :
uID = IDS_MAPI_E_UNKNOWN_RECIPIENT;
break;
default:
uID = IDS_MAPI_E_FAILURE;
}
//Currently the hresult in the Error info structure is set to E_FAIL
Error(uID,IID_Ismapi,E_FAIL,_Module.GetResourceInstance());
}