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.

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