Source code of Windows XP (NT5)
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.

2171 lines
48 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. mapi.c
  5. Abstract:
  6. This file implements wrappers for all mapi apis.
  7. The wrappers are necessary because mapi does not
  8. implement unicode and this code must be non-unicode.
  9. Author:
  10. Wesley Witt (wesw) 13-Sept-1996
  11. Revision History:
  12. --*/
  13. #undef UNICODE
  14. #undef _UNICODE
  15. #include <windows.h>
  16. #include <mapiwin.h>
  17. #include <mapix.h>
  18. #include <mapiutil.h>
  19. #include <stdio.h>
  20. #include "profinfo.h"
  21. #include "faxutil.h"
  22. typedef ULONG (STDAPIVCALLTYPE*ULRELEASE)(LPVOID);
  23. typedef VOID (STDAPIVCALLTYPE*FREEPADRLIST)(LPADRLIST);
  24. typedef ULONG (STDAPIVCALLTYPE*HRQUERYALLROWS)(LPMAPITABLE,LPSPropTagArray,LPSRestriction,LPSSortOrderSet,LONG,LPSRowSet*);
  25. typedef SCODE (STDAPIVCALLTYPE*SCDUPPROPSET)(int, LPSPropValue,LPALLOCATEBUFFER, LPSPropValue*);
  26. static LPMAPIINITIALIZE MapiInitialize;
  27. static LPMAPIUNINITIALIZE MapiUnInitialize;
  28. static LPMAPILOGONEX MapiLogonEx;
  29. static LPMAPIFREEBUFFER MapiFreeBuffer;
  30. static LPMAPIALLOCATEBUFFER MapiAllocateBuffer;
  31. static LPMAPIADMINPROFILES MapiAdminProfiles;
  32. static ULRELEASE pUlRelease;
  33. static FREEPADRLIST pFreePadrlist;
  34. static HRQUERYALLROWS pHrQueryAllRows;
  35. static SCDUPPROPSET pScDupPropset;
  36. static MAPIINIT_0 MapiInit;
  37. BOOL MapiIsInitialized = FALSE;
  38. extern ServiceDebug;
  39. PROC
  40. WINAPI
  41. MyGetProcAddress(
  42. HMODULE hModule,
  43. LPCSTR lpProcName
  44. );
  45. extern "C"
  46. LPSTR
  47. UnicodeStringToAnsiString(
  48. LPCWSTR UnicodeString
  49. );
  50. extern "C"
  51. VOID
  52. FreeString(
  53. LPVOID String
  54. );
  55. BOOL
  56. InitializeMapi(
  57. VOID
  58. )
  59. /*++
  60. Routine Description:
  61. Initializes MAPI.
  62. Arguments:
  63. NONE
  64. Return Value:
  65. TRUE if successful, FALSE if not
  66. --*/
  67. {
  68. HMODULE MapiMod = NULL;
  69. HRESULT Result;
  70. //
  71. // load the mapi dll
  72. //
  73. MapiMod = LoadLibrary( "mapi32.dll" );
  74. if (!MapiMod) {
  75. return FALSE;
  76. }
  77. //
  78. // get the addresses of the mapi functions that we need
  79. //
  80. MapiInitialize = (LPMAPIINITIALIZE) MyGetProcAddress( MapiMod, "MAPIInitialize" );
  81. MapiUnInitialize = (LPMAPIUNINITIALIZE) MyGetProcAddress( MapiMod, "MAPIUninitialize" );
  82. MapiLogonEx = (LPMAPILOGONEX) MyGetProcAddress( MapiMod, "MAPILogonEx" );
  83. MapiFreeBuffer = (LPMAPIFREEBUFFER) MyGetProcAddress( MapiMod, "MAPIFreeBuffer" );
  84. MapiAllocateBuffer = (LPMAPIALLOCATEBUFFER) MyGetProcAddress( MapiMod, "MAPIAllocateBuffer" );
  85. MapiAdminProfiles = (LPMAPIADMINPROFILES) MyGetProcAddress( MapiMod, "MAPIAdminProfiles" );
  86. pUlRelease = (ULRELEASE) MyGetProcAddress( MapiMod, "UlRelease@4" );
  87. pFreePadrlist = (FREEPADRLIST) MyGetProcAddress( MapiMod, "FreePadrlist@4" );
  88. pHrQueryAllRows = (HRQUERYALLROWS) MyGetProcAddress( MapiMod, "HrQueryAllRows@24" );
  89. pScDupPropset = (SCDUPPROPSET) MyGetProcAddress( MapiMod, "ScDupPropset@16" );
  90. if ((!MapiInitialize) || (!MapiUnInitialize) ||
  91. (!MapiLogonEx) || (!MapiAllocateBuffer) ||
  92. (!MapiFreeBuffer) || (!MapiAdminProfiles) ||
  93. (!pUlRelease) || (!pFreePadrlist) ||
  94. (!pHrQueryAllRows) || (!pScDupPropset)) {
  95. return FALSE;
  96. }
  97. MapiInit.ulFlags = MAPI_MULTITHREAD_NOTIFICATIONS;
  98. if (!ServiceDebug) {
  99. MapiInit.ulFlags |= MAPI_NT_SERVICE;
  100. }
  101. Result = MapiInitialize(&MapiInit);
  102. if (Result != S_OK) {
  103. return FALSE;
  104. }
  105. return MapiIsInitialized = TRUE;
  106. }
  107. VOID
  108. FreeProws(
  109. LPSRowSet prows
  110. )
  111. /*++
  112. Routine Description:
  113. Destroy SRowSet structure. Copied from MAPI.
  114. Arguments:
  115. hFile - Pointer to SRowSet
  116. Return value:
  117. NONE
  118. --*/
  119. {
  120. ULONG irow;
  121. if (!prows) {
  122. return;
  123. }
  124. for (irow = 0; irow < prows->cRows; ++irow) {
  125. MapiFreeBuffer(prows->aRow[irow].lpProps);
  126. }
  127. MapiFreeBuffer( prows );
  128. }
  129. HRESULT
  130. HrMAPIFindInbox(
  131. IN LPMDB lpMdb,
  132. OUT ULONG *lpcbeid,
  133. OUT LPENTRYID *lppeid
  134. )
  135. /*++
  136. Routine Description:
  137. Find IPM inbox folder. Copied from Exchange SDK.
  138. Arguments:
  139. lpMdb - pointer to message store
  140. lpcbeid - count of bytes in entry ID
  141. lppeid - entry ID of IPM inbox
  142. Return value:
  143. HRESULT (see MAPI docs)
  144. --*/
  145. {
  146. HRESULT hr = NOERROR;
  147. SCODE sc = 0;
  148. *lpcbeid = 0;
  149. *lppeid = NULL;
  150. //
  151. // Get the entry ID of the Inbox from the message store
  152. //
  153. hr = lpMdb->GetReceiveFolder(
  154. NULL,
  155. 0,
  156. lpcbeid,
  157. lppeid,
  158. NULL
  159. );
  160. return hr;
  161. }
  162. HRESULT
  163. HrMAPIFindOutbox(
  164. IN LPMDB lpMdb,
  165. OUT ULONG *lpcbeid,
  166. OUT LPENTRYID *lppeid
  167. )
  168. /*++
  169. Routine Description:
  170. Find IPM outbox folder. Copied from Exchange SDK.
  171. Arguments:
  172. lpMdb - pointer to message store
  173. lpcbeid - count of bytes in entry ID
  174. lppeid - entry ID of IPM inbox
  175. Return value:
  176. HRESULT (see MAPI docs)
  177. --*/
  178. {
  179. HRESULT hr = NOERROR;
  180. SCODE sc = 0;
  181. ULONG cValues = 0;
  182. LPSPropValue lpPropValue = NULL;
  183. ULONG cbeid = 0;
  184. SPropTagArray rgPropTag = { 1, { PR_IPM_OUTBOX_ENTRYID } };
  185. *lpcbeid = 0;
  186. *lppeid = NULL;
  187. //
  188. // Get the outbox entry ID property.
  189. //
  190. hr = lpMdb->GetProps(
  191. &rgPropTag,
  192. 0,
  193. &cValues,
  194. &lpPropValue
  195. );
  196. if (hr == MAPI_W_ERRORS_RETURNED) {
  197. goto cleanup;
  198. }
  199. if (FAILED(hr)) {
  200. lpPropValue = NULL;
  201. goto cleanup;
  202. }
  203. //
  204. // Check to make sure we got the right property.
  205. //
  206. if (lpPropValue->ulPropTag != PR_IPM_OUTBOX_ENTRYID) {
  207. goto cleanup;
  208. }
  209. cbeid = lpPropValue->Value.bin.cb;
  210. sc = MapiAllocateBuffer( cbeid, (void **)lppeid );
  211. if(FAILED(sc)) {
  212. goto cleanup;
  213. }
  214. //
  215. // Copy outbox Entry ID
  216. //
  217. CopyMemory(
  218. *lppeid,
  219. lpPropValue->Value.bin.lpb,
  220. cbeid
  221. );
  222. *lpcbeid = cbeid;
  223. cleanup:
  224. MapiFreeBuffer( lpPropValue );
  225. return hr;
  226. }
  227. HRESULT
  228. HrMAPIFindDefaultMsgStore(
  229. IN LPMAPISESSION lplhSession,
  230. OUT ULONG *lpcbeid,
  231. OUT LPENTRYID *lppeid
  232. )
  233. /*++
  234. Routine Description:
  235. Get the entry ID of the default message store. Copied from Exchange SDK.
  236. Arguments:
  237. lplhSession - session pointer
  238. lpcbeid - count of bytes in entry ID
  239. lppeid - entry ID default store
  240. Return value:
  241. HRESULT (see MAPI docs)
  242. --*/
  243. {
  244. HRESULT hr = NOERROR;
  245. SCODE sc = 0;
  246. LPMAPITABLE lpTable = NULL;
  247. LPSRowSet lpRows = NULL;
  248. LPENTRYID lpeid = NULL;
  249. ULONG cbeid = 0;
  250. ULONG cRows = 0;
  251. ULONG i = 0;
  252. SizedSPropTagArray(2, rgPropTagArray) =
  253. {
  254. 2,
  255. {
  256. PR_DEFAULT_STORE,
  257. PR_ENTRYID
  258. }
  259. };
  260. //
  261. // Get the list of available message stores from MAPI
  262. //
  263. hr = lplhSession->GetMsgStoresTable( 0, &lpTable );
  264. if (FAILED(hr)) {
  265. goto cleanup;
  266. }
  267. //
  268. // Get the row count for the message recipient table
  269. //
  270. hr = lpTable->GetRowCount( 0, &cRows );
  271. if (FAILED(hr)) {
  272. goto cleanup;
  273. }
  274. //
  275. // Set the columns to return
  276. //
  277. hr = lpTable->SetColumns( (LPSPropTagArray)&rgPropTagArray, 0 );
  278. if (FAILED(hr)) {
  279. goto cleanup;
  280. }
  281. //
  282. // Go to the beginning of the recipient table for the envelope
  283. //
  284. hr = lpTable->SeekRow( BOOKMARK_BEGINNING, 0, NULL );
  285. if (FAILED(hr)) {
  286. goto cleanup;
  287. }
  288. //
  289. // Read all the rows of the table
  290. //
  291. hr = lpTable->QueryRows( cRows, 0, &lpRows );
  292. if (SUCCEEDED(hr) && (lpRows != NULL) && (lpRows->cRows == 0)) {
  293. FreeProws( lpRows );
  294. hr = MAPI_E_NOT_FOUND;
  295. }
  296. if (FAILED(hr) || (lpRows == NULL)) {
  297. goto cleanup;
  298. }
  299. for (i = 0; i < cRows; i++) {
  300. if(lpRows->aRow[i].lpProps[0].Value.b == TRUE) {
  301. cbeid = lpRows->aRow[i].lpProps[1].Value.bin.cb;
  302. sc = MapiAllocateBuffer( cbeid, (void **)&lpeid );
  303. if(FAILED(sc)) {
  304. cbeid = 0;
  305. lpeid = NULL;
  306. goto cleanup;
  307. }
  308. //
  309. // Copy entry ID of message store
  310. //
  311. CopyMemory(
  312. lpeid,
  313. lpRows->aRow[i].lpProps[1].Value.bin.lpb,
  314. cbeid
  315. );
  316. break;
  317. }
  318. }
  319. cleanup:
  320. if(!lpRows) {
  321. FreeProws( lpRows );
  322. }
  323. lpTable->Release();
  324. *lpcbeid = cbeid;
  325. *lppeid = lpeid;
  326. return hr;
  327. }
  328. HRESULT
  329. HrMAPIWriteFileToStream(
  330. IN HANDLE hFile,
  331. OUT LPSTREAM lpStream
  332. )
  333. /*++
  334. Routine Description:
  335. Write file to a stream given a stream pointer. Copied from Exchange SDK.
  336. Arguments:
  337. hFile - Handle to file
  338. lpStream - Pointer to stream
  339. Return value:
  340. HRESULT (see MAPI docs)
  341. --*/
  342. {
  343. HRESULT hr = NOERROR;
  344. DWORD cBytesRead = 0;
  345. ULONG cBytesWritten = 0;
  346. BYTE byteBuffer[128] = {0};
  347. BOOL fReadOk = FALSE;
  348. for(;;) {
  349. fReadOk = ReadFile(
  350. hFile,
  351. byteBuffer,
  352. sizeof(byteBuffer),
  353. &cBytesRead,
  354. NULL
  355. );
  356. if (!fReadOk) {
  357. break;
  358. }
  359. if (!cBytesRead) {
  360. hr = NOERROR;
  361. break;
  362. }
  363. hr = lpStream->Write(
  364. byteBuffer,
  365. cBytesRead,
  366. &cBytesWritten
  367. );
  368. if (FAILED(hr)) {
  369. break;
  370. }
  371. if(cBytesWritten != cBytesRead) {
  372. break;
  373. }
  374. }
  375. return hr;
  376. }
  377. VOID
  378. DoMapiLogon(
  379. PPROFILE_INFO ProfileInfo
  380. )
  381. {
  382. HRESULT HResult = 0;
  383. FLAGS MAPILogonFlags = MAPI_NEW_SESSION | MAPI_EXTENDED | MAPI_NO_MAIL;
  384. LPSTR ProfileName;
  385. LPMAPISESSION Session = NULL;
  386. if (!MapiIsInitialized) {
  387. ProfileInfo->Session = NULL;
  388. SetEvent( ProfileInfo->EventHandle );
  389. return;
  390. }
  391. if (!ServiceDebug) {
  392. MAPILogonFlags |= MAPI_NT_SERVICE;
  393. }
  394. if (ProfileInfo->UseMail) {
  395. MAPILogonFlags &= ~MAPI_NO_MAIL;
  396. }
  397. if (ProfileInfo->ProfileName[0] == 0) {
  398. MAPILogonFlags |= MAPI_USE_DEFAULT;
  399. }
  400. ProfileName = UnicodeStringToAnsiString( ProfileInfo->ProfileName );
  401. __try {
  402. HResult = MapiLogonEx(
  403. 0,
  404. ProfileName,
  405. NULL,
  406. MAPILogonFlags,
  407. &Session
  408. );
  409. } __except (EXCEPTION_EXECUTE_HANDLER) {
  410. HResult = GetExceptionCode();
  411. }
  412. if (HR_FAILED(HResult)) {
  413. SetLastError( HResult );
  414. ProfileInfo->Session = NULL;
  415. } else {
  416. InitializeCriticalSection( &ProfileInfo->CsSession );
  417. ProfileInfo->Session = Session;
  418. }
  419. FreeString( ProfileName );
  420. SetEvent( ProfileInfo->EventHandle );
  421. }
  422. BOOL
  423. DoMapiLogoff(
  424. LPMAPISESSION Session
  425. )
  426. {
  427. HRESULT HResult = Session->Logoff( 0, 0, 0 );
  428. if (HR_FAILED(HResult)) {
  429. return FALSE;
  430. }
  431. return TRUE;
  432. }
  433. extern "C"
  434. BOOL WINAPI
  435. StoreMapiMessage(
  436. LPVOID ProfileInfo,
  437. LPWSTR MsgSenderNameW,
  438. LPWSTR MsgSubjectW,
  439. LPWSTR MsgBodyW,
  440. LPWSTR MsgAttachmentFileNameW,
  441. LPWSTR MsgAttachmentTitleW,
  442. DWORD MsgImportance,
  443. LPFILETIME MsgTime,
  444. PULONG ResultCode
  445. )
  446. /*++
  447. Routine Description:
  448. Mails a TIFF file to the inbox in the specified profile.
  449. Arguments:
  450. TiffFileName - Name of TIFF file to mail
  451. ProfileName - Profile name to use
  452. ResultCode - The result of the failed API call
  453. Return Value:
  454. TRUE for success, FALSE on error
  455. --*/
  456. {
  457. LPATTACH Attach = NULL;
  458. ULONG AttachmentNum;
  459. CHAR FileExt[_MAX_EXT];
  460. CHAR FileName[MAX_PATH];
  461. HRESULT HResult = 0;
  462. LPMAPIFOLDER Inbox = NULL;
  463. LPMESSAGE Message = NULL;
  464. LPSTR MsgAttachmentFileName = NULL;
  465. LPSTR MsgAttachmentTitle = NULL;
  466. LPSTR MsgBody = NULL;
  467. LPSTR MsgSenderName = NULL;
  468. LPSTR MsgSubject = NULL;
  469. DWORD RenderingPosition = 0;
  470. LPMDB Store = NULL;
  471. LPSTREAM Stream = NULL;
  472. ULONG cbInEntryID = 0;
  473. HANDLE hFile = INVALID_HANDLE_VALUE;
  474. LPENTRYID lpInEntryID = NULL;
  475. LPSPropProblemArray lppProblems;
  476. ULONG lpulObjType;
  477. SPropValue spvAttachProps[5] = { 0 };
  478. SPropValue spvMsgProps[9] = { 0 };
  479. FILETIME CurrentTime;
  480. LPMAPISESSION Session = ((PPROFILE_INFO)ProfileInfo)->Session;
  481. _try {
  482. //
  483. // get the time if the caller wants us to
  484. //
  485. if (!MsgTime) {
  486. MsgTime = &CurrentTime;
  487. GetSystemTimeAsFileTime( MsgTime );
  488. }
  489. //
  490. // find the default message store
  491. //
  492. HResult = HrMAPIFindDefaultMsgStore( (LPMAPISESSION) Session, &cbInEntryID, &lpInEntryID );
  493. if(HR_FAILED(HResult)) {
  494. _leave;
  495. }
  496. //
  497. // open the message store
  498. //
  499. HResult = ((LPMAPISESSION)Session)->OpenMsgStore(
  500. 0,
  501. cbInEntryID,
  502. lpInEntryID,
  503. NULL,
  504. MDB_NO_DIALOG | MDB_WRITE,
  505. &Store
  506. );
  507. if (HR_FAILED(HResult)) {
  508. _leave;
  509. }
  510. MapiFreeBuffer( lpInEntryID );
  511. //
  512. // find the inbox
  513. //
  514. HResult= HrMAPIFindInbox( Store, &cbInEntryID, &lpInEntryID );
  515. if(HR_FAILED(HResult)) {
  516. _leave;
  517. }
  518. //
  519. // open the inbox
  520. //
  521. HResult = ((LPMAPISESSION)Session)->OpenEntry(
  522. cbInEntryID,
  523. lpInEntryID,
  524. NULL,
  525. MAPI_MODIFY,
  526. &lpulObjType,
  527. (LPUNKNOWN *) &Inbox
  528. );
  529. if (HR_FAILED(HResult)) {
  530. _leave;
  531. }
  532. //
  533. // Create a message
  534. //
  535. HResult = Inbox->CreateMessage(
  536. NULL,
  537. 0,
  538. &Message
  539. );
  540. if (HR_FAILED(HResult)) {
  541. _leave;
  542. }
  543. //
  544. // convert all of the strings to ansi strings
  545. //
  546. MsgSenderName = UnicodeStringToAnsiString( MsgSenderNameW );
  547. MsgSubject = UnicodeStringToAnsiString( MsgSubjectW );
  548. MsgBody = UnicodeStringToAnsiString( MsgBodyW );
  549. MsgAttachmentFileName = UnicodeStringToAnsiString( MsgAttachmentFileNameW );
  550. MsgAttachmentTitle = UnicodeStringToAnsiString( MsgAttachmentTitleW );
  551. //
  552. // Fill in message properties and set them
  553. //
  554. spvMsgProps[0].ulPropTag = PR_SENDER_NAME;
  555. spvMsgProps[1].ulPropTag = PR_SENT_REPRESENTING_NAME;
  556. spvMsgProps[2].ulPropTag = PR_SUBJECT;
  557. spvMsgProps[3].ulPropTag = PR_MESSAGE_CLASS;
  558. spvMsgProps[4].ulPropTag = PR_BODY;
  559. spvMsgProps[5].ulPropTag = PR_MESSAGE_DELIVERY_TIME;
  560. spvMsgProps[6].ulPropTag = PR_CLIENT_SUBMIT_TIME;
  561. spvMsgProps[7].ulPropTag = PR_MESSAGE_FLAGS;
  562. spvMsgProps[8].ulPropTag = PR_IMPORTANCE;
  563. spvMsgProps[0].Value.lpszA = MsgSenderName;
  564. spvMsgProps[1].Value.lpszA = MsgSenderName;
  565. spvMsgProps[2].Value.lpszA = MsgSubject;
  566. spvMsgProps[3].Value.lpszA = "IPM.Note";
  567. spvMsgProps[4].Value.lpszA = MsgBody;
  568. spvMsgProps[5].Value.ft = *MsgTime;
  569. spvMsgProps[6].Value.ft = *MsgTime;
  570. spvMsgProps[7].Value.ul = 0;
  571. spvMsgProps[8].Value.ul = MsgImportance;
  572. HResult = Message->SetProps(
  573. sizeof(spvMsgProps)/sizeof(SPropValue),
  574. (LPSPropValue) spvMsgProps,
  575. &lppProblems
  576. );
  577. if (HR_FAILED(HResult)) {
  578. _leave;
  579. }
  580. MapiFreeBuffer( lppProblems );
  581. if (MsgAttachmentFileName) {
  582. //
  583. // Create an attachment
  584. //
  585. HResult = Message->CreateAttach(
  586. NULL,
  587. 0,
  588. &AttachmentNum,
  589. &Attach
  590. );
  591. if (HR_FAILED(HResult)) {
  592. _leave;
  593. }
  594. _splitpath( MsgAttachmentFileName, NULL, NULL, FileName, FileExt );
  595. strcat( FileName, FileExt );
  596. //
  597. // Fill in attachment properties and set them
  598. //
  599. if (!MsgAttachmentTitle) {
  600. MsgAttachmentTitle = FileName;
  601. }
  602. RenderingPosition = strlen(MsgBody);
  603. spvAttachProps[0].ulPropTag = PR_RENDERING_POSITION;
  604. spvAttachProps[1].ulPropTag = PR_ATTACH_METHOD;
  605. spvAttachProps[2].ulPropTag = PR_ATTACH_LONG_FILENAME;
  606. spvAttachProps[3].ulPropTag = PR_DISPLAY_NAME;
  607. spvAttachProps[4].ulPropTag = PR_ATTACH_EXTENSION;
  608. spvAttachProps[0].Value.ul = RenderingPosition;
  609. spvAttachProps[1].Value.ul = ATTACH_BY_VALUE;
  610. spvAttachProps[2].Value.lpszA = MsgAttachmentTitle;
  611. spvAttachProps[3].Value.lpszA = MsgAttachmentTitle;
  612. spvAttachProps[4].Value.lpszA = FileExt;
  613. HResult = Attach->SetProps(
  614. sizeof(spvAttachProps)/sizeof(SPropValue),
  615. (LPSPropValue) spvAttachProps,
  616. &lppProblems
  617. );
  618. if (HR_FAILED(HResult)) {
  619. _leave;
  620. }
  621. MapiFreeBuffer( lppProblems );
  622. //
  623. // Attach a data property to the attachment
  624. //
  625. HResult = Attach->OpenProperty(
  626. PR_ATTACH_DATA_BIN,
  627. &IID_IStream,
  628. 0,
  629. MAPI_CREATE | MAPI_MODIFY,
  630. (LPUNKNOWN *) &Stream
  631. );
  632. if (HR_FAILED(HResult)) {
  633. _leave;
  634. }
  635. //
  636. // open the message attachment file
  637. //
  638. hFile = CreateFile(
  639. MsgAttachmentFileName,
  640. GENERIC_READ,
  641. FILE_SHARE_READ,
  642. NULL,
  643. OPEN_EXISTING,
  644. 0,
  645. NULL
  646. );
  647. if (hFile == INVALID_HANDLE_VALUE) {
  648. _leave;
  649. }
  650. //
  651. // Write the file to the data property
  652. //
  653. HResult = HrMAPIWriteFileToStream( hFile, Stream );
  654. if (HR_FAILED(HResult)) {
  655. _leave;
  656. }
  657. }
  658. //
  659. // Save the changes and logoff
  660. //
  661. HResult = Attach->SaveChanges(
  662. FORCE_SAVE
  663. );
  664. if (HR_FAILED(HResult)) {
  665. _leave;
  666. }
  667. HResult = Message->SaveChanges(
  668. FORCE_SAVE
  669. );
  670. if (HR_FAILED(HResult)) {
  671. _leave;
  672. }
  673. }
  674. _finally {
  675. MapiFreeBuffer( lpInEntryID );
  676. if (Store) {
  677. Store->Release();
  678. }
  679. if (Inbox) {
  680. Inbox->Release();
  681. }
  682. if (Message) {
  683. Message->Release();
  684. }
  685. if (Attach) {
  686. Attach->Release();
  687. }
  688. if (Stream) {
  689. Stream->Release();
  690. }
  691. FreeString( MsgSenderName );
  692. FreeString( MsgSubject );
  693. FreeString( MsgBody );
  694. FreeString( MsgAttachmentFileName );
  695. if (MsgAttachmentTitleW && MsgAttachmentTitle) {
  696. FreeString( MsgAttachmentTitle );
  697. }
  698. CloseHandle( hFile );
  699. }
  700. *ResultCode = HResult;
  701. return HResult == 0;
  702. }
  703. extern "C"
  704. LONG WINAPI
  705. GetMapiProfiles(
  706. LPWSTR *OutBuffer,
  707. LPDWORD OutBufferSize
  708. )
  709. {
  710. HMODULE MapiMod = NULL;
  711. LPMAPITABLE pmt = NULL;
  712. LPSRowSet prws = NULL;
  713. LPSPropValue pval;
  714. LPPROFADMIN lpProfAdmin;
  715. DWORD i;
  716. HRESULT hr;
  717. DWORD Count;
  718. LPWSTR Buffer;
  719. DWORD BytesNeeded;
  720. DWORD Offset = 0;
  721. if (!MapiIsInitialized) {
  722. return MAPI_E_NO_SUPPORT;
  723. }
  724. if (hr = MapiAdminProfiles( 0, &lpProfAdmin )) {
  725. return hr;
  726. }
  727. //
  728. // get the mapi table object
  729. //
  730. if (hr = lpProfAdmin->GetProfileTable( 0, &pmt )) {
  731. goto exit;
  732. }
  733. //
  734. // get the actual profile data, FINALLY
  735. //
  736. if (hr = pmt->QueryRows( 4000, 0, &prws )) {
  737. goto exit;
  738. }
  739. //
  740. // enumerate the profiles and put the name
  741. // of each profile in the combo box
  742. //
  743. BytesNeeded = 0;
  744. for (i=0; i<prws->cRows; i++) {
  745. pval = prws->aRow[i].lpProps;
  746. Count = MultiByteToWideChar(
  747. CP_ACP,
  748. MB_PRECOMPOSED,
  749. pval[0].Value.lpszA,
  750. -1,
  751. NULL,
  752. 0
  753. );
  754. if (Count == 0) {
  755. hr = GetLastError();
  756. goto exit;
  757. } else {
  758. BytesNeeded += Count * sizeof(WCHAR);
  759. }
  760. }
  761. BytesNeeded += sizeof(UNICODE_NULL);
  762. Buffer = (LPWSTR) MemAlloc( BytesNeeded );
  763. if (Buffer == NULL) {
  764. hr = ERROR_INSUFFICIENT_BUFFER;
  765. goto exit;
  766. }
  767. for (i=0; i<prws->cRows; i++) {
  768. pval = prws->aRow[i].lpProps;
  769. Count = MultiByteToWideChar(
  770. CP_ACP,
  771. MB_PRECOMPOSED,
  772. pval[0].Value.lpszA,
  773. -1,
  774. &Buffer[Offset],
  775. BytesNeeded - (Offset * sizeof(WCHAR))
  776. );
  777. if (Count == 0) {
  778. hr = GetLastError();
  779. goto exit;
  780. } else {
  781. Offset += Count;
  782. }
  783. }
  784. Buffer[Offset] = 0;
  785. *OutBuffer = Buffer;
  786. *OutBufferSize = BytesNeeded;
  787. hr = ERROR_SUCCESS;
  788. exit:
  789. FreeProws( prws );
  790. if (pmt) {
  791. pmt->Release();
  792. }
  793. if (lpProfAdmin) {
  794. lpProfAdmin->Release();
  795. }
  796. return hr;
  797. }
  798. BOOL
  799. GetDefaultMapiProfile(
  800. LPWSTR ProfileName
  801. )
  802. {
  803. BOOL rVal = FALSE;
  804. LPMAPITABLE pmt = NULL;
  805. LPSRowSet prws = NULL;
  806. LPSPropValue pval;
  807. LPPROFADMIN lpProfAdmin;
  808. DWORD i;
  809. DWORD j;
  810. if (!MapiIsInitialized) {
  811. goto exit;
  812. }
  813. if (MapiAdminProfiles( 0, &lpProfAdmin )) {
  814. goto exit;
  815. }
  816. //
  817. // get the mapi profile table object
  818. //
  819. if (lpProfAdmin->GetProfileTable( 0, &pmt )) {
  820. goto exit;
  821. }
  822. //
  823. // get the actual profile data, FINALLY
  824. //
  825. if (pmt->QueryRows( 4000, 0, &prws )) {
  826. goto exit;
  827. }
  828. //
  829. // enumerate the profiles looking for the default profile
  830. //
  831. for (i=0; i<prws->cRows; i++) {
  832. pval = prws->aRow[i].lpProps;
  833. for (j = 0; j < 2; j++) {
  834. if (pval[j].ulPropTag == PR_DEFAULT_PROFILE && pval[j].Value.b) {
  835. //
  836. // this is the default profile
  837. //
  838. MultiByteToWideChar(
  839. CP_ACP,
  840. MB_PRECOMPOSED,
  841. pval[0].Value.lpszA,
  842. -1,
  843. ProfileName,
  844. (cchProfileNameMax + 1) * sizeof(WCHAR)
  845. );
  846. rVal = TRUE;
  847. break;
  848. }
  849. }
  850. }
  851. exit:
  852. FreeProws( prws );
  853. if (pmt) {
  854. pmt->Release();
  855. }
  856. return rVal;
  857. }
  858. #define IADDRTYPE 0
  859. #define IEMAILADDR 1
  860. #define IMAPIRECIP 2
  861. #define IPROXYADDR 3
  862. #define PR_EMS_AB_CONTAINERID PROP_TAG(PT_LONG, 0xFFFD)
  863. #define PR_EMS_AB_PROXY_ADDRESSES_A PROP_TAG(PT_MV_STRING8, 0x800F)
  864. #define MUIDEMSAB {0xDC, 0xA7, 0x40, 0xC8, 0xC0, 0x42, 0x10, 0x1A, 0xB4, 0xB9, 0x08, 0x00, 0x2B, 0x2F, 0xE1, 0x82}
  865. #define CbNewFlagList(_cflag) (offsetof(FlagList,ulFlag) + (_cflag)*sizeof(ULONG))
  866. HRESULT
  867. HrMAPICreateSizedAddressList( // RETURNS: return code
  868. IN ULONG cEntries, // count of entries in address list
  869. OUT LPADRLIST *lppAdrList // pointer to address list pointer
  870. )
  871. {
  872. HRESULT hr = NOERROR;
  873. SCODE sc = 0;
  874. ULONG cBytes = 0;
  875. *lppAdrList = NULL;
  876. cBytes = CbNewADRLIST(cEntries);
  877. sc = MapiAllocateBuffer(cBytes, (PVOID*) lppAdrList);
  878. if(FAILED(sc))
  879. {
  880. hr = E_OUTOFMEMORY;
  881. goto cleanup;
  882. }
  883. // Initialize ADRLIST structure
  884. ZeroMemory(*lppAdrList, cBytes);
  885. (*lppAdrList)->cEntries = cEntries;
  886. cleanup:
  887. return hr;
  888. }
  889. HRESULT
  890. HrMAPISetAddressList( // RETURNS: return code
  891. IN ULONG iEntry, // index of address list entry
  892. IN ULONG cProps, // count of values in address list entry
  893. IN LPSPropValue lpPropValues, // pointer to address list entry
  894. IN OUT LPADRLIST lpAdrList // pointer to address list pointer
  895. )
  896. {
  897. HRESULT hr = NOERROR;
  898. SCODE sc = 0;
  899. LPSPropValue lpNewPropValues = NULL;
  900. ULONG cBytes = 0;
  901. if(iEntry >= lpAdrList->cEntries)
  902. {
  903. hr = E_FAIL;
  904. goto cleanup;
  905. }
  906. sc = pScDupPropset(
  907. cProps,
  908. lpPropValues,
  909. MapiAllocateBuffer,
  910. &lpNewPropValues
  911. );
  912. if(FAILED(sc))
  913. {
  914. hr = E_FAIL;
  915. goto cleanup;
  916. }
  917. if(lpAdrList->aEntries[iEntry].rgPropVals != NULL)
  918. {
  919. MapiFreeBuffer(lpAdrList->aEntries[iEntry].rgPropVals);
  920. }
  921. lpAdrList->aEntries[iEntry].cValues = cProps;
  922. lpAdrList->aEntries[iEntry].rgPropVals = lpNewPropValues;
  923. cleanup:
  924. return hr;
  925. }
  926. HRESULT
  927. HrCheckForTypeA( // RETURNS: return code
  928. IN LPCSTR lpszAddrType, // pointer to address type
  929. IN LPCSTR lpszProxy, // pointer to proxy address
  930. OUT LPSTR * lppszAddress // pointer to address pointer
  931. )
  932. {
  933. HRESULT hr = E_FAIL;
  934. LPCSTR lpszProxyAddr = NULL;
  935. ULONG cbAddress = 0;
  936. SCODE sc = 0;
  937. ULONG cchProxy = 0;
  938. ULONG cchProxyType = 0;
  939. // Initialize output parameter
  940. *lppszAddress = NULL;
  941. // find the ':' separator.
  942. cchProxy = lstrlenA(lpszProxy);
  943. cchProxyType = strcspn(lpszProxy, ":");
  944. if((cchProxyType == 0) || (cchProxyType >= cchProxy))
  945. {
  946. hr = E_FAIL;
  947. goto cleanup;
  948. }
  949. hr = MAPI_E_NOT_FOUND;
  950. // does the address type match?
  951. if((cchProxyType == (ULONG)lstrlenA(lpszAddrType)) &&
  952. (_strnicmp(lpszProxy, lpszAddrType, cchProxyType) == 0))
  953. {
  954. // specified address type found
  955. lpszProxyAddr = lpszProxy + cchProxyType + 1;
  956. cbAddress = strlen(lpszProxyAddr);
  957. // make a buffer to hold it.
  958. sc = MapiAllocateBuffer(cbAddress, (void **)lppszAddress);
  959. if(FAILED(sc))
  960. {
  961. hr = E_OUTOFMEMORY;
  962. }
  963. else
  964. {
  965. CopyMemory(*lppszAddress, lpszProxyAddr, cbAddress);
  966. hr = NOERROR;
  967. }
  968. }
  969. cleanup:
  970. return hr;
  971. }
  972. HRESULT
  973. HrFindExchangeGlobalAddressList(
  974. IN LPADRBOOK lpAdrBook,
  975. OUT ULONG *lpcbeid,
  976. OUT LPENTRYID *lppeid
  977. )
  978. {
  979. HRESULT hr = NOERROR;
  980. ULONG ulObjType = 0;
  981. ULONG i = 0;
  982. LPMAPIPROP lpRootContainer = NULL;
  983. LPMAPIPROP lpContainer = NULL;
  984. LPMAPITABLE lpContainerTable = NULL;
  985. LPSRowSet lpRows = NULL;
  986. ULONG cbContainerEntryId = 0;
  987. LPENTRYID lpContainerEntryId = NULL;
  988. LPSPropValue lpCurrProp = NULL;
  989. SRestriction SRestrictAnd[2] = {0};
  990. SRestriction SRestrictGAL = {0};
  991. SPropValue SPropID = {0};
  992. SPropValue SPropProvider = {0};
  993. BYTE muid[] = MUIDEMSAB;
  994. SizedSPropTagArray(1, rgPropTags) =
  995. {
  996. 1,
  997. {
  998. PR_ENTRYID,
  999. }
  1000. };
  1001. *lpcbeid = 0;
  1002. *lppeid = NULL;
  1003. // Open the root container of the address book
  1004. hr = lpAdrBook->OpenEntry(
  1005. 0,
  1006. NULL,
  1007. NULL,
  1008. MAPI_DEFERRED_ERRORS,
  1009. &ulObjType,
  1010. (LPUNKNOWN FAR *)&lpRootContainer
  1011. );
  1012. if(FAILED(hr))
  1013. {
  1014. goto cleanup;
  1015. }
  1016. if(ulObjType != MAPI_ABCONT)
  1017. {
  1018. hr = E_FAIL;
  1019. goto cleanup;
  1020. }
  1021. // Get the hierarchy table of the root container
  1022. hr = ((LPABCONT)lpRootContainer)->GetHierarchyTable(
  1023. MAPI_DEFERRED_ERRORS|CONVENIENT_DEPTH,
  1024. &lpContainerTable
  1025. );
  1026. if(FAILED(hr))
  1027. {
  1028. goto cleanup;
  1029. }
  1030. // Restrict the table to the global address list (GAL)
  1031. // ---------------------------------------------------
  1032. // Initialize provider restriction to only Exchange providers
  1033. SRestrictAnd[0].rt = RES_PROPERTY;
  1034. SRestrictAnd[0].res.resProperty.relop = RELOP_EQ;
  1035. SRestrictAnd[0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID;
  1036. SPropProvider.ulPropTag = PR_AB_PROVIDER_ID;
  1037. SPropProvider.Value.bin.cb = 16;
  1038. SPropProvider.Value.bin.lpb = (LPBYTE)muid;
  1039. SRestrictAnd[0].res.resProperty.lpProp = &SPropProvider;
  1040. // Initialize container ID restriction to only GAL container
  1041. SRestrictAnd[1].rt = RES_PROPERTY;
  1042. SRestrictAnd[1].res.resProperty.relop = RELOP_EQ;
  1043. SRestrictAnd[1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID;
  1044. SPropID.ulPropTag = PR_EMS_AB_CONTAINERID;
  1045. SPropID.Value.l = 0;
  1046. SRestrictAnd[1].res.resProperty.lpProp = &SPropID;
  1047. // Initialize AND restriction
  1048. SRestrictGAL.rt = RES_AND;
  1049. SRestrictGAL.res.resAnd.cRes = 2;
  1050. SRestrictGAL.res.resAnd.lpRes = &SRestrictAnd[0];
  1051. // Restrict the table to the GAL - only a single row should remain
  1052. // Get the row corresponding to the GAL
  1053. //
  1054. // Query all the rows
  1055. //
  1056. hr = pHrQueryAllRows(
  1057. lpContainerTable,
  1058. (LPSPropTagArray)&rgPropTags,
  1059. &SRestrictGAL,
  1060. NULL,
  1061. 0,
  1062. &lpRows
  1063. );
  1064. if(FAILED(hr) || (lpRows == NULL) || (lpRows->cRows != 1))
  1065. {
  1066. hr = E_FAIL;
  1067. goto cleanup;
  1068. }
  1069. // Get the entry ID for the GAL
  1070. lpCurrProp = &(lpRows->aRow[0].lpProps[0]);
  1071. if(lpCurrProp->ulPropTag == PR_ENTRYID)
  1072. {
  1073. cbContainerEntryId = lpCurrProp->Value.bin.cb;
  1074. lpContainerEntryId = (LPENTRYID)lpCurrProp->Value.bin.lpb;
  1075. }
  1076. else
  1077. {
  1078. hr = E_FAIL;
  1079. goto cleanup;
  1080. }
  1081. hr = MapiAllocateBuffer( cbContainerEntryId, (LPVOID *)lppeid );
  1082. if(FAILED(hr))
  1083. {
  1084. *lpcbeid = 0;
  1085. *lppeid = NULL;
  1086. }
  1087. else
  1088. {
  1089. CopyMemory(
  1090. *lppeid,
  1091. lpContainerEntryId,
  1092. cbContainerEntryId);
  1093. *lpcbeid = cbContainerEntryId;
  1094. }
  1095. cleanup:
  1096. pUlRelease(lpRootContainer);
  1097. pUlRelease(lpContainerTable);
  1098. pUlRelease(lpContainer);
  1099. FreeProws( lpRows );
  1100. if(FAILED(hr)) {
  1101. MapiFreeBuffer( *lppeid );
  1102. *lpcbeid = 0;
  1103. *lppeid = NULL;
  1104. }
  1105. return hr;
  1106. }
  1107. HRESULT
  1108. HrGWResolveProxy(
  1109. IN LPADRBOOK lpAdrBook, // pointer to address book
  1110. IN ULONG cbeid, // count of bytes in the entry ID
  1111. IN LPENTRYID lpeid, // pointer to the entry ID
  1112. IN LPCSTR lpszAddrType, // pointer to the address type
  1113. OUT BOOL *lpfMapiRecip, // MAPI recipient
  1114. OUT LPSTR *lppszAddress // pointer to the address pointer
  1115. )
  1116. {
  1117. HRESULT hr = E_FAIL;
  1118. HRESULT hrT = 0;
  1119. SCODE sc = 0;
  1120. ULONG i = 0;
  1121. ULONG cbAddress = 0;
  1122. ULONG cProxy = 0;
  1123. LPSPropValue lpProps = NULL;
  1124. LPADRLIST lpAdrList = NULL;
  1125. SPropValue prop[2] = {0};
  1126. SizedSPropTagArray(4, rgPropTags) =
  1127. {
  1128. 4,
  1129. {
  1130. PR_ADDRTYPE_A,
  1131. PR_EMAIL_ADDRESS_A,
  1132. PR_SEND_RICH_INFO,
  1133. PR_EMS_AB_PROXY_ADDRESSES_A
  1134. }
  1135. };
  1136. // Initialize output parameters
  1137. *lpfMapiRecip = FALSE;
  1138. *lppszAddress = NULL;
  1139. hr = HrMAPICreateSizedAddressList(1, &lpAdrList);
  1140. if(FAILED(hr))
  1141. {
  1142. goto cleanup;
  1143. }
  1144. prop[0].ulPropTag = PR_ENTRYID;
  1145. prop[0].Value.bin.cb = cbeid;
  1146. prop[0].Value.bin.lpb = (LPBYTE)lpeid;
  1147. prop[1].ulPropTag = PR_RECIPIENT_TYPE;
  1148. prop[1].Value.ul = MAPI_TO;
  1149. hr = HrMAPISetAddressList(
  1150. 0,
  1151. 2,
  1152. prop,
  1153. lpAdrList
  1154. );
  1155. if(FAILED(hr))
  1156. {
  1157. goto cleanup;
  1158. }
  1159. hrT = lpAdrBook->PrepareRecips(
  1160. 0,
  1161. (LPSPropTagArray)&rgPropTags,
  1162. lpAdrList
  1163. );
  1164. if(FAILED(hrT))
  1165. {
  1166. goto cleanup;
  1167. }
  1168. lpProps = lpAdrList->aEntries[0].rgPropVals;
  1169. //
  1170. // Hack: detect the case where prepare recips doesn't work correctly.
  1171. // This happens when trying to look up a recipient that is in
  1172. // a replicated directory but not in the local directory.
  1173. //
  1174. if (lpAdrList->aEntries[0].cValues == 3)
  1175. {
  1176. hr = E_FAIL;
  1177. goto cleanup;
  1178. }
  1179. // If the given address type matches the PR_ADDRTYPE value,
  1180. // return the PR_EMAIL_ADDRESS value
  1181. if((PROP_TYPE(lpProps[IADDRTYPE].ulPropTag) != PT_ERROR) &&
  1182. (PROP_TYPE(lpProps[IEMAILADDR].ulPropTag) != PT_ERROR) &&
  1183. (_strcmpi(lpProps[IADDRTYPE].Value.lpszA, lpszAddrType) == 0))
  1184. {
  1185. cbAddress = strlen(lpProps[IEMAILADDR].Value.lpszA);
  1186. sc = MapiAllocateBuffer(cbAddress, (void **)lppszAddress);
  1187. if(FAILED(sc))
  1188. {
  1189. hr = E_OUTOFMEMORY;
  1190. }
  1191. else
  1192. {
  1193. CopyMemory(*lppszAddress, lpProps[IEMAILADDR].Value.lpszW, cbAddress);
  1194. hr = NOERROR;
  1195. }
  1196. goto cleanup;
  1197. }
  1198. // Search for a PR_EMS_AB_PROXY_ADDRESSES of the given type if present.
  1199. else if(PROP_TYPE(lpProps[IPROXYADDR].ulPropTag) != PT_ERROR)
  1200. {
  1201. // count of proxy addresses
  1202. cProxy = lpAdrList->aEntries[0].rgPropVals[IPROXYADDR].Value.MVszA.cValues;
  1203. for(i = 0; i < cProxy; i++)
  1204. {
  1205. hr = HrCheckForTypeA(
  1206. lpszAddrType,
  1207. lpProps[IPROXYADDR].Value.MVszA.lppszA[i],
  1208. lppszAddress
  1209. );
  1210. if(hr == MAPI_E_NOT_FOUND)
  1211. {
  1212. continue;
  1213. }
  1214. else if(FAILED(hr))
  1215. {
  1216. goto cleanup;
  1217. }
  1218. else
  1219. {
  1220. //
  1221. // Found a matching proxy address.
  1222. //
  1223. goto cleanup;
  1224. }
  1225. }
  1226. }
  1227. else
  1228. {
  1229. hr = E_FAIL;
  1230. goto cleanup;
  1231. }
  1232. cleanup:
  1233. if(SUCCEEDED(hr))
  1234. {
  1235. *lpfMapiRecip = lpAdrList->aEntries[0].rgPropVals[IMAPIRECIP].Value.b;
  1236. }
  1237. pFreePadrlist(lpAdrList);
  1238. return hr;
  1239. }
  1240. HRESULT
  1241. HrGWResolveAddress(
  1242. IN LPABCONT lpGalABCont, // pointer to GAL container
  1243. IN LPCSTR lpszAddress, // pointer to proxy address
  1244. OUT BOOL *lpfMapiRecip, // MAPI recipient
  1245. OUT ULONG *lpcbEntryID, // count of bytes in entry ID
  1246. OUT LPENTRYID *lppEntryID, // pointer to entry ID
  1247. OUT LPADRLIST *lpAdrList // address list
  1248. )
  1249. {
  1250. HRESULT hr = NOERROR;
  1251. HRESULT hrT = 0;
  1252. SCODE sc = 0;
  1253. LPFlagList lpFlagList = NULL;
  1254. SPropValue prop[2] = {0};
  1255. ULONG cbEntryID = 0;
  1256. LPENTRYID lpEntryID = NULL;
  1257. static const SizedSPropTagArray(2, rgPropTags) =
  1258. { 2,
  1259. {
  1260. PR_ENTRYID,
  1261. PR_SEND_RICH_INFO
  1262. }
  1263. };
  1264. *lpfMapiRecip = FALSE;
  1265. *lpcbEntryID = 0;
  1266. *lppEntryID = NULL;
  1267. *lpAdrList = NULL;
  1268. sc = MapiAllocateBuffer( CbNewFlagList(1), (LPVOID*)&lpFlagList);
  1269. if(FAILED(sc))
  1270. {
  1271. hr = E_OUTOFMEMORY;
  1272. goto cleanup;
  1273. }
  1274. lpFlagList->cFlags = 1;
  1275. lpFlagList->ulFlag[0] = MAPI_UNRESOLVED;
  1276. hr = HrMAPICreateSizedAddressList(
  1277. 1,
  1278. lpAdrList
  1279. );
  1280. if(FAILED(hr)) {
  1281. goto cleanup;
  1282. }
  1283. prop[0].ulPropTag = PR_DISPLAY_NAME_A;
  1284. prop[0].Value.lpszA = (LPSTR)lpszAddress;
  1285. prop[1].ulPropTag = PR_RECIPIENT_TYPE;
  1286. prop[1].Value.ul = MAPI_TO;
  1287. hr = HrMAPISetAddressList(
  1288. 0,
  1289. 2,
  1290. prop,
  1291. *lpAdrList
  1292. );
  1293. if(FAILED(hr)) {
  1294. goto cleanup;
  1295. }
  1296. hrT = lpGalABCont->ResolveNames(
  1297. (LPSPropTagArray)&rgPropTags,
  1298. 0,
  1299. *lpAdrList,
  1300. lpFlagList
  1301. );
  1302. if(lpFlagList->ulFlag[0] != MAPI_RESOLVED)
  1303. {
  1304. if(lpFlagList->ulFlag[0] == MAPI_AMBIGUOUS)
  1305. {
  1306. hrT = MAPI_E_AMBIGUOUS_RECIP;
  1307. }
  1308. else
  1309. {
  1310. hrT = MAPI_E_NOT_FOUND;
  1311. }
  1312. }
  1313. if(FAILED(hrT))
  1314. {
  1315. if(hrT == MAPI_E_NOT_FOUND)
  1316. {
  1317. hr = MAPI_E_NOT_FOUND;
  1318. }
  1319. else
  1320. {
  1321. hr = E_FAIL;
  1322. }
  1323. goto cleanup;
  1324. }
  1325. cbEntryID = (*lpAdrList)->aEntries[0].rgPropVals[0].Value.bin.cb;
  1326. lpEntryID = (LPENTRYID)(*lpAdrList)->aEntries[0].rgPropVals[0].Value.bin.lpb;
  1327. sc = MapiAllocateBuffer( cbEntryID, (LPVOID*)lppEntryID);
  1328. if(FAILED(sc))
  1329. {
  1330. hr = E_OUTOFMEMORY;
  1331. goto cleanup;
  1332. }
  1333. CopyMemory(*lppEntryID, lpEntryID, cbEntryID);
  1334. *lpcbEntryID = cbEntryID;
  1335. *lpfMapiRecip = (*lpAdrList)->aEntries[0].rgPropVals[1].Value.b;
  1336. cleanup:
  1337. MapiFreeBuffer(lpFlagList);
  1338. return hr;
  1339. }
  1340. extern "C"
  1341. BOOL WINAPI
  1342. MailMapiMessage(
  1343. LPVOID ProfileInfo,
  1344. LPWSTR RecipientNameW,
  1345. LPWSTR MsgSubjectW,
  1346. LPWSTR MsgBodyW,
  1347. LPWSTR MsgAttachmentFileNameW,
  1348. LPWSTR MsgAttachmentTitleW,
  1349. DWORD MsgImportance,
  1350. PULONG ResultCode
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. Mails a TIFF file to the addressbook recipient in the specified profile.
  1355. Arguments:
  1356. TiffFileName - Name of TIFF file to mail
  1357. ProfileName - Profile name to use
  1358. ResultCode - The result of the failed API call
  1359. Return Value:
  1360. TRUE for success, FALSE on error
  1361. --*/
  1362. {
  1363. ULONG cbInEntryID = 0;
  1364. LPENTRYID lpInEntryID = NULL;
  1365. LPMDB Store = NULL;
  1366. ULONG lpulObjType;
  1367. LPMAPIFOLDER Inbox = NULL;
  1368. LPMAPIFOLDER Outbox = NULL;
  1369. LPMESSAGE Message = NULL;
  1370. LPATTACH Attach = NULL;
  1371. LPSTREAM Stream = NULL;
  1372. ULONG AttachmentNum;
  1373. HRESULT HResult = 0;
  1374. LPSTR MsgAttachmentFileName = NULL;
  1375. LPSTR MsgAttachmentTitle = NULL;
  1376. LPSTR MsgBody = NULL;
  1377. LPSTR MsgSubject = NULL;
  1378. LPSTR BodyStrA = NULL;
  1379. LPSTR SubjectStrA = NULL;
  1380. LPSTR SenderStrA = NULL;
  1381. LPSTR LongFileNameA = NULL;
  1382. LPSTR RecipientName = NULL;
  1383. DWORD RenderingPosition = 0;
  1384. LPADRBOOK AddrBook;
  1385. LPADRLIST lpAddrList = NULL;
  1386. ULONG ulFlags = LOGOFF_PURGE;
  1387. LPSPropProblemArray lppProblems;
  1388. ULONG cbGalEid = 0;
  1389. LPENTRYID lpGalEid = NULL;
  1390. LPSTR lpszProxyAddr = NULL;
  1391. BOOL fMapiRecip = FALSE;
  1392. ULONG ulObjType = 0;
  1393. LPABCONT lpGalABCont = NULL;
  1394. ULONG cbEntryID = 0;
  1395. LPENTRYID lpEntryID = NULL;
  1396. SPropValue spvAttachProps[5] = { 0 };
  1397. SPropValue spvMsgProps[5] = { 0 };
  1398. CHAR FileExt[_MAX_EXT];
  1399. CHAR FileName[MAX_PATH];
  1400. HANDLE hFile = INVALID_HANDLE_VALUE;
  1401. LPMAPISESSION Session = ((PPROFILE_INFO)ProfileInfo)->Session;
  1402. _try {
  1403. //
  1404. // convert all of the strings to ansi strings
  1405. //
  1406. RecipientName = UnicodeStringToAnsiString( RecipientNameW );
  1407. MsgSubject = UnicodeStringToAnsiString( MsgSubjectW );
  1408. MsgBody = UnicodeStringToAnsiString( MsgBodyW );
  1409. MsgAttachmentFileName = UnicodeStringToAnsiString( MsgAttachmentFileNameW );
  1410. MsgAttachmentTitle = UnicodeStringToAnsiString( MsgAttachmentTitleW );
  1411. HResult = ((LPMAPISESSION)Session)->OpenAddressBook(
  1412. 0,
  1413. NULL,
  1414. AB_NO_DIALOG,
  1415. &AddrBook
  1416. );
  1417. if(HR_FAILED(HResult)) {
  1418. _leave;
  1419. }
  1420. HResult = HrFindExchangeGlobalAddressList(
  1421. AddrBook,
  1422. &cbGalEid,
  1423. &lpGalEid
  1424. );
  1425. if(HR_FAILED(HResult)) {
  1426. _leave;
  1427. }
  1428. HResult = AddrBook->OpenEntry(
  1429. cbGalEid,
  1430. lpGalEid,
  1431. NULL,
  1432. MAPI_DEFERRED_ERRORS,
  1433. &ulObjType,
  1434. (LPUNKNOWN FAR *)&lpGalABCont
  1435. );
  1436. if(HR_FAILED(HResult)) {
  1437. _leave;
  1438. }
  1439. HResult = HrGWResolveAddress(
  1440. lpGalABCont,
  1441. RecipientName,
  1442. &fMapiRecip,
  1443. &cbEntryID,
  1444. &lpEntryID,
  1445. &lpAddrList
  1446. );
  1447. if(HR_FAILED(HResult)) {
  1448. _leave;
  1449. }
  1450. //
  1451. // Find the default message store
  1452. //
  1453. HResult = HrMAPIFindDefaultMsgStore(
  1454. (LPMAPISESSION)Session,
  1455. &cbInEntryID,
  1456. &lpInEntryID
  1457. );
  1458. if(HR_FAILED(HResult)) {
  1459. _leave;
  1460. }
  1461. //
  1462. // Open it
  1463. //
  1464. HResult = ((LPMAPISESSION)Session)->OpenMsgStore(
  1465. (ULONG)0,
  1466. cbInEntryID,
  1467. lpInEntryID,
  1468. NULL,
  1469. MDB_NO_DIALOG | MDB_WRITE,
  1470. &Store
  1471. );
  1472. if(HR_FAILED(HResult)) {
  1473. _leave;
  1474. }
  1475. MapiFreeBuffer(lpInEntryID);
  1476. //
  1477. // Find the outbox
  1478. //
  1479. HResult= HrMAPIFindOutbox(
  1480. Store,
  1481. &cbInEntryID,
  1482. &lpInEntryID
  1483. );
  1484. if(HR_FAILED(HResult)) {
  1485. _leave;
  1486. }
  1487. //
  1488. // Open it
  1489. //
  1490. HResult = Store->OpenEntry(
  1491. cbInEntryID,
  1492. lpInEntryID,
  1493. NULL,
  1494. MAPI_MODIFY | MAPI_DEFERRED_ERRORS,
  1495. &lpulObjType,
  1496. (LPUNKNOWN *) &Outbox
  1497. );
  1498. if(HR_FAILED(HResult)) {
  1499. _leave;
  1500. }
  1501. //
  1502. // Create a message
  1503. //
  1504. HResult = Outbox->CreateMessage(
  1505. NULL,
  1506. 0,
  1507. &Message
  1508. );
  1509. if(HR_FAILED(HResult)) {
  1510. _leave;
  1511. }
  1512. HResult = Message->ModifyRecipients(
  1513. 0,
  1514. lpAddrList
  1515. );
  1516. if(HR_FAILED(HResult)) {
  1517. _leave;
  1518. }
  1519. //
  1520. // Fill in message properties and set them
  1521. //
  1522. spvMsgProps[0].ulPropTag = PR_SUBJECT;
  1523. spvMsgProps[1].ulPropTag = PR_MESSAGE_CLASS;
  1524. spvMsgProps[2].ulPropTag = PR_BODY;
  1525. spvMsgProps[3].ulPropTag = PR_IMPORTANCE;
  1526. spvMsgProps[4].ulPropTag = PR_DELETE_AFTER_SUBMIT;
  1527. spvMsgProps[0].Value.lpszA = MsgSubject;
  1528. spvMsgProps[1].Value.lpszA = "IPM.Note";
  1529. spvMsgProps[2].Value.lpszA = MsgBody;
  1530. spvMsgProps[3].Value.ul = MsgImportance;
  1531. spvMsgProps[4].Value.ul = TRUE;
  1532. HResult = Message->SetProps(
  1533. sizeof(spvMsgProps)/sizeof(SPropValue),
  1534. (LPSPropValue) spvMsgProps,
  1535. &lppProblems
  1536. );
  1537. if (HR_FAILED(HResult)) {
  1538. _leave;
  1539. }
  1540. MapiFreeBuffer( lppProblems );
  1541. if (MsgAttachmentFileName) {
  1542. //
  1543. // Create an attachment
  1544. //
  1545. HResult = Message->CreateAttach(
  1546. NULL,
  1547. 0,
  1548. &AttachmentNum,
  1549. &Attach
  1550. );
  1551. if (HR_FAILED(HResult)) {
  1552. _leave;
  1553. }
  1554. _splitpath( MsgAttachmentFileName, NULL, NULL, FileName, FileExt );
  1555. strcat( FileName, FileExt );
  1556. //
  1557. // Fill in attachment properties and set them
  1558. //
  1559. if (!MsgAttachmentTitle) {
  1560. MsgAttachmentTitle = FileName;
  1561. }
  1562. RenderingPosition = strlen(MsgBody);
  1563. spvAttachProps[0].ulPropTag = PR_RENDERING_POSITION;
  1564. spvAttachProps[1].ulPropTag = PR_ATTACH_METHOD;
  1565. spvAttachProps[2].ulPropTag = PR_ATTACH_LONG_FILENAME;
  1566. spvAttachProps[3].ulPropTag = PR_DISPLAY_NAME;
  1567. spvAttachProps[4].ulPropTag = PR_ATTACH_EXTENSION;
  1568. spvAttachProps[0].Value.ul = RenderingPosition;
  1569. spvAttachProps[1].Value.ul = ATTACH_BY_VALUE;
  1570. spvAttachProps[2].Value.lpszA = MsgAttachmentTitle;
  1571. spvAttachProps[3].Value.lpszA = MsgAttachmentTitle;
  1572. spvAttachProps[4].Value.lpszA = FileExt;
  1573. HResult = Attach->SetProps(
  1574. sizeof(spvAttachProps)/sizeof(SPropValue),
  1575. (LPSPropValue) spvAttachProps,
  1576. &lppProblems
  1577. );
  1578. if (HR_FAILED(HResult)) {
  1579. _leave;
  1580. }
  1581. MapiFreeBuffer( lppProblems );
  1582. //
  1583. // Attach a data property to the attachment
  1584. //
  1585. HResult = Attach->OpenProperty(
  1586. PR_ATTACH_DATA_BIN,
  1587. &IID_IStream,
  1588. 0,
  1589. MAPI_CREATE | MAPI_MODIFY,
  1590. (LPUNKNOWN *) &Stream
  1591. );
  1592. if (HR_FAILED(HResult)) {
  1593. _leave;
  1594. }
  1595. //
  1596. // open the message attachment file
  1597. //
  1598. hFile = CreateFile(
  1599. MsgAttachmentFileName,
  1600. GENERIC_READ,
  1601. FILE_SHARE_READ,
  1602. NULL,
  1603. OPEN_EXISTING,
  1604. 0,
  1605. NULL
  1606. );
  1607. if (hFile == INVALID_HANDLE_VALUE) {
  1608. _leave;
  1609. }
  1610. //
  1611. // Write the file to the data property
  1612. //
  1613. HResult = HrMAPIWriteFileToStream( hFile, Stream );
  1614. if (HR_FAILED(HResult)) {
  1615. _leave;
  1616. }
  1617. HResult = Attach->SaveChanges(
  1618. FORCE_SAVE
  1619. );
  1620. if (HR_FAILED(HResult)) {
  1621. _leave;
  1622. }
  1623. }
  1624. //
  1625. // mail the message
  1626. //
  1627. HResult = Message->SubmitMessage(
  1628. 0
  1629. );
  1630. if(HR_FAILED(HResult)) {
  1631. _leave;
  1632. }
  1633. HResult = Store->StoreLogoff(
  1634. &ulFlags
  1635. );
  1636. if(HR_FAILED(HResult)) {
  1637. _leave;
  1638. }
  1639. }
  1640. _finally {
  1641. if (Store) {
  1642. Store->Release();
  1643. }
  1644. if (Inbox) {
  1645. Inbox->Release();
  1646. }
  1647. if (Message) {
  1648. Message->Release();
  1649. }
  1650. if (Attach) {
  1651. Attach->Release();
  1652. }
  1653. if (Stream) {
  1654. Stream->Release();
  1655. }
  1656. if (AddrBook) {
  1657. AddrBook->Release();
  1658. }
  1659. if (lpAddrList) {
  1660. pFreePadrlist( lpAddrList );
  1661. }
  1662. if (lpEntryID) {
  1663. MapiFreeBuffer( lpEntryID );
  1664. }
  1665. if (lpszProxyAddr) {
  1666. MapiFreeBuffer( lpszProxyAddr );
  1667. }
  1668. if (lpInEntryID) {
  1669. MapiFreeBuffer( lpInEntryID );
  1670. }
  1671. FreeString( MsgSubject );
  1672. FreeString( MsgBody );
  1673. FreeString( MsgAttachmentFileName );
  1674. if (MsgAttachmentTitleW && MsgAttachmentTitle) {
  1675. FreeString( MsgAttachmentTitle );
  1676. }
  1677. CloseHandle( hFile );
  1678. }
  1679. *ResultCode = HResult;
  1680. return HResult == 0;
  1681. }
  1682. PROC
  1683. WINAPI
  1684. MyGetProcAddress(
  1685. HMODULE hModule,
  1686. LPCSTR lpProcName
  1687. )
  1688. {
  1689. FARPROC Proc;
  1690. Proc = GetProcAddress( hModule, lpProcName );
  1691. if (Proc) {
  1692. return Proc;
  1693. } else {
  1694. char *c = strrchr( lpProcName, '@' );
  1695. //
  1696. // remove name decoration
  1697. //
  1698. if (c) {
  1699. char * lpAltProcName = (char *) MemAlloc( strlen( lpProcName ) );
  1700. if (!lpAltProcName) {
  1701. return NULL;
  1702. }
  1703. strncpy( lpAltProcName, lpProcName, (int)(c - lpProcName) );
  1704. Proc = GetProcAddress( hModule, lpAltProcName );
  1705. MemFree( lpAltProcName );
  1706. return Proc;
  1707. } else {
  1708. return NULL;
  1709. }
  1710. }
  1711. }