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.

1017 lines
21 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. mapiutil.c
  5. Abstract:
  6. Utility functions for working with MAPI
  7. Environment:
  8. Windows NT fax driver user interface
  9. Revision History:
  10. 09/18/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include "faxui.h"
  16. #define INITGUID
  17. #define USES_IID_IMAPISession
  18. #define USES_IID_IDistList
  19. #include "mapiwrap.h"
  20. //
  21. // Global variables used for accessing MAPI services
  22. //
  23. static HINSTANCE hInstMapi = NULL;
  24. static INT mapiRefCount = 0;
  25. ULONG lhMapiSession = 0;
  26. LPMAPISESSION lpMapiSession = NULL;
  27. LPMAPILOGON lpfnMAPILogon = NULL;
  28. LPMAPILOGOFF lpfnMAPILogoff = NULL;
  29. LPMAPIADDRESS lpfnMAPIAddress = NULL;
  30. LPMAPIFREEBUFFER lpfnMAPIFreeBuffer = NULL;
  31. LPSCMAPIXFROMSMAPI lpfnScMAPIXFromSMAPI = NULL;
  32. //
  33. // Function to insert a recipient into the recipient list view
  34. //
  35. BOOL
  36. InsertRecipientListItem(
  37. HWND hwndLV,
  38. PRECIPIENT pRecipient
  39. );
  40. BOOL
  41. IsMapiAvailable(
  42. VOID
  43. )
  44. /*++
  45. Routine Description:
  46. Determine whether MAPI is available
  47. Arguments:
  48. NONE
  49. Return Value:
  50. TRUE if MAPI is installed on the system, FALSE otherwise
  51. --*/
  52. {
  53. return GetProfileInt(TEXT("MAIL"), TEXT("MAPI"), 0);
  54. }
  55. BOOL
  56. DoMapiLogon(
  57. HWND hDlg
  58. )
  59. /*++
  60. Routine Description:
  61. Logon MAPI to in order to access address book
  62. Arguments:
  63. hDlg - Handle to the send fax wizard window
  64. Return Value:
  65. TRUE if successful, FALSE if there is an error
  66. !!!BUGBUG:
  67. MAPI is not Unicoded enabled on NT.
  68. Must revisit this code once that's fixed.
  69. --*/
  70. #define MAX_PROFILE_NAME 256
  71. {
  72. LPTSTR profileName;
  73. CHAR ansiProfileName[MAX_PROFILE_NAME];
  74. HKEY hRegKey;
  75. ULONG status;
  76. //
  77. // Retrieve the fax profile name stored in registry
  78. //
  79. profileName[0] = NUL;
  80. if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_SETUP, REG_READONLY)) {
  81. profileName = GetRegistryString(hRegKey, REGVAL_FAX_PROFILE, TEXT(""));
  82. RegCloseKey(hRegKey);
  83. if (!profileName || !*profileName) {
  84. return FALSE;
  85. }
  86. } else {
  87. return FALSE;
  88. }
  89. Verbose(("Fax profile name: %ws\n", profileName));
  90. //
  91. // Attempt to logon to MAPI - We need to convert MAPI profile name to ANSI
  92. // here because MAPI is not Unicode enabled.
  93. //
  94. if (! WideCharToMultiByte(CP_ACP,
  95. 0,
  96. profileName,
  97. -1,
  98. ansiProfileName,
  99. MAX_PROFILE_NAME,
  100. NULL,
  101. NULL))
  102. {
  103. Error(("WideCharToMultiByte failed: %d\n", GetLastError()));
  104. MemFree(profileName);
  105. return FALSE;
  106. }
  107. MemFree(profileName);
  108. status = lpfnMAPILogon((ULONG) hDlg,
  109. ansiProfileName,
  110. NULL,
  111. MAPI_LOGON_UI,
  112. 0,
  113. &lhMapiSession);
  114. //
  115. // If a profile name is specified and logon failed,
  116. // then try again without a profile.
  117. //
  118. if (status != SUCCESS_SUCCESS && !IsEmptyString(ansiProfileName)) {
  119. ansiProfileName[0] = NUL;
  120. status = lpfnMAPILogon((ULONG) hDlg,
  121. ansiProfileName,
  122. NULL,
  123. MAPI_LOGON_UI,
  124. 0,
  125. &lhMapiSession);
  126. }
  127. if (status != SUCCESS_SUCCESS) {
  128. Error(("MAPILogon failed: %d\n", status));
  129. return FALSE;
  130. }
  131. //
  132. // Convert simple MAPI session handle to extended MAPI session pointer
  133. //
  134. if (FAILED(lpfnScMAPIXFromSMAPI(lhMapiSession, 0, &IID_IMAPISession, &lpMapiSession))) {
  135. Error(("ScMAPIXFromSMAPI failed: %d\n", GetLastError()));
  136. lpfnMAPILogoff(lhMapiSession, 0, 0, 0);
  137. return FALSE;
  138. }
  139. return TRUE;
  140. }
  141. BOOL
  142. InitMapiService(
  143. HWND hDlg
  144. )
  145. /*++
  146. Routine Description:
  147. Initialize Simple MAPI services if necessary
  148. Arguments:
  149. hDlg - Handle to the send fax wizard window
  150. Return Value:
  151. TRUE if successful, FALSE otherwise
  152. NOTE:
  153. Every successful call to this function must be balanced
  154. by a call to DeinitMapiService.
  155. --*/
  156. {
  157. BOOL result;
  158. EnterDrvSem();
  159. //
  160. // Load MAPI32.DLL into memory if necessary
  161. //
  162. if ((hInstMapi == NULL) &&
  163. (hInstMapi = LoadLibrary(TEXT("MAPI32.DLL"))))
  164. {
  165. //
  166. // Get pointers to various Simple MAPI functions
  167. //
  168. lpfnMAPILogon = (LPMAPILOGON) GetProcAddress(hInstMapi, "MAPILogon");
  169. lpfnMAPILogoff = (LPMAPILOGOFF) GetProcAddress(hInstMapi, "MAPILogoff");
  170. lpfnMAPIAddress = (LPMAPIADDRESS) GetProcAddress(hInstMapi, "MAPIAddress");
  171. lpfnMAPIFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress(hInstMapi, "MAPIFreeBuffer");
  172. lpfnScMAPIXFromSMAPI = (LPSCMAPIXFROMSMAPI) GetProcAddress(hInstMapi, "ScMAPIXFromSMAPI");
  173. //
  174. // Begins a simple MAPI session and obtain session handle and pointer
  175. //
  176. if (lpfnMAPILogon == NULL ||
  177. lpfnMAPILogoff == NULL ||
  178. lpfnMAPIAddress == NULL ||
  179. lpfnMAPIFreeBuffer == NULL ||
  180. lpfnScMAPIXFromSMAPI == NULL ||
  181. !DoMapiLogon(hDlg))
  182. {
  183. //
  184. // Clean up properly in case of error
  185. //
  186. lhMapiSession = 0;
  187. lpMapiSession = NULL;
  188. FreeLibrary(hInstMapi);
  189. hInstMapi = NULL;
  190. }
  191. }
  192. if (result = (hInstMapi != NULL))
  193. mapiRefCount++;
  194. else
  195. Error(("InitMapiService failed: %d", GetLastError()));
  196. LeaveDrvSem();
  197. return result;
  198. }
  199. VOID
  200. DeinitMapiService(
  201. VOID
  202. )
  203. /*++
  204. Routine Description:
  205. Deinitialize Simple MAPI services if necessary
  206. Arguments:
  207. NONE
  208. Return Value:
  209. NONE
  210. --*/
  211. {
  212. EnterDrvSem();
  213. Assert(hInstMapi != NULL);
  214. if (mapiRefCount > 0 && --mapiRefCount == 0 && hInstMapi != NULL) {
  215. if (lpMapiSession)
  216. MAPICALL(lpMapiSession)->Release(lpMapiSession);
  217. if (lhMapiSession)
  218. lpfnMAPILogoff(lhMapiSession, 0, 0, 0);
  219. lhMapiSession = 0;
  220. lpMapiSession = NULL;
  221. FreeLibrary(hInstMapi);
  222. hInstMapi = NULL;
  223. }
  224. LeaveDrvSem();
  225. }
  226. LPSTR
  227. DupStringUnicodeToAnsi(
  228. LPWSTR pUnicodeStr
  229. )
  230. /*++
  231. Routine Description:
  232. Convert a Unicode string to a multi-byte string
  233. Arguments:
  234. pUnicodeStr - Pointer to the Unicode string to be duplicated
  235. Return Value:
  236. Pointer to the duplicated multi-byte string
  237. NOTE:
  238. This is only need because MAPI is not Unicode enabled on NT.
  239. --*/
  240. {
  241. INT nChar;
  242. LPSTR pAnsiStr;
  243. //
  244. // Figure out how much memory to allocate for the multi-byte string
  245. //
  246. if (! (nChar = WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, NULL, 0, NULL, NULL)) ||
  247. ! (pAnsiStr = MemAlloc(nChar)))
  248. {
  249. return NULL;
  250. }
  251. //
  252. // Convert Unicode string to multi-byte string
  253. //
  254. WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, pAnsiStr, nChar, NULL, NULL);
  255. return pAnsiStr;
  256. }
  257. BOOL
  258. CallMapiAddress(
  259. HWND hDlg,
  260. PUSERMEM pUserMem,
  261. PULONG pnRecips,
  262. lpMapiRecipDesc *ppRecips
  263. )
  264. /*++
  265. Routine Description:
  266. Call MAPIAddress to display the address dialog
  267. Arguments:
  268. hDlg - Handle to the send fax wizard window
  269. pUserMem - Points to user mode memory structure
  270. pnRecips - Returns number of selected recipients
  271. ppRecips - Returns information about selected recipients
  272. Return Value:
  273. TRUE if successful, FALSE if there is an error
  274. --*/
  275. {
  276. lpMapiRecipDesc pRecips;
  277. PRECIPIENT pRecipient;
  278. ULONG nRecips, index;
  279. LONG status;
  280. //
  281. // Convert the recipient list to an array of MapiRecipDesc
  282. //
  283. nRecips = 0;
  284. pRecipient = pUserMem->pRecipients;
  285. while (pRecipient) {
  286. nRecips++;
  287. pRecipient = pRecipient->pNext;
  288. }
  289. if (nRecips == 0)
  290. pRecips = NULL;
  291. else if (! (pRecips = MemAllocZ(nRecips * sizeof(MapiRecipDesc))))
  292. return FALSE;
  293. status = SUCCESS_SUCCESS;
  294. index = nRecips;
  295. pRecipient = pUserMem->pRecipients;
  296. Verbose(("Recipients passed to MAPIAddress:\n"));
  297. while (index-- > 0) {
  298. Assert(pRecipient != NULL);
  299. pRecips[index].ulRecipClass = MAPI_TO;
  300. pRecips[index].lpszName = DupStringUnicodeToAnsi(pRecipient->pName);
  301. pRecips[index].lpszAddress = DupStringUnicodeToAnsi(pRecipient->pAddress);
  302. if (!pRecips[index].lpszName || !pRecips[index].lpszAddress) {
  303. status = MAPI_E_INSUFFICIENT_MEMORY;
  304. break;
  305. }
  306. Verbose((" %s, %s\n", pRecips[index].lpszName, pRecips[index].lpszAddress));
  307. pRecipient = pRecipient->pNext;
  308. }
  309. //
  310. // Call MAPI to display the address book dialog
  311. //
  312. if (status == SUCCESS_SUCCESS) {
  313. status = lpfnMAPIAddress(lhMapiSession,
  314. (ULONG) hDlg,
  315. NULL,
  316. 1,
  317. NULL,
  318. nRecips,
  319. pRecips,
  320. MAPI_LOGON_UI,
  321. 0,
  322. pnRecips,
  323. ppRecips);
  324. }
  325. //
  326. // Free the input recipient list after coming back from MAPI
  327. //
  328. for (index=0; index < nRecips; index++) {
  329. MemFree(pRecips[index].lpszName);
  330. MemFree(pRecips[index].lpszAddress);
  331. }
  332. MemFree(pRecips);
  333. if (status != SUCCESS_SUCCESS) {
  334. Error(("MAPIAddress failed: %d\n", status));
  335. return FALSE;
  336. }
  337. return TRUE;
  338. }
  339. INT
  340. InterpretSimpleAddress(
  341. PUSERMEM pUserMem,
  342. HWND hwndLV,
  343. LPSTR pRecipName,
  344. LPSTR pRecipAddress
  345. )
  346. /*++
  347. Routine Description:
  348. Process a simple address entry and insert it into the recipient list view
  349. Arguments:
  350. pUserMem - Points to user mode memory structure
  351. hwndLV - Handle to the recipient list view window
  352. pRecipName - Specifies the name of the recipient
  353. pRecipName - Specifies the recipient's address
  354. Return Value:
  355. -1 : if there is an error
  356. 0 : if the address entry is ignored
  357. 1 : if successful
  358. --*/
  359. {
  360. LPTSTR pName, pAddress;
  361. INT nameLen, addrLen;
  362. PRECIPIENT pRecipient;
  363. //
  364. // Allocate memory to hold recipient information
  365. //
  366. if (pRecipName == NULL) {
  367. Error(("Recipient name is NULL!\n"));
  368. return -1;
  369. }
  370. nameLen = strlen(pRecipName) + 1;
  371. addrLen = strlen(pRecipAddress) + 1;
  372. pRecipient = MemAllocZ(sizeof(RECIPIENT));
  373. pName = MemAllocZ(nameLen * sizeof(TCHAR));
  374. pAddress = MemAllocZ(addrLen * sizeof(TCHAR));
  375. if (!pRecipient || !pName || !pAddress) {
  376. Error(("Memory allocation failed\n"));
  377. MemFree(pRecipient);
  378. MemFree(pName);
  379. MemFree(pAddress);
  380. return -1;
  381. }
  382. pRecipient->pName = pName;
  383. pRecipient->pAddress = pAddress;
  384. //
  385. // Convert name and address from Ansi string to Unicode string
  386. //
  387. MultiByteToWideChar(CP_ACP, 0, pRecipName, -1, pName, nameLen);
  388. MultiByteToWideChar(CP_ACP, 0, pRecipAddress, -1, pAddress, addrLen);
  389. //
  390. // Add this recipient to the recipient list
  391. //
  392. if (InsertRecipientListItem(hwndLV, pRecipient)) {
  393. pRecipient->pNext = pUserMem->pRecipients;
  394. pUserMem->pRecipients = pRecipient;
  395. return 1;
  396. } else {
  397. FreeRecipient(pRecipient);
  398. return -1;
  399. }
  400. }
  401. INT
  402. DetermineAddressType(
  403. LPSTR pAddress
  404. )
  405. /*++
  406. Routine Description:
  407. Determine the type of an address
  408. Arguments:
  409. pAddress - Points to an address or address type string
  410. Return Value:
  411. One of the ADDRTYPE_* constants below
  412. --*/
  413. #define ADDRTYPE_NULL 0
  414. #define ADDRTYPE_FAX 1
  415. #define ADDRTYPE_MAPIPDL 2
  416. #define ADDRTYPE_UNKNOWN 3
  417. #define ADDRTYPESTR_FAX "FAX"
  418. #define ADDRTYPESTR_MAPIPDL "MAPIPDL"
  419. {
  420. INT n;
  421. LPSTR p;
  422. //
  423. // Check if the input string is NULL
  424. //
  425. if (pAddress == NULL)
  426. return ADDRTYPE_NULL;
  427. //
  428. // Check if the address type is FAX
  429. //
  430. p = ADDRTYPESTR_FAX;
  431. n = strlen(p);
  432. if ((_strnicmp(pAddress, p, n) == EQUAL_STRING) &&
  433. (pAddress[n] == NUL || pAddress[n] == ':'))
  434. {
  435. return ADDRTYPE_FAX;
  436. }
  437. //
  438. // Check if the address type is MAPIPDL
  439. //
  440. p = ADDRTYPESTR_MAPIPDL;
  441. n = strlen(p);
  442. if ((_strnicmp(pAddress, p, n) == EQUAL_STRING) &&
  443. (pAddress[n] == NUL || pAddress[n] == ':'))
  444. {
  445. return ADDRTYPE_MAPIPDL;
  446. }
  447. //
  448. // Address type is something that we don't understand
  449. //
  450. return ADDRTYPE_UNKNOWN;
  451. }
  452. LPSTR
  453. ConcatTypeWithAddress(
  454. LPSTR pType,
  455. LPSTR pAddress
  456. )
  457. /*++
  458. Routine Description:
  459. Helper function to concatenate address type in front of the address
  460. Arguments:
  461. pType - Points to address type string
  462. pAddress - Points to address string
  463. Return Value:
  464. Pointer to concatenated address, NULL if there is an error
  465. --*/
  466. {
  467. INT length;
  468. LPSTR p;
  469. //
  470. // Sanity check
  471. //
  472. if (pType == NULL || pAddress == NULL)
  473. return NULL;
  474. //
  475. // Calculate the length of the concatenated string
  476. //
  477. length = strlen(pType) + 1 + strlen(pAddress) + 1;
  478. //
  479. // Concatenate type with address, separated by a colon
  480. //
  481. if (p = MemAllocZ(length))
  482. sprintf(p, "%s:%s", pType, pAddress);
  483. return p;
  484. }
  485. INT
  486. InterpretDistList(
  487. PUSERMEM pUserMem,
  488. HWND hwndLV,
  489. ULONG ulEIDSize,
  490. PVOID pEntryID
  491. )
  492. /*++
  493. Routine Description:
  494. Expand a distribution list entry and insert the individual
  495. addresses into the recipient list view.
  496. Arguments:
  497. pUserMem - Points to user mode memory structure
  498. hwndLV - Handle to the recipient list view window
  499. ulEIDSize - Specifies the size of entry ID
  500. pEntryID - Points to entry ID data
  501. Return Value:
  502. > 0 : total number of useful address entries
  503. = 0 : no useful address entry found
  504. < 0 : if there is an error
  505. --*/
  506. #define EXIT_IF_FAILED(hr) { if (FAILED(hr)) goto ExitDistList; }
  507. {
  508. LPDISTLIST pDistList = NULL;
  509. LPMAPITABLE pMapiTable = NULL;
  510. LPSRowSet pRows = NULL;
  511. ULONG ulObjType, cRows;
  512. HRESULT hr;
  513. INT entriesUsed = 0;
  514. static SizedSPropTagArray(4, sPropTags) =
  515. {
  516. 4,
  517. {
  518. PR_ENTRYID,
  519. PR_ADDRTYPE_A,
  520. PR_DISPLAY_NAME_A,
  521. PR_EMAIL_ADDRESS_A
  522. }
  523. };
  524. //
  525. // Deal with distribution lists
  526. //
  527. if (ulEIDSize == 0 || pEntryID == NULL) {
  528. Error(("Unusable address entry\n"));
  529. return FALSE;
  530. }
  531. //
  532. // Open the recipient entry
  533. //
  534. hr = MAPICALL(lpMapiSession)->OpenEntry(lpMapiSession,
  535. ulEIDSize,
  536. pEntryID,
  537. &IID_IDistList,
  538. MAPI_DEFERRED_ERRORS,
  539. &ulObjType,
  540. (LPUNKNOWN *) &pDistList);
  541. EXIT_IF_FAILED(hr);
  542. //
  543. // Get the contents table of the address entry
  544. //
  545. hr = MAPICALL(pDistList)->GetContentsTable(pDistList,
  546. MAPI_DEFERRED_ERRORS,
  547. &pMapiTable);
  548. EXIT_IF_FAILED(hr);
  549. //
  550. // Limit the query to only the properties we're interested in
  551. //
  552. hr = MAPICALL(pMapiTable)->SetColumns(pMapiTable, (LPSPropTagArray) &sPropTags, 0);
  553. EXIT_IF_FAILED(hr);
  554. //
  555. // Get the total number of rows
  556. //
  557. hr = MAPICALL(pMapiTable)->GetRowCount(pMapiTable, 0, &cRows);
  558. EXIT_IF_FAILED(hr);
  559. //
  560. // Get the individual entries of the distribution list
  561. //
  562. hr = MAPICALL(pMapiTable)->SeekRow(pMapiTable, BOOKMARK_BEGINNING, 0, NULL);
  563. EXIT_IF_FAILED(hr);
  564. hr = MAPICALL(pMapiTable)->QueryRows(pMapiTable, cRows, 0, &pRows);
  565. EXIT_IF_FAILED(hr);
  566. hr = S_OK;
  567. entriesUsed = 0;
  568. if (pRows && pRows->cRows) {
  569. //
  570. // Handle each entry of the distribution list in turn:
  571. // for simple entries, call InterpretSimpleAddress
  572. // for embedded distribution list, call this function recursively
  573. //
  574. for (cRows = 0; cRows < pRows->cRows; cRows++) {
  575. LPSPropValue lpProps = pRows->aRow[cRows].lpProps;
  576. LPSTR pType, pName, pAddress;
  577. INT result;
  578. pType = lpProps[1].Value.lpszA;
  579. pName = lpProps[2].Value.lpszA;
  580. pAddress = lpProps[3].Value.lpszA;
  581. Verbose((" %s: %s", pType, pName));
  582. switch (DetermineAddressType(pType)) {
  583. case ADDRTYPE_FAX:
  584. if ((pAddress != NULL) &&
  585. (lpProps[3].ulPropTag == PR_EMAIL_ADDRESS_A) &&
  586. (pAddress = ConcatTypeWithAddress(pType, pAddress)))
  587. {
  588. Verbose((", %s\n", pAddress));
  589. result = InterpretSimpleAddress(pUserMem, hwndLV, pName, pAddress);
  590. MemFree(pAddress);
  591. } else {
  592. Verbose(("\nBad address.\n"));
  593. result = -1;
  594. }
  595. break;
  596. case ADDRTYPE_MAPIPDL:
  597. case ADDRTYPE_NULL:
  598. Verbose(("\n"));
  599. result = InterpretDistList(pUserMem,
  600. hwndLV,
  601. lpProps[0].Value.bin.cb,
  602. lpProps[0].Value.bin.lpb);
  603. break;
  604. default:
  605. Verbose(("\nUnknown address type.\n"));
  606. result = 0;
  607. break;
  608. }
  609. if (result < 0)
  610. hr = -1;
  611. else
  612. entriesUsed += result;
  613. }
  614. }
  615. ExitDistList:
  616. //
  617. // Perform necessary clean up before returning to caller
  618. //
  619. if (pRows) {
  620. for (cRows = 0; cRows < pRows->cRows; cRows++)
  621. lpfnMAPIFreeBuffer(pRows->aRow[cRows].lpProps);
  622. lpfnMAPIFreeBuffer(pRows);
  623. }
  624. if (pMapiTable)
  625. MAPICALL(pMapiTable)->Release(pMapiTable);
  626. if (pDistList)
  627. MAPICALL(pDistList)->Release(pDistList);
  628. if (FAILED(hr)) {
  629. Error(("InterpretDistList failed: 0x%x\n", hr));
  630. return -1;
  631. } else
  632. return entriesUsed;
  633. }
  634. BOOL
  635. InterpretSelectedAddresses(
  636. HWND hDlg,
  637. PUSERMEM pUserMem,
  638. HWND hwndLV,
  639. ULONG nRecips,
  640. lpMapiRecipDesc pRecips
  641. )
  642. /*++
  643. Routine Description:
  644. Expand the selected addresses and insert them into the recipient list view
  645. Arguments:
  646. hDlg - Handle to the send fax wizard window
  647. pUserMem - Points to user mode memory structure
  648. hwndLV - Handle to the recipient list view window
  649. nRecips - Number of selected recipients
  650. pRecips - Information about selected recipients
  651. Return Value:
  652. TRUE if successful, FALSE if there is an error
  653. --*/
  654. {
  655. INT discarded = 0;
  656. //
  657. // Remove all existing entries in the recipient list view
  658. //
  659. if (! ListView_DeleteAllItems(hwndLV))
  660. return FALSE;
  661. FreeRecipientList(pUserMem);
  662. Verbose(("Recipients returned from MAPIAddress:\n"));
  663. for ( ; nRecips--; pRecips++) {
  664. INT result;
  665. Verbose((" %s, %s\n", pRecips->lpszName, pRecips->lpszAddress));
  666. switch (DetermineAddressType(pRecips->lpszAddress)) {
  667. case ADDRTYPE_FAX:
  668. result = InterpretSimpleAddress(pUserMem,
  669. hwndLV,
  670. pRecips->lpszName,
  671. pRecips->lpszAddress);
  672. break;
  673. case ADDRTYPE_MAPIPDL:
  674. case ADDRTYPE_NULL:
  675. result = InterpretDistList(pUserMem,
  676. hwndLV,
  677. pRecips->ulEIDSize,
  678. pRecips->lpEntryID);
  679. break;
  680. default:
  681. Verbose(("Unknown address type.\n"));
  682. result = 0;
  683. break;
  684. }
  685. if (result <= 0)
  686. discarded++;
  687. }
  688. if (discarded)
  689. DisplayMessageDialog(hDlg, 0, 0, IDS_BAD_ADDRESS_TYPE);
  690. return TRUE;
  691. }