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

  1. /*
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. smapi.cpp
  5. Abstract:
  6. CSMapi object. Used to support our simple MAPI functions.
  7. Revision History:
  8. created steveshi 08/23/00
  9. */
  10. #include "stdafx.h"
  11. #include "Rcbdyctl.h"
  12. #include "smapi.h"
  13. #include "mapix.h"
  14. #include "utils.h"
  15. #define C_OEAPP TEXT("Outlook Express")
  16. #define F_ISOE 0x1
  17. #define F_ISCONFIG 0x2
  18. #define LEN_MSOE_DLL 9 // length of "\\msoe.dll"
  19. #define LEN_HMMAPI_DLL 11 // length of "\\hmmapi.dll"
  20. BOOL GetMAPIDefaultProfile(TCHAR*, DWORD*);
  21. #define E_FUNC_NOTFOUND 1000 //Userdefined error no.
  22. // Csmapi
  23. Csmapi::~Csmapi()
  24. {
  25. if (m_bLogonOK)
  26. Logoff();
  27. if (m_hLib)
  28. FreeLibrary(m_hLib);
  29. }
  30. STDMETHODIMP Csmapi::InterfaceSupportsErrorInfo(REFIID riid)
  31. {
  32. static const IID* arr[] =
  33. {
  34. &IID_Ismapi
  35. };
  36. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  37. {
  38. if (InlineIsEqualGUID(*arr[i],riid))
  39. return S_OK;
  40. }
  41. return S_FALSE;
  42. }
  43. BOOL Csmapi::IsOEConfig()
  44. {
  45. CRegKey cOE;
  46. LONG lRet;
  47. BOOL bRet = FALSE;
  48. TCHAR szBuf[MAX_PATH];
  49. DWORD dwCount = MAX_PATH -1 ;
  50. lRet = cOE.Open(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Account Manager"), KEY_READ);
  51. if(lRet == ERROR_SUCCESS)
  52. {
  53. lRet = cOE.QueryValue(szBuf, TEXT("Default Mail Account"), &dwCount);
  54. if (lRet == ERROR_SUCCESS)
  55. {
  56. TCHAR szActs[MAX_PATH];
  57. CRegKey cOEAcct;
  58. wsprintf(szActs, TEXT("Accounts\\%s"), szBuf);
  59. lRet = cOEAcct.Open((HKEY)cOE, szActs, KEY_READ);
  60. if (lRet == ERROR_SUCCESS)
  61. {
  62. bRet = TRUE;
  63. cOEAcct.Close();
  64. }
  65. }
  66. cOE.Close();
  67. }
  68. return bRet;
  69. }
  70. HRESULT Csmapi::get_Reload(LONG* pVal)
  71. {
  72. if (!pVal)
  73. return E_POINTER;
  74. HRESULT hr = S_OK;
  75. CComBSTR bstrName, bstrOldName;
  76. *pVal = 0; // assume failed for some reason;
  77. if(m_bLogonOK)
  78. {
  79. Logoff();
  80. }
  81. if (m_hLib)
  82. {
  83. FreeLibrary(m_hLib);
  84. m_lpfnMapiFreeBuf = NULL;
  85. m_lpfnMapiAddress = NULL;
  86. m_hLib = NULL;
  87. }
  88. if (m_szSmapiName[0] != _T('\0'))
  89. bstrOldName = m_szSmapiName;
  90. m_lOEFlag = 0;
  91. hr = get_SMAPIClientName(&bstrName);
  92. if (FAILED(hr) || bstrName.Length() == 0)
  93. {
  94. *pVal = 0; // failed for some reason
  95. goto done;
  96. }
  97. if (bstrOldName.Length() > 0 && wcscmp(bstrOldName,bstrName) != 0)
  98. {
  99. *pVal = 1; // Email client get changed.
  100. }
  101. else
  102. {
  103. *pVal = -1; // succeed.
  104. }
  105. done:
  106. return S_OK;
  107. }
  108. HRESULT Csmapi::get_SMAPIClientName(BSTR *pVal)
  109. {
  110. if (!pVal)
  111. return E_POINTER;
  112. HRESULT hr = S_OK;
  113. CRegKey cKey;
  114. LONG lRet;
  115. DWORD dwCount = sizeof(m_szSmapiName)/sizeof(m_szSmapiName[0]) -1;
  116. // Get default email client
  117. if (m_hLib) // Already initialized.
  118. goto done;
  119. #ifndef _WIN64 // WIN32. We use only OE on Win64.
  120. lRet = cKey.Open(HKEY_LOCAL_MACHINE, TEXT("Software\\Clients\\Mail"), KEY_READ);
  121. if (lRet != ERROR_SUCCESS)
  122. goto done;
  123. lRet = cKey.QueryValue(m_szSmapiName, NULL, &dwCount); // get default value
  124. if (lRet == ERROR_SUCCESS)
  125. {
  126. // Is the email client Smapi compliant?
  127. // 1. get it's dllpath
  128. CRegKey cMail;
  129. lRet = cMail.Open((HKEY)cKey, m_szSmapiName, KEY_READ);
  130. if (lRet == ERROR_SUCCESS)
  131. {
  132. dwCount = sizeof(m_szDllPath)/sizeof(m_szDllPath[0]) - 1;
  133. lRet = cMail.QueryValue(m_szDllPath, TEXT("DLLPath"), &dwCount);
  134. if (lRet == ERROR_SUCCESS)
  135. {
  136. LONG len = lstrlen(m_szDllPath);
  137. if ( !(len > LEN_MSOE_DLL && // no need to check OE
  138. lstrcmpi(&m_szDllPath[len - LEN_MSOE_DLL], TEXT("\\msoe.dll")) == 0) &&
  139. !(len > LEN_HMMAPI_DLL && // We don't want HMMAPI either
  140. _tcsicmp(&m_szDllPath[len - LEN_HMMAPI_DLL], TEXT("\\hmmapi.dll")) == 0))
  141. {
  142. HMODULE hLib = LoadLibrary(m_szDllPath);
  143. if (hLib != NULL)
  144. {
  145. if (GetProcAddress(hLib, "MAPILogon"))
  146. {
  147. m_hLib = hLib; // OK, this is the email program that we want.
  148. }
  149. }
  150. }
  151. cMail.Close();
  152. }
  153. }
  154. cKey.Close();
  155. }
  156. #endif
  157. if (m_hLib == NULL) // Need to use OE
  158. {
  159. m_szSmapiName[0] = TEXT('\0'); // in case OE is not available.
  160. m_hLib = LoadOE();
  161. }
  162. done:
  163. *pVal = (BSTR)CComBSTR(m_szSmapiName).Copy();
  164. return hr;
  165. }
  166. HMODULE Csmapi::LoadOE()
  167. {
  168. LONG lRet;
  169. HKEY hKey, hSubKey;
  170. DWORD dwIndex = 0;
  171. TCHAR szName[MAX_PATH];
  172. TCHAR szBuf[MAX_PATH];
  173. TCHAR szDll[MAX_PATH];
  174. DWORD dwName, dwBuf;
  175. FILETIME ft;
  176. HMODULE hLib = NULL;
  177. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  178. TEXT("Software\\Clients\\Mail"),
  179. 0,
  180. KEY_ENUMERATE_SUB_KEYS,
  181. &hKey);
  182. if (lRet == ERROR_SUCCESS)
  183. {
  184. dwName = sizeof(szName) / sizeof(szName[0]);
  185. while(ERROR_SUCCESS == RegEnumKeyEx(hKey,
  186. dwIndex++, // subkey index
  187. &szName[0], // subkey name
  188. &dwName, // size of subkey buffer
  189. NULL,
  190. NULL,
  191. NULL,
  192. &ft))
  193. {
  194. // get dll path.
  195. lRet = RegOpenKeyEx(hKey, szName, 0, KEY_QUERY_VALUE, &hSubKey);
  196. if (lRet == ERROR_SUCCESS)
  197. {
  198. dwBuf = sizeof(szBuf);
  199. lRet = RegQueryValueEx(hSubKey, // handle to key
  200. TEXT("DllPath"),
  201. NULL,
  202. NULL,
  203. (BYTE*)&szBuf[0], // data buffer
  204. &dwBuf);
  205. if (lRet == ERROR_SUCCESS)
  206. {
  207. // is it msoe.dll?
  208. lRet = lstrlen(szBuf);
  209. if (lRet > LEN_MSOE_DLL &&
  210. lstrcmpi(&szBuf[lRet - LEN_MSOE_DLL], TEXT("\\msoe.dll")) == 0)
  211. {
  212. // Resolve environment variable.
  213. lRet = sizeof(m_szDllPath) / sizeof(m_szDllPath[0]);
  214. dwBuf = ExpandEnvironmentStrings(szBuf, m_szDllPath, lRet);
  215. if (dwBuf > (DWORD)lRet)
  216. {
  217. // TODO: Need to handle this case
  218. }
  219. else if (dwBuf == 0)
  220. {
  221. // TODO: Failed.
  222. }
  223. else if ((hLib = LoadLibrary(m_szDllPath)))
  224. {
  225. lstrcpy(m_szSmapiName, szName);
  226. m_lOEFlag = F_ISOE | (IsOEConfig() ? F_ISCONFIG : 0);
  227. }
  228. break;
  229. }
  230. }
  231. RegCloseKey(hSubKey);
  232. }
  233. dwName = sizeof(szName) / sizeof(szName[0]);
  234. }
  235. RegCloseKey(hKey);
  236. }
  237. return hLib;
  238. }
  239. HRESULT Csmapi::get_IsSMAPIClient_OE(LONG *pVal)
  240. {
  241. if (!pVal)
  242. return E_POINTER;
  243. HRESULT hr = S_OK;
  244. CComBSTR bstrTest;
  245. get_SMAPIClientName(&bstrTest);
  246. *pVal = m_lOEFlag;
  247. return hr;
  248. }
  249. /******************************************
  250. Func:
  251. Logon
  252. Abstract:
  253. Simple MAPI logon wrapper
  254. Params:
  255. None
  256. *******************************************/
  257. STDMETHODIMP Csmapi::Logon(ULONG *plReg)
  258. {
  259. if (!plReg)
  260. return E_POINTER;
  261. HRESULT hr = E_FAIL;
  262. *plReg = 0;
  263. USES_CONVERSION;
  264. ULONG err = 0;
  265. // Check Win.ini MAPI == 1 ?
  266. if (m_bLogonOK)
  267. {
  268. hr = S_OK;
  269. *plReg = 0;
  270. goto done;
  271. }
  272. // Load MAPI32.DLL
  273. if (!m_hLib)
  274. {
  275. LONG lError;
  276. get_Reload(&lError);
  277. if (lError == 0) // failed.
  278. {
  279. *plReg = 1;
  280. goto done;
  281. }
  282. }
  283. if (m_hLib != NULL)
  284. {
  285. LPMAPILOGON lpfnMapiLogon = (LPMAPILOGON)GetProcAddress(m_hLib, "MAPILogon");
  286. if (lpfnMapiLogon == NULL)
  287. goto done;
  288. // 1st, is there any existing session that I can use?
  289. err = lpfnMapiLogon(
  290. 0L,
  291. NULL,
  292. NULL,
  293. 0 ,
  294. 0,
  295. &m_lhSession);
  296. if (err != SUCCESS_SUCCESS)
  297. {
  298. // OK. I need a new session.
  299. // Get default profile from registry
  300. //
  301. TCHAR szProfile[256];
  302. DWORD dwCount = 255;
  303. szProfile[0]= TEXT('\0');
  304. ::GetMAPIDefaultProfile((TCHAR*)szProfile, &dwCount);
  305. err = lpfnMapiLogon(
  306. 0L,
  307. T2A(szProfile),
  308. NULL,
  309. MAPI_LOGON_UI ,
  310. 0,
  311. &m_lhSession);
  312. if (err != SUCCESS_SUCCESS)
  313. {
  314. PopulateAndThrowErrorInfo(err);
  315. goto done;
  316. }
  317. }
  318. // err == SUCCESS_SUCCESS
  319. m_bLogonOK = TRUE;
  320. *plReg = 1;
  321. hr = S_OK;
  322. }
  323. done:
  324. return hr;
  325. }
  326. /******************************************
  327. Func:
  328. Logoff
  329. Abstract:
  330. Simple MAPI logoff wrapper
  331. Params:
  332. *******************************************/
  333. STDMETHODIMP Csmapi::Logoff()
  334. {
  335. if (m_bLogonOK)
  336. {
  337. LPMAPILOGOFF lpfnMapiLogOff = (LPMAPILOGOFF)GetProcAddress(m_hLib, "MAPILogoff");
  338. if (lpfnMapiLogOff)
  339. lpfnMapiLogOff (m_lhSession, 0, 0, 0);
  340. m_bLogonOK = FALSE;
  341. }
  342. return S_OK;
  343. }
  344. /******************************************
  345. Func:
  346. SendMail
  347. Abstract:
  348. Simple MAPI MAPISendMail wrapper. It always take the attachment file from m_bstrXMLFile member variable.
  349. Params:
  350. *plStatus: 1(Succeed)/others(Fail)
  351. *******************************************/
  352. STDMETHODIMP Csmapi::SendMail(LONG* plStatus)
  353. {
  354. if (!plStatus)
  355. return E_POINTER;
  356. HRESULT hr = E_FAIL;
  357. ULONG err = 0;
  358. ULONG cRecip = 0;
  359. MapiRecipDesc *pMapiRecipDesc = NULL;
  360. USES_CONVERSION;
  361. *plStatus = 0;
  362. if (!m_bLogonOK) // Logon problem !
  363. return S_FALSE;
  364. LPMAPISENDMAIL lpfnMapiSendMail = (LPMAPISENDMAIL)GetProcAddress(m_hLib, "MAPISendMail");
  365. if (lpfnMapiSendMail == NULL)
  366. return E_FAIL;
  367. // Since we don't resolve name before, we need to resolve name here
  368. // Even if the name list comes form AddressBook, some name list was not resolved
  369. // in address book.
  370. MapiFileDesc attachment = {0, // ulReserved, must be 0
  371. 0, // no flags; this is a data file
  372. (ULONG)-1, // position not specified
  373. W2A(m_bstrXMLFile), // pathname
  374. NULL, //"RcBuddy.MsRcIncident", // original filename
  375. NULL}; // MapiFileTagExt unused
  376. // Create a blank message. Most members are set to NULL or 0 because
  377. // MAPISendMail will let the user set them.
  378. MapiMessage note = {0, // reserved, must be 0
  379. W2A(m_bstrSubject),
  380. W2A(m_bstrBody),
  381. NULL, // NULL = interpersonal message
  382. NULL, // no date; MAPISendMail ignores it
  383. NULL, // no conversation ID
  384. 0, // no flags, MAPISendMail ignores it
  385. NULL, // no originator, this is ignored too
  386. cRecip, // # of recipients
  387. NULL, //pMapiRecipDesc, // recipient array
  388. 1, // one attachment
  389. &attachment}; // the attachment structure
  390. //Next, the client calls the MAPISendMail function and
  391. //stores the return status so it can detect whether the call succeeded.
  392. err = lpfnMapiSendMail (m_lhSession, // use implicit session.
  393. 0L, // ulUIParam; 0 is always valid
  394. &note, // the message being sent
  395. MAPI_DIALOG, // Use MapiMessge recipients
  396. 0L); // reserved; must be 0
  397. if (err == SUCCESS_SUCCESS )
  398. {
  399. *plStatus = 1;
  400. hr = S_OK;
  401. }
  402. else
  403. {
  404. PopulateAndThrowErrorInfo(err);
  405. }
  406. // remove array allocated inside BuildMapiRecipDesc with 'new' command
  407. if (pMapiRecipDesc)
  408. delete pMapiRecipDesc;
  409. return hr;
  410. }
  411. /******************************************
  412. Func:
  413. get_Subject
  414. Abstract:
  415. Return the Subject line information.
  416. Params:
  417. *pVal: returned string
  418. *******************************************/
  419. STDMETHODIMP Csmapi::get_Subject(BSTR *pVal)
  420. {
  421. if (!pVal)
  422. return E_POINTER;
  423. //GET_BSTR(pVal, m_bstrSubject);
  424. *pVal = m_bstrSubject.Copy();
  425. return S_OK;
  426. }
  427. /******************************************
  428. Func:
  429. put_Subject
  430. Abstract:
  431. Set the Subject line information.
  432. Params:
  433. newVal: new string
  434. *******************************************/
  435. STDMETHODIMP Csmapi::put_Subject(BSTR newVal)
  436. {
  437. m_bstrSubject = newVal;
  438. return S_OK;
  439. }
  440. /******************************************
  441. Func:
  442. get_Body
  443. Abstract:
  444. Get the Body message
  445. Params:
  446. *pVal: body message string
  447. *******************************************/
  448. STDMETHODIMP Csmapi::get_Body(BSTR *pVal)
  449. {
  450. if (!pVal)
  451. return E_POINTER;
  452. //GET_BSTR(pVal, m_bstrBody);
  453. *pVal = m_bstrBody.Copy();
  454. return S_OK;
  455. }
  456. /******************************************
  457. Func:
  458. put_Body
  459. Abstract:
  460. Set the Body message
  461. Params:
  462. newVal: new body message string
  463. *******************************************/
  464. STDMETHODIMP Csmapi::put_Body(BSTR newVal)
  465. {
  466. m_bstrBody = newVal;
  467. return S_OK;
  468. }
  469. /******************************************
  470. Func:
  471. get_AttachedXMLFile
  472. Abstract:
  473. get Attachment file info.
  474. Params:
  475. *pVal: attachment file pathname.
  476. *******************************************/
  477. STDMETHODIMP Csmapi::get_AttachedXMLFile(BSTR *pVal)
  478. {
  479. if (!pVal)
  480. return E_POINTER;
  481. //GET_BSTR(pVal, m_bstrXMLFile);
  482. *pVal = m_bstrXMLFile.Copy();
  483. return S_OK;
  484. }
  485. /******************************************
  486. Func:
  487. put_AttachedXMLFile
  488. Abstract:
  489. set Attachment file info.
  490. Params:
  491. newVal: attachment file pathname.
  492. *******************************************/
  493. STDMETHODIMP Csmapi::put_AttachedXMLFile(BSTR newVal)
  494. {
  495. m_bstrXMLFile = newVal;
  496. return S_OK;
  497. }
  498. /* ----------------------------------------------------------- */
  499. /* Internal Helper functions */
  500. /* ----------------------------------------------------------- */
  501. /******************************************
  502. Func:
  503. MAPIFreeBuffer
  504. Abstract:
  505. MAPIFreeBuffer wrapper.
  506. Params:
  507. *p: buffer pointer will be deleted.
  508. *******************************************/
  509. void Csmapi::MAPIFreeBuffer( MapiRecipDesc* p )
  510. {
  511. if (m_lpfnMapiFreeBuf == NULL && m_hLib)
  512. {
  513. m_lpfnMapiFreeBuf = (LPMAPIFREEBUFFER)GetProcAddress(m_hLib, "MAPIFreeBuffer");
  514. }
  515. if (!m_lpfnMapiFreeBuf)
  516. return;
  517. m_lpfnMapiFreeBuf(p);
  518. }
  519. /******************************************
  520. Func:
  521. GetMAPIDefaultProfile
  522. Abstract:
  523. get default profile string from Registry
  524. Params:
  525. *pProfile: profile string buffer.
  526. *pdwCount: # of char of profile string
  527. *******************************************/
  528. BOOL GetMAPIDefaultProfile(TCHAR* pProfile, DWORD* pdwCount)
  529. {
  530. CRegKey cKey;
  531. LONG lRet;
  532. BOOL bRet = FALSE;
  533. lRet = cKey.Open(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles"), KEY_READ);
  534. if (lRet == ERROR_SUCCESS)
  535. {
  536. lRet = cKey.QueryValue(pProfile, TEXT("DefaultProfile"), pdwCount);
  537. if (lRet == ERROR_SUCCESS)
  538. {
  539. bRet = TRUE;
  540. }
  541. cKey.Close();
  542. }
  543. return bRet;
  544. }
  545. void Csmapi::PopulateAndThrowErrorInfo(ULONG err)
  546. {
  547. UINT uID = 0;
  548. switch (err)
  549. {
  550. case E_FUNC_NOTFOUND:
  551. uID = IDS_E_FUNC_NOTFOUND;
  552. break;
  553. case MAPI_E_FAILURE :
  554. uID = IDS_MAPI_E_FAILURE;
  555. break;
  556. case MAPI_E_INSUFFICIENT_MEMORY :
  557. uID = IDS_MAPI_E_INSUFFICIENT_MEMORY;
  558. break;
  559. case MAPI_E_LOGIN_FAILURE :
  560. uID = IDS_MAPI_E_LOGIN_FAILURE;
  561. break;
  562. case MAPI_E_TOO_MANY_SESSIONS :
  563. uID = IDS_MAPI_E_TOO_MANY_SESSIONS;
  564. break;
  565. case MAPI_E_USER_ABORT :
  566. uID = IDS_MAPI_E_USER_ABORT;
  567. break;
  568. case MAPI_E_INVALID_SESSION :
  569. uID = IDS_MAPI_E_INVALID_SESSION;
  570. break;
  571. case MAPI_E_INVALID_EDITFIELDS :
  572. uID = IDS_MAPI_E_INVALID_EDITFIELDS;
  573. break;
  574. case MAPI_E_INVALID_RECIPS :
  575. uID = IDS_MAPI_E_INVALID_RECIPS;
  576. break;
  577. case MAPI_E_NOT_SUPPORTED :
  578. uID = IDS_MAPI_E_NOT_SUPPORTED;
  579. break;
  580. case MAPI_E_AMBIGUOUS_RECIPIENT :
  581. uID = IDS_MAPI_E_AMBIGUOUS_RECIPIENT;
  582. break;
  583. case MAPI_E_ATTACHMENT_NOT_FOUND :
  584. uID = IDS_MAPI_E_ATTACHMENT_NOT_FOUND;
  585. break;
  586. case MAPI_E_ATTACHMENT_OPEN_FAILURE :
  587. uID = IDS_MAPI_E_ATTACHMENT_OPEN_FAILURE;
  588. break;
  589. case MAPI_E_BAD_RECIPTYPE :
  590. uID = IDS_MAPI_E_BAD_RECIPTYPE;
  591. break;
  592. case MAPI_E_TEXT_TOO_LARGE :
  593. uID = IDS_MAPI_E_TEXT_TOO_LARGE;
  594. break;
  595. case MAPI_E_TOO_MANY_FILES :
  596. uID = IDS_MAPI_E_TOO_MANY_FILES;
  597. break;
  598. case MAPI_E_TOO_MANY_RECIPIENTS :
  599. uID = IDS_MAPI_E_TOO_MANY_RECIPIENTS;
  600. break;
  601. case MAPI_E_UNKNOWN_RECIPIENT :
  602. uID = IDS_MAPI_E_UNKNOWN_RECIPIENT;
  603. break;
  604. default:
  605. uID = IDS_MAPI_E_FAILURE;
  606. }
  607. //Currently the hresult in the Error info structure is set to E_FAIL
  608. Error(uID,IID_Ismapi,E_FAIL,_Module.GetResourceInstance());
  609. }