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

2094 lines
52 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. abobj.cpp
  5. Abstract:
  6. Interface to the common address book.
  7. Environment:
  8. Fax send wizard
  9. Revision History:
  10. 09/02/99 -v-sashab-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include <windows.h>
  16. #include <prsht.h>
  17. #include <tchar.h>
  18. #include <assert.h>
  19. #include <mbstring.h>
  20. #include <mapix.h>
  21. #include "faxui.h"
  22. #include "abobj.h"
  23. #define PR_EMS_AB_PROXY_ADDRESSES PROP_TAG( PT_MV_TSTRING, 0x800F)
  24. #define PR_EMS_AB_PROXY_ADDRESSES_A PROP_TAG( PT_MV_STRING8, 0x800F)
  25. #define PR_EMS_AB_PROXY_ADDRESSES_W PROP_TAG( PT_MV_UNICODE, 0x800F)
  26. static SizedSPropTagArray(10, sPropTagsW) =
  27. {
  28. 10,
  29. {
  30. PR_ADDRTYPE_W,
  31. PR_EMAIL_ADDRESS_W,
  32. PR_DISPLAY_NAME_W,
  33. PR_PRIMARY_FAX_NUMBER_W,
  34. PR_HOME_FAX_NUMBER_W,
  35. PR_BUSINESS_FAX_NUMBER_W,
  36. PR_COUNTRY_W,
  37. PR_OBJECT_TYPE,
  38. PR_EMS_AB_PROXY_ADDRESSES_W,
  39. PR_ENTRYID
  40. }
  41. };
  42. static SizedSPropTagArray(10, sPropTagsA) =
  43. {
  44. 10,
  45. {
  46. PR_ADDRTYPE_A,
  47. PR_EMAIL_ADDRESS_A,
  48. PR_DISPLAY_NAME_A,
  49. PR_PRIMARY_FAX_NUMBER_A,
  50. PR_HOME_FAX_NUMBER_A,
  51. PR_BUSINESS_FAX_NUMBER_A,
  52. PR_COUNTRY_A,
  53. PR_OBJECT_TYPE,
  54. PR_EMS_AB_PROXY_ADDRESSES_A,
  55. PR_ENTRYID
  56. }
  57. };
  58. HINSTANCE CCommonAbObj::m_hInstance = NULL;
  59. /*
  60. Comparison operator 'less'
  61. Compare two PRECIPIENT by recipient's name and fax number
  62. */
  63. bool
  64. CRecipCmp::operator()(
  65. const PRECIPIENT pcRecipient1,
  66. const PRECIPIENT pcRecipient2) const
  67. {
  68. bool bRes = false;
  69. int nFaxNumberCpm = 0;
  70. if(!pcRecipient1 ||
  71. !pcRecipient2 ||
  72. !pcRecipient1->pAddress ||
  73. !pcRecipient2->pAddress)
  74. {
  75. assert(false);
  76. return bRes;
  77. }
  78. nFaxNumberCpm = _tcscmp(pcRecipient1->pAddress, pcRecipient2->pAddress);
  79. if(nFaxNumberCpm < 0)
  80. {
  81. bRes = true;
  82. }
  83. else if(nFaxNumberCpm == 0)
  84. {
  85. //
  86. // The fax numbers are same
  87. // lets compare the names
  88. //
  89. if(pcRecipient1->pName && pcRecipient2->pName)
  90. {
  91. bRes = (_tcsicmp(pcRecipient1->pName, pcRecipient2->pName) < 0);
  92. }
  93. else
  94. {
  95. bRes = (pcRecipient1->pName < pcRecipient2->pName);
  96. }
  97. }
  98. return bRes;
  99. } // CRecipCmp::operator()
  100. CCommonAbObj::CCommonAbObj(HINSTANCE hInstance) :
  101. m_lpAdrBook(NULL),
  102. m_lpMailUser(NULL),
  103. m_bUnicode(FALSE)
  104. /*++
  105. Routine Description:
  106. Constructor for CCommonAbObj class
  107. Arguments:
  108. hInstance - Instance handle
  109. Return Value:
  110. NONE
  111. --*/
  112. {
  113. m_hInstance = hInstance;
  114. } // CCommonAbObj::CCommonAbObj()
  115. CCommonAbObj::~CCommonAbObj()
  116. /*++
  117. Routine Description:
  118. Destructor for CCommonAbObj class
  119. Arguments:
  120. NONE
  121. Return Value:
  122. NONE
  123. --*/
  124. {
  125. }
  126. BOOL
  127. CCommonAbObj::Address(
  128. HWND hWnd,
  129. PRECIPIENT pOldRecipList,
  130. PRECIPIENT* ppNewRecipList
  131. )
  132. /*++
  133. Routine Description:
  134. Bring up the address book UI. Prepopulate the to box with the entries in
  135. pRecipient. Return the modified entries in ppNewRecip.
  136. Arguments:
  137. hWnd - window handle to parent window
  138. pOldRecipList - list of recipients to look up
  139. ppNewRecipList - list of new/modified recipients
  140. Return Value:
  141. TRUE if all recipients had a fax number.
  142. FALSE if one or more of them didn't.
  143. --*/
  144. {
  145. ADRPARM AdrParms = { 0 };
  146. HRESULT hr;
  147. DWORD i;
  148. DWORD nRecips;
  149. PRECIPIENT tmpRecipient;
  150. ULONG DestComps[1] = { MAPI_TO };
  151. DWORD cDropped = 0;
  152. DWORD dwRes = ERROR_SUCCESS;
  153. TCHAR tszCaption[MAX_PATH] = {0};
  154. nRecips = 0;
  155. tmpRecipient = pOldRecipList;
  156. m_hWnd = hWnd;
  157. //
  158. // count recipients and set up initial address list
  159. //
  160. while (tmpRecipient)
  161. {
  162. nRecips++;
  163. tmpRecipient = (PRECIPIENT) tmpRecipient->pNext;
  164. }
  165. //
  166. // Allocate address list
  167. //
  168. m_lpAdrList = NULL;
  169. if (nRecips > 0)
  170. {
  171. hr = ABAllocateBuffer( CbNewADRLIST( nRecips ), (LPVOID *) &m_lpAdrList );
  172. if(!m_lpAdrList)
  173. {
  174. goto exit;
  175. }
  176. ZeroMemory(m_lpAdrList, CbNewADRLIST( nRecips ));
  177. m_lpAdrList->cEntries = nRecips;
  178. }
  179. //
  180. // Allocate SPropValue arrays for each address entry
  181. //
  182. for (i = 0, tmpRecipient = pOldRecipList; i < nRecips; i++, tmpRecipient = tmpRecipient->pNext)
  183. {
  184. if(!GetRecipientProps(tmpRecipient,
  185. &(m_lpAdrList->aEntries[i].rgPropVals),
  186. &(m_lpAdrList->aEntries[i].cValues)))
  187. {
  188. goto error;
  189. }
  190. } // for
  191. if(GetAddrBookCaption(tszCaption, ARR_SIZE(tszCaption)))
  192. {
  193. AdrParms.lpszCaption = tszCaption;
  194. }
  195. AdrParms.cDestFields = 1;
  196. AdrParms.ulFlags = StrCoding() | DIALOG_MODAL | AB_RESOLVE;
  197. AdrParms.nDestFieldFocus = 0;
  198. AdrParms.lpulDestComps = DestComps;
  199. //
  200. // Bring up the address book UI
  201. //
  202. hr = m_lpAdrBook->Address((ULONG_PTR*)&hWnd,
  203. &AdrParms,
  204. &m_lpAdrList);
  205. //
  206. // IAddrBook::Address returns always S_OK (according to MSDN, July 1999), but ...
  207. //
  208. if (FAILED (hr) || !m_lpAdrList || m_lpAdrList->cEntries == 0)
  209. {
  210. //
  211. // in this case the user pressed cancel, so we skip resolving
  212. // any of our addresses that aren't listed in the AB
  213. //
  214. goto exit;
  215. }
  216. exit:
  217. if (m_lpAdrList)
  218. {
  219. m_lpMailUser = NULL;
  220. try
  221. {
  222. m_setRecipients.clear();
  223. }
  224. catch (std::bad_alloc&)
  225. {
  226. goto error;
  227. }
  228. for (i = cDropped = 0; i < m_lpAdrList->cEntries; i++)
  229. {
  230. LPADRENTRY lpAdrEntry = &m_lpAdrList->aEntries[i];
  231. dwRes = InterpretAddress(lpAdrEntry->rgPropVals,
  232. lpAdrEntry->cValues,
  233. ppNewRecipList,
  234. pOldRecipList);
  235. if(ERROR_SUCCESS == dwRes)
  236. {
  237. continue;
  238. }
  239. else if(ERROR_INVALID_DATA == dwRes)
  240. {
  241. ++cDropped;
  242. }
  243. else
  244. {
  245. break;
  246. }
  247. } // for
  248. error:
  249. if(m_lpMailUser)
  250. {
  251. m_lpMailUser->Release();
  252. m_lpMailUser = NULL;
  253. }
  254. //
  255. // Clean up
  256. //
  257. for (ULONG iEntry = 0; iEntry < m_lpAdrList->cEntries; ++iEntry)
  258. {
  259. if(m_lpAdrList->aEntries[iEntry].rgPropVals)
  260. {
  261. ABFreeBuffer(m_lpAdrList->aEntries[iEntry].rgPropVals);
  262. }
  263. }
  264. ABFreeBuffer(m_lpAdrList);
  265. m_lpAdrList = NULL;
  266. } // if (m_lpAdrList)
  267. m_hWnd = NULL;
  268. return cDropped == 0;
  269. } // CCommonAbObj::Address
  270. BOOL
  271. CCommonAbObj::GetRecipientProps(
  272. PRECIPIENT pRecipient,
  273. LPSPropValue* pMapiProps,
  274. DWORD* pdwPropsNum
  275. )
  276. /*++
  277. Routine Description:
  278. Allocate SPropValue array and fill it with recipient info
  279. According to MSDN "Managing Memory for ADRLIST and SRowSet Structures"
  280. Arguments:
  281. pRecipient - [in] recipient info struct
  282. pMapiProps - [out] allocated SPropValue array
  283. pdwPropsNum - [out] SPropValue array size
  284. Return Value:
  285. TRUE if success
  286. FALSE otherwize
  287. --*/
  288. {
  289. BOOL bRes = FALSE;
  290. if(!pRecipient || !pMapiProps || !pdwPropsNum)
  291. {
  292. return FALSE;
  293. }
  294. HRESULT hr;
  295. LPTSTR pName = NULL;
  296. DWORD dwNameSize=0; // size of pName
  297. LPTSTR pAddress = NULL;
  298. DWORD dwAddressSize=0; // size of pAddress
  299. LPENTRYID lpEntryId = NULL;
  300. ULONG cbEntryId = 0; // size of lpEntryId
  301. UINT ucPropertiesNum = pRecipient->bFromAddressBook ? 5 : 4;
  302. enum FaxMapiProp { FXS_DISPLAY_NAME,
  303. FXS_RECIPIENT_TYPE,
  304. FXS_PRIMARY_FAX_NUMBER,
  305. FXS_ENTRYID,
  306. FXS_OBJECT_TYPE
  307. };
  308. //
  309. // Convert strings to the address book encoding
  310. //
  311. if(pRecipient->pAddress)
  312. {
  313. pAddress = StrToAddrBk(pRecipient->pAddress, &dwAddressSize);
  314. if(!pAddress)
  315. {
  316. goto exit;
  317. }
  318. }
  319. if(pRecipient->pName)
  320. {
  321. pName = StrToAddrBk(pRecipient->pName, &dwNameSize);
  322. if(!pName)
  323. {
  324. goto exit;
  325. }
  326. }
  327. //
  328. // Get entry ID
  329. //
  330. if (pRecipient->bFromAddressBook)
  331. {
  332. assert(pRecipient->lpEntryId);
  333. lpEntryId = (LPENTRYID)pRecipient->lpEntryId;
  334. cbEntryId = pRecipient->cbEntryId;
  335. }
  336. else
  337. {
  338. LPTSTR pAddrType = NULL;
  339. if(!(pAddrType = StrToAddrBk(TEXT("FAX"))))
  340. {
  341. goto exit;
  342. }
  343. hr = m_lpAdrBook->CreateOneOff(pName,
  344. pAddrType,
  345. pAddress,
  346. StrCoding(),
  347. &cbEntryId,
  348. &lpEntryId);
  349. if (FAILED(hr))
  350. {
  351. goto exit;
  352. }
  353. MemFree(pAddrType);
  354. }
  355. //
  356. // Allocate MAPI prop array
  357. //
  358. LPSPropValue mapiProps = NULL;
  359. DWORD dwPropArrSize = sizeof( SPropValue ) * ucPropertiesNum;
  360. DWORD dwPropSize = dwPropArrSize + dwAddressSize + dwNameSize + cbEntryId;
  361. hr = ABAllocateBuffer( dwPropSize, (LPVOID *) &mapiProps );
  362. if(!mapiProps)
  363. {
  364. goto exit;
  365. }
  366. ZeroMemory(mapiProps, dwPropSize);
  367. //
  368. // Set memory pointer to the end of the SPropValue prop array
  369. //
  370. LPBYTE pMem = (LPBYTE)mapiProps;
  371. pMem += dwPropArrSize;
  372. //
  373. // Copy fax number
  374. //
  375. if(dwAddressSize)
  376. {
  377. CopyMemory(pMem, pAddress, dwAddressSize);
  378. if(m_bUnicode)
  379. {
  380. mapiProps[FXS_PRIMARY_FAX_NUMBER].Value.lpszW = (LPWSTR)pMem;
  381. }
  382. else
  383. {
  384. mapiProps[FXS_PRIMARY_FAX_NUMBER].Value.lpszA = (LPSTR)pMem;
  385. }
  386. pMem += dwAddressSize;
  387. }
  388. mapiProps[FXS_PRIMARY_FAX_NUMBER].ulPropTag = m_bUnicode ? PR_PRIMARY_FAX_NUMBER_W : PR_PRIMARY_FAX_NUMBER_A;
  389. //
  390. // Copy display name
  391. //
  392. if(dwNameSize)
  393. {
  394. CopyMemory(pMem, pName, dwNameSize);
  395. if(m_bUnicode)
  396. {
  397. mapiProps[FXS_DISPLAY_NAME].Value.lpszW = (LPWSTR)pMem;
  398. }
  399. else
  400. {
  401. mapiProps[FXS_DISPLAY_NAME].Value.lpszA = (LPSTR)pMem;
  402. }
  403. pMem += dwNameSize;
  404. }
  405. mapiProps[FXS_DISPLAY_NAME].ulPropTag = m_bUnicode ? PR_DISPLAY_NAME_W : PR_DISPLAY_NAME_A;
  406. //
  407. // Copy entry ID
  408. //
  409. if(cbEntryId)
  410. {
  411. CopyMemory(pMem, lpEntryId, cbEntryId);
  412. mapiProps[FXS_ENTRYID].Value.bin.lpb = (LPBYTE)pMem;
  413. }
  414. mapiProps[FXS_ENTRYID].ulPropTag = PR_ENTRYID;
  415. mapiProps[FXS_ENTRYID].Value.bin.cb = cbEntryId;
  416. //
  417. // Recipient type
  418. //
  419. mapiProps[FXS_RECIPIENT_TYPE].ulPropTag = PR_RECIPIENT_TYPE;
  420. mapiProps[FXS_RECIPIENT_TYPE].Value.l = MAPI_TO;
  421. //
  422. // Object type
  423. //
  424. if (pRecipient->bFromAddressBook)
  425. {
  426. mapiProps[FXS_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  427. mapiProps[FXS_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
  428. }
  429. *pdwPropsNum = ucPropertiesNum;
  430. *pMapiProps = mapiProps;
  431. bRes = TRUE;
  432. exit:
  433. MemFree(pName);
  434. MemFree(pAddress);
  435. if (!pRecipient->bFromAddressBook && lpEntryId)
  436. {
  437. ABFreeBuffer(lpEntryId);
  438. }
  439. return bRes;
  440. } // CCommonAbObj::GetRecipientProps
  441. LPTSTR
  442. CCommonAbObj::AddressEmail(
  443. HWND hWnd
  444. )
  445. /*++
  446. Routine Description:
  447. Bring up the address book UI. Returns an E-mail address.
  448. Arguments:
  449. hWnd - window handle to parent window
  450. Return Value:
  451. A choosen E-mail address.
  452. NULL otherwise.
  453. --*/
  454. {
  455. ADRPARM AdrParms = { 0 };
  456. HRESULT hr;
  457. LPTSTR lptstrEmailAddress = NULL;
  458. TCHAR tszCaption[MAX_PATH] = {0};
  459. m_hWnd = hWnd;
  460. m_lpAdrList = NULL;
  461. AdrParms.ulFlags = StrCoding() | DIALOG_MODAL | ADDRESS_ONE | AB_RESOLVE ;
  462. if(GetAddrBookCaption(tszCaption, ARR_SIZE(tszCaption)))
  463. {
  464. AdrParms.lpszCaption = tszCaption;
  465. }
  466. //
  467. // Bring up the address book UI
  468. //
  469. hr = m_lpAdrBook->Address((ULONG_PTR *) &hWnd, &AdrParms, &m_lpAdrList);
  470. //
  471. // IAddrBook::Address returns always S_OK (according to MSDN, July 1999), but ...
  472. //
  473. if (FAILED(hr))
  474. {
  475. return NULL;
  476. }
  477. if (!m_lpAdrList)
  478. {
  479. assert(m_lpAdrList->cEntries==1);
  480. }
  481. if (m_lpAdrList && (m_lpAdrList->cEntries != 0) )
  482. {
  483. LPADRENTRY lpAdrEntry = &m_lpAdrList->aEntries[0];
  484. lptstrEmailAddress = InterpretEmailAddress( lpAdrEntry->rgPropVals, lpAdrEntry->cValues);
  485. ABFreeBuffer(m_lpAdrList->aEntries[0].rgPropVals);
  486. ABFreeBuffer(m_lpAdrList);
  487. m_lpAdrList = NULL;
  488. }
  489. m_hWnd = NULL;
  490. return lptstrEmailAddress;
  491. } // CCommonAbObj::AddressEmail
  492. DWORD
  493. CCommonAbObj::InterpretAddress(
  494. LPSPropValue SPropVal,
  495. ULONG cValues,
  496. PRECIPIENT *ppNewRecipList,
  497. PRECIPIENT pOldRecipList
  498. )
  499. /*++
  500. Routine Description:
  501. Interpret the address book entry represented by SPropVal.
  502. Arguments:
  503. SPropVal - Property values for address book entry.
  504. cValues - number of property values
  505. ppNewRecip - new recipient list
  506. Return Value:
  507. ERROR_SUCCESS - if all of the entries have a fax number.
  508. ERROR_CANCELLED - the operation was canceled by user
  509. ERROR_INVALID_DATA - otherwise.
  510. --*/
  511. {
  512. DWORD dwRes = ERROR_INVALID_DATA;
  513. LPSPropValue lpSPropVal;
  514. RECIPIENT NewRecipient = {0};
  515. //
  516. // get the object type
  517. //
  518. lpSPropVal = FindProp( SPropVal, cValues, PR_OBJECT_TYPE );
  519. if (lpSPropVal)
  520. {
  521. //
  522. // If the object is a mail user, get the fax numbers and add the recipient
  523. // to the list. If the object is a distribtion list, process it.
  524. //
  525. switch (lpSPropVal->Value.l)
  526. {
  527. case MAPI_MAILUSER:
  528. dwRes = GetRecipientInfo(SPropVal,
  529. cValues,
  530. &NewRecipient,
  531. pOldRecipList);
  532. if(ERROR_SUCCESS == dwRes)
  533. {
  534. dwRes = AddRecipient(ppNewRecipList,
  535. &NewRecipient,
  536. TRUE);
  537. }
  538. break;
  539. case MAPI_DISTLIST:
  540. dwRes = InterpretDistList( SPropVal,
  541. cValues,
  542. ppNewRecipList,
  543. pOldRecipList);
  544. }
  545. return dwRes;
  546. }
  547. else
  548. {
  549. //
  550. // If there is no object type then this is valid entry that we queried on that went unresolved.
  551. // We know that there is a fax number so add it.
  552. //
  553. if(GetOneOffRecipientInfo( SPropVal,
  554. cValues,
  555. &NewRecipient,
  556. pOldRecipList))
  557. {
  558. dwRes = AddRecipient(ppNewRecipList,
  559. &NewRecipient,
  560. FALSE);
  561. }
  562. }
  563. return dwRes;
  564. } // CCommonAbObj::InterpretAddress
  565. LPTSTR
  566. CCommonAbObj::InterpretEmailAddress(
  567. LPSPropValue SPropVal,
  568. ULONG cValues
  569. )
  570. /*++
  571. Routine Description:
  572. Interpret the address book entry represented by SPropVal.
  573. Arguments:
  574. SPropVal - Property values for address book entry.
  575. cValues - number of property values
  576. Return Value:
  577. A choosen E-mail address
  578. NULL otherwise.
  579. --*/
  580. {
  581. LPSPropValue lpSPropVal;
  582. LPTSTR lptstrEmailAddress = NULL;
  583. BOOL rVal = FALSE;
  584. TCHAR tszBuffer[MAX_STRING_LEN];
  585. //
  586. // get the object type
  587. //
  588. lpSPropVal = FindProp( SPropVal, cValues, PR_OBJECT_TYPE );
  589. if(!lpSPropVal)
  590. {
  591. assert(FALSE);
  592. return NULL;
  593. }
  594. if (lpSPropVal->Value.l == MAPI_MAILUSER)
  595. {
  596. lptstrEmailAddress = GetEmail( SPropVal, cValues);
  597. return lptstrEmailAddress;
  598. }
  599. else
  600. {
  601. if (!::LoadString((HINSTANCE )m_hInstance, IDS_ERROR_RECEIPT_DL,tszBuffer, MAX_STRING_LEN))
  602. {
  603. assert(FALSE);
  604. }
  605. else
  606. {
  607. AlignedMessageBox( m_hWnd, tszBuffer, NULL, MB_ICONSTOP | MB_OK);
  608. }
  609. }
  610. return lptstrEmailAddress;
  611. } // CCommonAbObj::InterpretEmailAddress
  612. DWORD
  613. CCommonAbObj::InterpretDistList(
  614. LPSPropValue SPropVal,
  615. ULONG cValues,
  616. PRECIPIENT* ppNewRecipList,
  617. PRECIPIENT pOldRecipList
  618. )
  619. /*++
  620. Routine Description:
  621. Process a distribution list.
  622. Arguments:
  623. SPropVal - Property values for distribution list.
  624. cValues - Number of properties.
  625. ppNewRecipList - New recipient list.
  626. pOldRecipList - Old recipient list.
  627. Return Value:
  628. ERROR_SUCCESS - if all of the entries have a fax number.
  629. ERROR_CANCELLED - the operation was canceled by user
  630. ERROR_INVALID_DATA - otherwise.
  631. --*/
  632. #define EXIT_IF_FAILED(hr) { if (FAILED(hr)) goto ExitDistList; }
  633. {
  634. LPSPropValue lpPropVals;
  635. LPSRowSet pRows = NULL;
  636. LPDISTLIST lpMailDistList = NULL;
  637. LPMAPITABLE pMapiTable = NULL;
  638. ULONG ulObjType, cRows;
  639. HRESULT hr;
  640. DWORD dwEntriesSuccessfullyProcessed = 0;
  641. DWORD dwRes = ERROR_INVALID_DATA;
  642. lpPropVals = FindProp( SPropVal, cValues, PR_ENTRYID );
  643. if (lpPropVals)
  644. {
  645. LPENTRYID lpEntryId = (LPENTRYID) lpPropVals->Value.bin.lpb;
  646. DWORD cbEntryId = lpPropVals->Value.bin.cb;
  647. //
  648. // Open the recipient entry
  649. //
  650. hr = m_lpAdrBook->OpenEntry(
  651. cbEntryId,
  652. lpEntryId,
  653. (LPCIID) NULL,
  654. 0,
  655. &ulObjType,
  656. (LPUNKNOWN *) &lpMailDistList
  657. );
  658. EXIT_IF_FAILED(hr);
  659. //
  660. // Get the contents table of the address entry
  661. //
  662. hr = lpMailDistList->GetContentsTable(StrCoding(),
  663. &pMapiTable);
  664. EXIT_IF_FAILED(hr);
  665. //
  666. // Limit the query to only the properties we're interested in
  667. //
  668. hr = pMapiTable->SetColumns(m_bUnicode ? (LPSPropTagArray)&sPropTagsW : (LPSPropTagArray)&sPropTagsA, 0);
  669. EXIT_IF_FAILED(hr);
  670. //
  671. // Get the total number of rows
  672. //
  673. hr = pMapiTable->GetRowCount(0, &cRows);
  674. EXIT_IF_FAILED(hr);
  675. //
  676. // Get the individual entries of the distribution list
  677. //
  678. hr = pMapiTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
  679. EXIT_IF_FAILED(hr);
  680. hr = pMapiTable->QueryRows(cRows, 0, &pRows);
  681. EXIT_IF_FAILED(hr);
  682. hr = S_OK;
  683. if (pRows && pRows->cRows)
  684. {
  685. //
  686. // Handle each entry of the distribution list in turn:
  687. // for simple entries, call InterpretAddress
  688. // for embedded distribution list, call this function recursively
  689. //
  690. for (cRows = 0; cRows < pRows->cRows; cRows++)
  691. {
  692. LPSPropValue lpProps = pRows->aRow[cRows].lpProps;
  693. ULONG cRowValues = pRows->aRow[cRows].cValues;
  694. lpPropVals = FindProp( lpProps, cRowValues, PR_OBJECT_TYPE );
  695. if (lpPropVals)
  696. {
  697. switch (lpPropVals->Value.l)
  698. {
  699. case MAPI_MAILUSER:
  700. {
  701. dwRes = InterpretAddress( lpProps,
  702. cRowValues,
  703. ppNewRecipList,
  704. pOldRecipList);
  705. if (ERROR_SUCCESS == dwRes)
  706. {
  707. dwEntriesSuccessfullyProcessed++;
  708. }
  709. break;
  710. }
  711. case MAPI_DISTLIST:
  712. {
  713. dwRes = InterpretDistList( lpProps,
  714. cRowValues,
  715. ppNewRecipList,
  716. pOldRecipList);
  717. if (ERROR_SUCCESS == dwRes)
  718. {
  719. dwEntriesSuccessfullyProcessed++;
  720. }
  721. break;
  722. }
  723. } // End of switch
  724. } // End of property
  725. } // End of properties loop
  726. } // End of row
  727. } // End of values
  728. ExitDistList:
  729. //
  730. // Perform necessary clean up before returning to caller
  731. //
  732. if (pRows)
  733. {
  734. for (cRows = 0; cRows < pRows->cRows; cRows++)
  735. {
  736. ABFreeBuffer(pRows->aRow[cRows].lpProps);
  737. }
  738. ABFreeBuffer(pRows);
  739. }
  740. if (pMapiTable)
  741. {
  742. pMapiTable->Release();
  743. }
  744. if (lpMailDistList)
  745. {
  746. lpMailDistList->Release();
  747. }
  748. //
  749. // We only care if we successfully processed at least one object.
  750. // Return ERROR_SUCCESS if we did.
  751. //
  752. return dwEntriesSuccessfullyProcessed ? ERROR_SUCCESS : dwRes;
  753. } // CCommonAbObj::InterpretDistList
  754. INT_PTR
  755. CALLBACK
  756. ChooseFaxNumberDlgProc(
  757. HWND hDlg,
  758. UINT uMsg,
  759. WPARAM wParam,
  760. LPARAM lParam
  761. )
  762. /*++
  763. Routine Description:
  764. Dialog proc for choose fax number dialog.
  765. Arguments:
  766. lParam - pointer to PickFax structure.
  767. Return Value:
  768. Control id of selection.
  769. --*/
  770. {
  771. PPICKFAX pPickFax = (PPICKFAX) lParam;
  772. switch (uMsg)
  773. {
  774. case WM_INITDIALOG:
  775. {
  776. TCHAR szTitle[MAX_PATH] = {0};
  777. TCHAR szFormat[MAX_PATH] = {0};
  778. if(LoadString(CCommonAbObj::m_hInstance,
  779. IDS_CHOOSE_FAX_NUMBER,
  780. szFormat,
  781. MAX_PATH-1))
  782. {
  783. _sntprintf(szTitle, MAX_PATH-1, szFormat, pPickFax->DisplayName);
  784. SetDlgItemText(hDlg, IDC_DISPLAY_NAME, szTitle);
  785. }
  786. else
  787. {
  788. assert(FALSE);
  789. }
  790. if(pPickFax->BusinessFax)
  791. {
  792. SetDlgItemText(hDlg, IDC_BUSINESS_FAX_NUM, pPickFax->BusinessFax);
  793. CheckDlgButton(hDlg, IDC_BUSINESS_FAX, BST_CHECKED);
  794. }
  795. else
  796. {
  797. EnableWindow(GetDlgItem(hDlg, IDC_BUSINESS_FAX), FALSE);
  798. }
  799. if(pPickFax->HomeFax)
  800. {
  801. SetDlgItemText(hDlg, IDC_HOME_FAX_NUM, pPickFax->HomeFax);
  802. if(!pPickFax->BusinessFax)
  803. {
  804. CheckDlgButton(hDlg, IDC_HOME_FAX, BST_CHECKED);
  805. }
  806. }
  807. else
  808. {
  809. EnableWindow(GetDlgItem(hDlg, IDC_HOME_FAX), FALSE);
  810. }
  811. if(pPickFax->OtherFax)
  812. {
  813. SetDlgItemText(hDlg, IDC_OTHER_FAX_NUM, pPickFax->OtherFax);
  814. }
  815. else
  816. {
  817. EnableWindow(GetDlgItem(hDlg, IDC_OTHER_FAX), FALSE);
  818. }
  819. return TRUE;
  820. }
  821. case WM_COMMAND:
  822. {
  823. switch(LOWORD(wParam))
  824. {
  825. case IDOK:
  826. DWORD dwRes;
  827. if(IsDlgButtonChecked( hDlg, IDC_BUSINESS_FAX ))
  828. {
  829. dwRes = IDC_BUSINESS_FAX;
  830. }
  831. else if(IsDlgButtonChecked( hDlg, IDC_HOME_FAX ))
  832. {
  833. dwRes = IDC_HOME_FAX;
  834. }
  835. else
  836. {
  837. dwRes = IDC_OTHER_FAX;
  838. }
  839. EndDialog( hDlg, dwRes);
  840. return TRUE;
  841. case IDCANCEL:
  842. EndDialog( hDlg, IDCANCEL);
  843. return TRUE;
  844. }
  845. }
  846. default:
  847. return FALSE;
  848. }
  849. return FALSE;
  850. } // ChooseFaxNumberDlgProc
  851. PRECIPIENT
  852. CCommonAbObj::FindRecipient(
  853. PRECIPIENT pRecipient,
  854. PRECIPIENT pRecipList
  855. )
  856. /*++
  857. Routine Description:
  858. Find recipient (pRecipient) in the recipient list (pRecipList)
  859. by recipient name and fax number
  860. Arguments:
  861. pRecipList - pointer to recipient list
  862. pRecipient - pointer to recipient data
  863. Return Value:
  864. pointer to RECIPIENT structure if found
  865. NULL - otherwise.
  866. --*/
  867. {
  868. if(!pRecipient || !pRecipList || !pRecipient->pName || !pRecipient->pAddress)
  869. {
  870. return NULL;
  871. }
  872. while(pRecipList)
  873. {
  874. if(pRecipList->pName && pRecipList->pAddress &&
  875. !_tcscmp(pRecipList->pName, pRecipient->pName) &&
  876. !_tcscmp(pRecipList->pAddress, pRecipient->pAddress))
  877. {
  878. return pRecipList;
  879. }
  880. pRecipList = pRecipList->pNext;
  881. }
  882. return NULL;
  883. } // CCommonAbObj::FindRecipient
  884. PRECIPIENT
  885. CCommonAbObj::FindRecipient(
  886. PRECIPIENT pRecipList,
  887. PICKFAX* pPickFax
  888. )
  889. /*++
  890. Routine Description:
  891. Find recipient (pPickFax) in the recipient list (pRecipList)
  892. by recipient name and fax number
  893. Arguments:
  894. pRecipList - pointer to recipient list
  895. pPickFax - pointer to recipient data
  896. Return Value:
  897. pointer to RECIPIENT structure if found
  898. NULL - otherwise.
  899. --*/
  900. {
  901. if(!pRecipList || !pPickFax || !pPickFax->DisplayName)
  902. {
  903. return NULL;
  904. }
  905. while(pRecipList)
  906. {
  907. if(pRecipList->pName && pRecipList->pAddress &&
  908. !_tcscmp(pRecipList->pName, pPickFax->DisplayName))
  909. {
  910. if((pPickFax->BusinessFax &&
  911. !_tcscmp(pRecipList->pAddress, pPickFax->BusinessFax)) ||
  912. (pPickFax->HomeFax &&
  913. !_tcscmp(pRecipList->pAddress, pPickFax->HomeFax)) ||
  914. (pPickFax->OtherFax &&
  915. !_tcscmp(pRecipList->pAddress, pPickFax->OtherFax)))
  916. {
  917. return pRecipList;
  918. }
  919. }
  920. pRecipList = pRecipList->pNext;
  921. }
  922. return NULL;
  923. } // CCommonAbObj::FindRecipient
  924. BOOL
  925. CCommonAbObj::StrPropOk(LPSPropValue lpPropVals)
  926. {
  927. if(!lpPropVals)
  928. {
  929. return FALSE;
  930. }
  931. #ifdef UNIOCODE
  932. if(!m_bUnicode)
  933. {
  934. return (lpPropVals->Value.lpszA && *lpPropVals->Value.lpszA);
  935. }
  936. #endif
  937. return (lpPropVals->Value.LPSZ && *lpPropVals->Value.LPSZ);
  938. } // CCommonAbObj::StrPropOk
  939. DWORD
  940. CCommonAbObj::GetRecipientInfo(
  941. LPSPropValue SPropVals,
  942. ULONG cValues,
  943. PRECIPIENT pNewRecip,
  944. PRECIPIENT pOldRecipList
  945. )
  946. /*++
  947. Routine Description:
  948. Get the fax number and display name properties.
  949. Arguments:
  950. SPropVal - Property values for distribution list.
  951. cValues - Number of properties.
  952. pNewRecip - [out] pointer to the new recipient
  953. pOldRecipList - [in] pointer to the old recipient list
  954. Return Value:
  955. ERROR_SUCCESS - if there is a fax number and display name.
  956. ERROR_CANCELLED - the operation was canceled by user
  957. ERROR_INVALID_DATA - otherwise.
  958. --*/
  959. {
  960. DWORD dwRes = ERROR_SUCCESS;
  961. LPSPropValue lpPropVals;
  962. LPSPropValue lpPropArray;
  963. BOOL Result = FALSE;
  964. PICKFAX PickFax = { 0 };
  965. DWORD dwFaxes = 0;
  966. assert(pNewRecip);
  967. ZeroMemory(pNewRecip, sizeof(RECIPIENT));
  968. //
  969. // Get the entryid and open the entry.
  970. //
  971. lpPropVals = FindProp( SPropVals, cValues, PR_ENTRYID );
  972. if (lpPropVals)
  973. {
  974. ULONG lpulObjType;
  975. LPMAILUSER lpMailUser = NULL;
  976. HRESULT hr;
  977. ULONG countValues;
  978. pNewRecip->cbEntryId = lpPropVals->Value.bin.cb;
  979. ABAllocateBuffer(pNewRecip->cbEntryId, (LPVOID *)&pNewRecip->lpEntryId);
  980. if(!pNewRecip->lpEntryId)
  981. {
  982. return ERROR_NOT_ENOUGH_MEMORY;
  983. }
  984. else
  985. {
  986. memcpy(pNewRecip->lpEntryId, lpPropVals->Value.bin.lpb, pNewRecip->cbEntryId);
  987. }
  988. hr = m_lpAdrBook->OpenEntry(pNewRecip->cbEntryId,
  989. (ENTRYID*)pNewRecip->lpEntryId,
  990. (LPCIID) NULL,
  991. 0,
  992. &lpulObjType,
  993. (LPUNKNOWN *) &lpMailUser);
  994. if (HR_SUCCEEDED(hr))
  995. {
  996. //
  997. // Get the properties.
  998. //
  999. hr = ((IMailUser *)lpMailUser)->GetProps(m_bUnicode ? (LPSPropTagArray)&sPropTagsW : (LPSPropTagArray)&sPropTagsA,
  1000. StrCoding(),
  1001. &countValues,
  1002. &lpPropArray );
  1003. if (HR_SUCCEEDED(hr))
  1004. {
  1005. lpPropVals = FindProp(lpPropArray, countValues, PR_PRIMARY_FAX_NUMBER);
  1006. if (StrPropOk( lpPropVals ))
  1007. {
  1008. PickFax.OtherFax = StrFromAddrBk(lpPropVals);
  1009. if(PickFax.OtherFax && _tcslen(PickFax.OtherFax))
  1010. {
  1011. ++dwFaxes;
  1012. }
  1013. }
  1014. lpPropVals = FindProp(lpPropArray, countValues, PR_BUSINESS_FAX_NUMBER);
  1015. if (StrPropOk( lpPropVals ))
  1016. {
  1017. PickFax.BusinessFax = StrFromAddrBk(lpPropVals);
  1018. if(PickFax.BusinessFax && _tcslen(PickFax.BusinessFax))
  1019. {
  1020. ++dwFaxes;
  1021. }
  1022. }
  1023. lpPropVals = FindProp(lpPropArray, countValues, PR_HOME_FAX_NUMBER);
  1024. if (StrPropOk( lpPropVals ))
  1025. {
  1026. PickFax.HomeFax = StrFromAddrBk(lpPropVals);
  1027. if(PickFax.HomeFax && _tcslen(PickFax.HomeFax))
  1028. {
  1029. ++dwFaxes;
  1030. }
  1031. }
  1032. lpPropVals = FindProp(lpPropArray, countValues, PR_DISPLAY_NAME);
  1033. if (StrPropOk( lpPropVals ))
  1034. {
  1035. pNewRecip->pName = PickFax.DisplayName = StrFromAddrBk(lpPropVals);
  1036. }
  1037. lpPropVals = FindProp(lpPropArray, countValues, PR_COUNTRY);
  1038. if (StrPropOk( lpPropVals ))
  1039. {
  1040. pNewRecip->pCountry = PickFax.Country = StrFromAddrBk(lpPropVals);
  1041. }
  1042. if (0 == dwFaxes)
  1043. {
  1044. lpPropVals = FindProp(lpPropArray, countValues, PR_ADDRTYPE);
  1045. if(lpPropVals && ABStrCmp(lpPropVals, TEXT("FAX")))
  1046. {
  1047. lpPropVals = FindProp(lpPropArray, countValues, PR_EMAIL_ADDRESS);
  1048. if (StrPropOk( lpPropVals ))
  1049. {
  1050. pNewRecip->pAddress = StrFromAddrBk(lpPropVals);
  1051. if(pNewRecip->pAddress)
  1052. {
  1053. ++dwFaxes;
  1054. }
  1055. }
  1056. }
  1057. }
  1058. PRECIPIENT pRecip = FindRecipient(pOldRecipList, &PickFax);
  1059. if(pRecip)
  1060. {
  1061. pNewRecip->pAddress = StringDup(pRecip->pAddress);
  1062. pNewRecip->dwCountryId = pRecip->dwCountryId;
  1063. pNewRecip->bUseDialingRules = pRecip->bUseDialingRules;
  1064. MemFree(PickFax.BusinessFax);
  1065. PickFax.BusinessFax = NULL;
  1066. MemFree(PickFax.HomeFax);
  1067. PickFax.HomeFax = NULL;
  1068. MemFree(PickFax.OtherFax);
  1069. PickFax.OtherFax = NULL;
  1070. dwFaxes = 1;
  1071. }
  1072. //
  1073. // If there are more then 1 fax numbers, ask the user to pick one.
  1074. //
  1075. if (dwFaxes > 1)
  1076. {
  1077. INT_PTR nResult;
  1078. nResult = DialogBoxParam((HINSTANCE) m_hInstance,
  1079. MAKEINTRESOURCE( IDD_CHOOSE_FAXNUMBER ),
  1080. m_hWnd,
  1081. ChooseFaxNumberDlgProc,
  1082. (LPARAM) &PickFax);
  1083. switch( nResult )
  1084. {
  1085. case IDC_BUSINESS_FAX:
  1086. pNewRecip->pAddress = PickFax.BusinessFax;
  1087. MemFree(PickFax.HomeFax);
  1088. PickFax.HomeFax = NULL;
  1089. MemFree(PickFax.OtherFax);
  1090. PickFax.OtherFax = NULL;
  1091. break;
  1092. case IDC_HOME_FAX:
  1093. pNewRecip->pAddress = PickFax.HomeFax;
  1094. MemFree(PickFax.BusinessFax);
  1095. PickFax.BusinessFax = NULL;
  1096. MemFree(PickFax.OtherFax);
  1097. PickFax.OtherFax = NULL;
  1098. break;
  1099. case IDC_OTHER_FAX:
  1100. pNewRecip->pAddress = PickFax.OtherFax;
  1101. MemFree(PickFax.BusinessFax);
  1102. PickFax.BusinessFax = NULL;
  1103. MemFree(PickFax.HomeFax);
  1104. PickFax.HomeFax = NULL;
  1105. break;
  1106. case IDCANCEL:
  1107. MemFree(PickFax.BusinessFax);
  1108. PickFax.BusinessFax = NULL;
  1109. MemFree(PickFax.HomeFax);
  1110. PickFax.HomeFax = NULL;
  1111. MemFree(PickFax.OtherFax);
  1112. PickFax.OtherFax = NULL;
  1113. dwRes = ERROR_CANCELLED;
  1114. break;
  1115. }
  1116. }
  1117. }
  1118. ABFreeBuffer( lpPropArray );
  1119. }
  1120. if(!m_lpMailUser)
  1121. {
  1122. //
  1123. // Remember the first MailUser and do not release it
  1124. // to avoid release of the MAPI DLLs
  1125. // m_lpMailUser should be released later
  1126. //
  1127. m_lpMailUser = lpMailUser;
  1128. }
  1129. else if(lpMailUser)
  1130. {
  1131. lpMailUser->Release();
  1132. lpMailUser = NULL;
  1133. }
  1134. }
  1135. if (0 == dwFaxes)
  1136. {
  1137. lpPropVals = FindProp(SPropVals, cValues, PR_ADDRTYPE);
  1138. if(lpPropVals && ABStrCmp(lpPropVals, TEXT("FAX")))
  1139. {
  1140. lpPropVals = FindProp(SPropVals, cValues, PR_EMAIL_ADDRESS);
  1141. if (StrPropOk( lpPropVals ))
  1142. {
  1143. TCHAR* pAddress = StrFromAddrBk(lpPropVals);
  1144. if(pAddress)
  1145. {
  1146. TCHAR* ptr = _tcschr(pAddress, TEXT('@'));
  1147. if(ptr)
  1148. {
  1149. ptr = _tcsinc(ptr);
  1150. pNewRecip->pAddress = StringDup(ptr);
  1151. MemFree(pAddress);
  1152. }
  1153. else
  1154. {
  1155. pNewRecip->pAddress = pAddress;
  1156. }
  1157. }
  1158. }
  1159. lpPropVals = FindProp(SPropVals, cValues, PR_DISPLAY_NAME);
  1160. if (StrPropOk( lpPropVals ))
  1161. {
  1162. MemFree(pNewRecip->pName);
  1163. pNewRecip->pName = NULL;
  1164. pNewRecip->pName = StrFromAddrBk(lpPropVals);
  1165. }
  1166. }
  1167. }
  1168. if (PickFax.BusinessFax)
  1169. {
  1170. pNewRecip->pAddress = PickFax.BusinessFax;
  1171. }
  1172. else if (PickFax.HomeFax)
  1173. {
  1174. pNewRecip->pAddress = PickFax.HomeFax;
  1175. }
  1176. else if (PickFax.OtherFax)
  1177. {
  1178. pNewRecip->pAddress = PickFax.OtherFax;
  1179. }
  1180. if (ERROR_CANCELLED != dwRes &&
  1181. (!pNewRecip->pAddress || !pNewRecip->pName))
  1182. {
  1183. dwRes = ERROR_INVALID_DATA;
  1184. }
  1185. if(ERROR_SUCCESS != dwRes)
  1186. {
  1187. MemFree(pNewRecip->pName);
  1188. MemFree(pNewRecip->pAddress);
  1189. MemFree(pNewRecip->pCountry);
  1190. ABFreeBuffer(pNewRecip->lpEntryId);
  1191. ZeroMemory(pNewRecip, sizeof(RECIPIENT));
  1192. }
  1193. return dwRes;
  1194. } // CCommonAbObj::GetRecipientInfo
  1195. BOOL
  1196. CCommonAbObj::GetOneOffRecipientInfo(
  1197. LPSPropValue SPropVals,
  1198. ULONG cValues,
  1199. PRECIPIENT pNewRecip,
  1200. PRECIPIENT pOldRecipList
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. Get the fax number and display name properties.
  1205. Arguments:
  1206. SPropVal - Property values for distribution list.
  1207. cValues - Number of properties.
  1208. pNewRecip - [out] pointer to a new recipient
  1209. pOldRecipList - pointer to the old recipient list
  1210. Return Value:
  1211. TRUE if there is a fax number and display name.
  1212. FALSE otherwise.
  1213. --*/
  1214. {
  1215. PRECIPIENT pRecip = NULL;
  1216. LPSPropValue lpPropVals;
  1217. assert(!pNewRecip);
  1218. lpPropVals = FindProp(SPropVals, cValues, PR_PRIMARY_FAX_NUMBER);
  1219. if (lpPropVals)
  1220. {
  1221. if (!(pNewRecip->pAddress = StrFromAddrBk(lpPropVals)))
  1222. {
  1223. goto error;
  1224. }
  1225. }
  1226. lpPropVals = FindProp(SPropVals, cValues, PR_DISPLAY_NAME);
  1227. if (lpPropVals)
  1228. {
  1229. if (!(pNewRecip->pName = StrFromAddrBk(lpPropVals)))
  1230. {
  1231. goto error;
  1232. }
  1233. }
  1234. pRecip = FindRecipient(pNewRecip, pOldRecipList);
  1235. if(pRecip)
  1236. {
  1237. pNewRecip->dwCountryId = pRecip->dwCountryId;
  1238. pNewRecip->bUseDialingRules = pRecip->bUseDialingRules;
  1239. }
  1240. return TRUE;
  1241. error:
  1242. MemFree(pNewRecip->pAddress);
  1243. MemFree(pNewRecip->pName);
  1244. return FALSE;
  1245. } // CCommonAbObj::GetOneOffRecipientInfo
  1246. LPTSTR
  1247. CCommonAbObj::GetEmail(
  1248. LPSPropValue SPropVals,
  1249. ULONG cValues
  1250. )
  1251. /*++
  1252. Routine Description:
  1253. Get e-mail address
  1254. Arguments:
  1255. SPropVal - Property values for distribution list.
  1256. cValues - Number of properties.
  1257. Return Value:
  1258. A choosen E-mail address
  1259. NULL otherwise.
  1260. --*/
  1261. {
  1262. LPSPropValue lpPropVals = NULL;
  1263. LPSPropValue lpPropArray = NULL;
  1264. BOOL Result = FALSE;
  1265. LPTSTR lptstrEmailAddress = NULL;
  1266. TCHAR tszBuffer[MAX_STRING_LEN];
  1267. ULONG lpulObjType = 0;
  1268. LPMAILUSER lpMailUser = NULL;
  1269. LPENTRYID lpEntryId = NULL;
  1270. DWORD cbEntryId = 0;
  1271. HRESULT hr;
  1272. ULONG countValues = 0;
  1273. //
  1274. // Get the entryid and open the entry.
  1275. //
  1276. lpPropVals = FindProp( SPropVals, cValues, PR_ENTRYID );
  1277. if (!lpPropVals)
  1278. {
  1279. goto exit;
  1280. }
  1281. lpEntryId = (LPENTRYID)lpPropVals->Value.bin.lpb;
  1282. cbEntryId = lpPropVals->Value.bin.cb;
  1283. hr = m_lpAdrBook->OpenEntry(cbEntryId,
  1284. lpEntryId,
  1285. (LPCIID) NULL,
  1286. 0,
  1287. &lpulObjType,
  1288. (LPUNKNOWN *) &lpMailUser);
  1289. if (HR_FAILED(hr))
  1290. {
  1291. goto exit;
  1292. }
  1293. //
  1294. // Get the properties.
  1295. //
  1296. hr = ((IMailUser*)lpMailUser)->GetProps(m_bUnicode ? (LPSPropTagArray)&sPropTagsW : (LPSPropTagArray)&sPropTagsA,
  1297. StrCoding(),
  1298. &countValues,
  1299. &lpPropArray);
  1300. if (HR_FAILED(hr))
  1301. {
  1302. goto exit;
  1303. }
  1304. lpPropVals = FindProp(lpPropArray, countValues, PR_ADDRTYPE);
  1305. if (lpPropVals && ABStrCmp(lpPropVals, TEXT("SMTP")))
  1306. {
  1307. lpPropVals = FindProp(lpPropArray, countValues, PR_EMAIL_ADDRESS);
  1308. if (StrPropOk( lpPropVals ))
  1309. {
  1310. lptstrEmailAddress = StrFromAddrBk(lpPropVals);
  1311. }
  1312. }
  1313. else if (lpPropVals && ABStrCmp(lpPropVals, TEXT("EX")))
  1314. {
  1315. lpPropVals = FindProp(lpPropArray, countValues, PR_EMS_AB_PROXY_ADDRESSES);
  1316. if (lpPropVals)
  1317. {
  1318. DWORD dwArrSize = m_bUnicode ? lpPropVals->Value.MVszW.cValues : lpPropVals->Value.MVszA.cValues;
  1319. for(DWORD dw=0; dw < dwArrSize; ++dw)
  1320. {
  1321. if(m_bUnicode)
  1322. {
  1323. if(wcsstr(lpPropVals->Value.MVszW.lppszW[dw], L"SMTP:"))
  1324. {
  1325. WCHAR* ptr = wcschr(lpPropVals->Value.MVszW.lppszW[dw], L':');
  1326. ptr++;
  1327. SPropValue propVal = {0};
  1328. propVal.Value.lpszW = ptr;
  1329. lptstrEmailAddress = StrFromAddrBk(&propVal);
  1330. break;
  1331. }
  1332. }
  1333. else // ANSII
  1334. {
  1335. if(strstr(lpPropVals->Value.MVszA.lppszA[dw], "SMTP:"))
  1336. {
  1337. CHAR* ptr = strchr(lpPropVals->Value.MVszA.lppszA[dw], ':');
  1338. ptr++;
  1339. SPropValue propVal = {0};
  1340. propVal.Value.lpszA = ptr;
  1341. lptstrEmailAddress = StrFromAddrBk(&propVal);
  1342. break;
  1343. }
  1344. }
  1345. }
  1346. }
  1347. }
  1348. exit:
  1349. if(lpPropArray)
  1350. {
  1351. ABFreeBuffer( lpPropArray );
  1352. }
  1353. if (lpMailUser)
  1354. {
  1355. lpMailUser->Release();
  1356. }
  1357. if(!lptstrEmailAddress)
  1358. {
  1359. if (!::LoadString((HINSTANCE )m_hInstance, IDS_ERROR_RECEIPT_SMTP,tszBuffer, MAX_STRING_LEN))
  1360. {
  1361. assert(FALSE);
  1362. }
  1363. else
  1364. {
  1365. AlignedMessageBox( m_hWnd, tszBuffer, NULL, MB_ICONSTOP | MB_OK);
  1366. }
  1367. }
  1368. return lptstrEmailAddress;
  1369. } // CCommonAbObj::GetEmail
  1370. LPSPropValue
  1371. CCommonAbObj::FindProp(
  1372. LPSPropValue rgprop,
  1373. ULONG cprop,
  1374. ULONG ulPropTag
  1375. )
  1376. /*++
  1377. Routine Description:
  1378. Searches for a given property tag in a propset. If the given
  1379. property tag has type PT_UNSPECIFIED, matches only on the
  1380. property ID; otherwise, matches on the entire tag.
  1381. Arguments:
  1382. rgprop - Property values.
  1383. cprop - Number of properties.
  1384. ulPropTag - Property to search for.
  1385. Return Value:
  1386. Pointer to property desired property value or NULL.
  1387. --*/
  1388. {
  1389. if (!cprop || !rgprop)
  1390. {
  1391. return NULL;
  1392. }
  1393. LPSPropValue pprop = rgprop;
  1394. #ifdef UNICODE
  1395. if(!m_bUnicode)
  1396. {
  1397. //
  1398. // If the Address Book does not support Unicode
  1399. // change the property type to ANSII
  1400. //
  1401. if(PROP_TYPE(ulPropTag) == PT_UNICODE)
  1402. {
  1403. ulPropTag = PROP_TAG( PT_STRING8, PROP_ID(ulPropTag));
  1404. }
  1405. if(PROP_TYPE(ulPropTag) == PT_MV_UNICODE)
  1406. {
  1407. ulPropTag = PROP_TAG( PT_MV_STRING8, PROP_ID(ulPropTag));
  1408. }
  1409. }
  1410. #endif
  1411. while (cprop--)
  1412. {
  1413. if (pprop->ulPropTag == ulPropTag)
  1414. {
  1415. return pprop;
  1416. }
  1417. ++pprop;
  1418. }
  1419. return NULL;
  1420. } // CCommonAbObj::FindProp
  1421. DWORD
  1422. CCommonAbObj::AddRecipient(
  1423. PRECIPIENT *ppNewRecipList,
  1424. PRECIPIENT pRecipient,
  1425. BOOL bFromAddressBook
  1426. )
  1427. /*++
  1428. Routine Description:
  1429. Add a recipient to the recipient list.
  1430. Arguments:
  1431. ppNewRecip - pointer to pointer to list to add item to.
  1432. pRecipient - pointer to the new recipient data
  1433. bFromAddressBook - boolean says if this recipient is from address book
  1434. Return Value:
  1435. NA
  1436. --*/
  1437. {
  1438. DWORD dwRes = ERROR_SUCCESS;
  1439. PRECIPIENT pNewRecip = NULL;
  1440. pNewRecip = (PRECIPIENT)MemAllocZ(sizeof(RECIPIENT));
  1441. if(!pNewRecip)
  1442. {
  1443. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  1444. goto error;
  1445. }
  1446. else
  1447. {
  1448. pNewRecip->pName = pRecipient->pName;
  1449. pNewRecip->pAddress = pRecipient->pAddress;
  1450. pNewRecip->pCountry = pRecipient->pCountry;
  1451. pNewRecip->cbEntryId = pRecipient->cbEntryId;
  1452. pNewRecip->lpEntryId = pRecipient->lpEntryId;
  1453. pNewRecip->dwCountryId = pRecipient->dwCountryId;
  1454. pNewRecip->bUseDialingRules = pRecipient->bUseDialingRules;
  1455. pNewRecip->bFromAddressBook = bFromAddressBook;
  1456. pNewRecip->pNext = *ppNewRecipList;
  1457. }
  1458. try
  1459. {
  1460. //
  1461. // Try to insert a recipient into the set
  1462. //
  1463. if(m_setRecipients.insert(pNewRecip).second == false)
  1464. {
  1465. //
  1466. // Such recipient already exists
  1467. //
  1468. goto error;
  1469. }
  1470. }
  1471. catch (std::bad_alloc&)
  1472. {
  1473. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  1474. goto error;
  1475. }
  1476. //
  1477. // Add the recipient into the list
  1478. //
  1479. *ppNewRecipList = pNewRecip;
  1480. return dwRes;
  1481. error:
  1482. MemFree(pRecipient->pName);
  1483. MemFree(pRecipient->pAddress);
  1484. MemFree(pRecipient->pCountry);
  1485. ABFreeBuffer(pRecipient->lpEntryId);
  1486. ZeroMemory(pRecipient, sizeof(RECIPIENT));
  1487. MemFree(pNewRecip);
  1488. return dwRes;
  1489. } // CCommonAbObj::AddRecipient
  1490. LPTSTR
  1491. CCommonAbObj::StrToAddrBk(
  1492. LPCTSTR szStr,
  1493. DWORD* pdwSize /* = NULL*/
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. Allocate string converted to the Address book encoding
  1498. Arguments:
  1499. szStr - [in] source string
  1500. pdwSize - [out] optional size of new string in bytes
  1501. Return Value:
  1502. Pointer to the converted string
  1503. Should be released by MemFree()
  1504. --*/
  1505. {
  1506. if(!szStr)
  1507. {
  1508. Assert(FALSE);
  1509. return NULL;
  1510. }
  1511. #ifdef UNICODE
  1512. if(!m_bUnicode)
  1513. {
  1514. //
  1515. // The address book does not support Unicode
  1516. //
  1517. INT nSize;
  1518. LPSTR pAnsii;
  1519. //
  1520. // Figure out how much memory to allocate for the multi-byte string
  1521. //
  1522. if (! (nSize = WideCharToMultiByte(CP_ACP, 0, szStr, -1, NULL, 0, NULL, NULL)) ||
  1523. ! (pAnsii = (LPSTR)MemAlloc(nSize)))
  1524. {
  1525. return NULL;
  1526. }
  1527. //
  1528. // Convert Unicode string to multi-byte string
  1529. //
  1530. WideCharToMultiByte(CP_ACP, 0, szStr, -1, pAnsii, nSize, NULL, NULL);
  1531. if(pdwSize)
  1532. {
  1533. *pdwSize = nSize;
  1534. }
  1535. return (LPTSTR)pAnsii;
  1536. }
  1537. #endif // UNICODE
  1538. LPTSTR pNewStr = StringDup(szStr);
  1539. if(pdwSize && pNewStr)
  1540. {
  1541. *pdwSize = (_tcslen(pNewStr)+1) * sizeof(TCHAR);
  1542. }
  1543. return pNewStr;
  1544. } // CCommonAbObj::StrToAddrBk
  1545. LPTSTR
  1546. CCommonAbObj::StrFromAddrBk(LPSPropValue pValue)
  1547. /*++
  1548. Routine Description:
  1549. Allocate string converted from the Address book encoding
  1550. Arguments:
  1551. pValue - [in] MAPI property
  1552. Return Value:
  1553. Pointer to the converted string
  1554. Should be released by MemFree()
  1555. --*/
  1556. {
  1557. if(!pValue)
  1558. {
  1559. Assert(FALSE);
  1560. return NULL;
  1561. }
  1562. #ifdef UNICODE
  1563. if(!m_bUnicode)
  1564. {
  1565. //
  1566. // The address book does not support Unicode
  1567. //
  1568. if(!pValue->Value.lpszA)
  1569. {
  1570. Assert(FALSE);
  1571. return NULL;
  1572. }
  1573. INT nSize;
  1574. LPWSTR pUnicodeStr;
  1575. if (! (nSize = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pValue->Value.lpszA, -1, NULL, 0)) ||
  1576. ! (pUnicodeStr = (LPWSTR) MemAlloc( nSize * sizeof(WCHAR))))
  1577. {
  1578. return NULL;
  1579. }
  1580. //
  1581. // Convert multi-byte string to Unicode string
  1582. //
  1583. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pValue->Value.lpszA, -1, pUnicodeStr, nSize);
  1584. return pUnicodeStr;
  1585. }
  1586. #endif // UNICODE
  1587. if(!pValue->Value.LPSZ)
  1588. {
  1589. Assert(FALSE);
  1590. return NULL;
  1591. }
  1592. LPTSTR pNewStr = StringDup(pValue->Value.LPSZ);
  1593. return pNewStr;
  1594. } // CCommonAbObj::StrFromAddrBk
  1595. BOOL
  1596. CCommonAbObj::ABStrCmp(LPSPropValue lpPropVals, LPTSTR pStr)
  1597. /*++
  1598. Routine Description:
  1599. Compare string with MAPI property value according to the address book encoding
  1600. Arguments:
  1601. lpPropVals - [in] MAPI property
  1602. pStr - [in] string to compare
  1603. Return Value:
  1604. TRUE if the strings are equal
  1605. FALSE otherwise
  1606. --*/
  1607. {
  1608. BOOL bRes = FALSE;
  1609. if(!lpPropVals || !pStr)
  1610. {
  1611. Assert(FALSE);
  1612. return bRes;
  1613. }
  1614. #ifdef UNICODE
  1615. if(!m_bUnicode)
  1616. {
  1617. LPSTR pAnsii = (LPSTR)StrToAddrBk(pStr);
  1618. if(pAnsii)
  1619. {
  1620. bRes = !strcmp(lpPropVals->Value.lpszA, pAnsii);
  1621. MemFree(pAnsii);
  1622. }
  1623. return bRes;
  1624. }
  1625. #endif
  1626. bRes = !_tcscmp(lpPropVals->Value.LPSZ, pStr);
  1627. return bRes;
  1628. } // CCommonAbObj::ABStrCmp
  1629. BOOL
  1630. CCommonAbObj::GetAddrBookCaption(
  1631. LPTSTR szCaption,
  1632. DWORD dwSize
  1633. )
  1634. /*++
  1635. Routine Description:
  1636. Get address book dialog caption according to the ANSII/Unicode capability
  1637. Arguments:
  1638. szCaption - [out] caption buffer
  1639. dwSize - [in] caption buffer size in characters
  1640. Return Value:
  1641. TRUE if success
  1642. FALSE otherwise
  1643. --*/
  1644. {
  1645. if(!szCaption || !dwSize)
  1646. {
  1647. Assert(FALSE);
  1648. return FALSE;
  1649. }
  1650. TCHAR tszStr[MAX_PATH] = {0};
  1651. if(!LoadString(m_hInstance, IDS_ADDRESS_BOOK_CAPTION, tszStr, ARR_SIZE(tszStr)))
  1652. {
  1653. return FALSE;
  1654. }
  1655. _tcsncpy(szCaption, tszStr, dwSize);
  1656. #ifdef UNICODE
  1657. if(!m_bUnicode || GetABType() == AB_MAPI)
  1658. {
  1659. //
  1660. // MAPI interpret lpszCaption as ANSII anyway
  1661. //
  1662. char szAnsiStr[MAX_PATH] = {0};
  1663. if(!WideCharToMultiByte(CP_ACP,
  1664. 0,
  1665. tszStr,
  1666. -1,
  1667. szAnsiStr,
  1668. ARR_SIZE(szAnsiStr),
  1669. NULL,
  1670. NULL))
  1671. {
  1672. return FALSE;
  1673. }
  1674. memcpy(szCaption, szAnsiStr, min(dwSize, strlen(szAnsiStr)+1));
  1675. }
  1676. #endif // UNICODE
  1677. return TRUE;
  1678. } // CCommonAbObj::GetAddrBookCaption