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.

1305 lines
35 KiB

  1. /*
  2. ===============================================================================
  3. Module - edk.cpp
  4. System - EnterpriseAdministrator
  5. Creator - Steven Bailey
  6. Created - 2 Apr 97
  7. Description - Exchange MAPI helper routines.
  8. Updates - Christy Boles - added more MAPI helper functions, and some DAPI
  9. helper functions.
  10. ===============================================================================
  11. */
  12. #ifdef USE_STDAFX
  13. # include "stdafx.h"
  14. #else
  15. # include <windows.h>
  16. #endif
  17. #include <mapiguid.h>
  18. #include "edk2.hpp"
  19. #include <edkcode.h>
  20. #include <objbase.h>
  21. #include <mapiutil.h>
  22. #include <emsabtag.h>
  23. #include <_ENTRYID.H>
  24. extern LPMAPIALLOCATEBUFFER pMAPIAllocateBuffer;
  25. extern LPMAPIFREEBUFFER pMAPIFreeBuffer;
  26. extern LPMAPIINITIALIZE pMAPIInitialize;
  27. extern LPMAPIUNINITIALIZE pMAPIUninitialize;
  28. extern LPMAPILOGONEX pMAPILogonEx;
  29. extern LPMAPIADMINPROFILES pMAPIAdminProfiles;
  30. extern LPFREEPADRLIST pFreePadrlist;
  31. extern LPFREEPROWS pFreeProws;
  32. extern LPSCDUPPROPSET pScDupPropset;
  33. extern LPHRQUERYALLROWS pHrQueryAllRows;
  34. extern LPULRELEASE pUlRelease;
  35. #define CHAR WCHAR
  36. #define HR_LOG(x) x
  37. // definition of the Exchange address type.
  38. // from edk.h
  39. #define EXCHANGE_ADDRTYPE L"EX"
  40. #define CbNewFlagList(_cflag) \
  41. (offsetof(FlagList,ulFlag) + (_cflag)*sizeof(ULONG))
  42. //$--cbStrLen@------------------------------------------------
  43. // Returns total number of bytes (including NULL) used by
  44. // a string. Useful for string allocations...
  45. // -----------------------------------------------------------
  46. #define cbStrLenA(sz) ((lstrlenA((sz)) + 1) * sizeof(CHAR))
  47. #if defined(_M_IX86)
  48. #define cbStrLenW(sz) ((lstrlenW((sz)) + 1) * sizeof(WCHAR))
  49. #else
  50. // lstrlenW can return 0 for UNALIGNED UNICODE strings on non-IX86 platforms
  51. __inline static size_t cbStrLenW(
  52. IN UNALIGNED const WCHAR *wsz)
  53. {
  54. size_t cbWsz = 0;
  55. for(; *wsz; wsz++)
  56. cbWsz += sizeof( WCHAR);
  57. return( cbWsz + sizeof( WCHAR));
  58. }
  59. #endif
  60. #ifdef UNICODE
  61. #define cbStrLen cbStrLenW
  62. #else
  63. #define cbStrLen cbStrLenA
  64. #endif
  65. #define ULRELEASE(x) \
  66. { \
  67. (*pUlRelease)((x)); \
  68. (x) = NULL; \
  69. }
  70. #define MAPIFREEBUFFER(x) \
  71. { \
  72. (*pMAPIFreeBuffer)((x)); \
  73. (x) = NULL; \
  74. }
  75. #define FREEPADRLIST(x) \
  76. { \
  77. (*pFreePadrlist)((x)); \
  78. (x) = NULL; \
  79. }
  80. #define FREEPROWS(x) \
  81. { \
  82. (*pFreeProws)((x)); \
  83. (x) = NULL; \
  84. }
  85. // Definitions from ExchInst.c
  86. #define MAX_CSV_LINE_SIZ 2048
  87. #define MAX_WORD 0xFFFF
  88. #define FILE_PREFIX L"EXCH"
  89. #define NEW_LINE L"\r\n"
  90. #define EXCHINST_DELIM L'\t'
  91. #define EXCHINST_QUOTE L'"'
  92. #define EXCHINST_MV_SEP L'%'
  93. #define SZ_EXCHINST_DELIM L"\t"
  94. #define SZ_EXCHINST_QUOTE L"\""
  95. #define SZ_EXCHINST_MV_SEP L"%"
  96. #define BEGIN_CSV_LINE(a,b) lstrcpy(a, b)
  97. #define APPEND_CSV_LINE(a,b) \
  98. { \
  99. lstrcat(a, SZ_EXCHINST_DELIM); \
  100. lstrcat(a, b); \
  101. }
  102. #define DELETEFILE(_file) \
  103. { \
  104. if((_file) != NULL && (_file)[0] != 0) \
  105. { \
  106. if(! DeleteFile ((_file))) \
  107. { \
  108. HRESULT _hr = HR_LOG(E_FAIL); \
  109. } \
  110. } \
  111. (_file)[0] = 0; \
  112. }
  113. #define CLOSEHANDLE(h) \
  114. { \
  115. if(((h) != NULL) && ((h) != INVALID_HANDLE_VALUE)) \
  116. { \
  117. if(CloseHandle((h)) == FALSE) \
  118. { \
  119. /* HRESULT _hr = HR_LOG(E_FAIL); \
  120. */ HR_LOG(E_FAIL); \
  121. } \
  122. (h) = NULL; \
  123. } \
  124. }
  125. //
  126. // Attribute Defines
  127. //
  128. #define OBJ_CLASS L"Obj-Class"
  129. #define MODE L"Mode"
  130. #define ADDR_SYNTAX L"Address-Syntax"
  131. #define ADDR_ENTRY_DT L"Address-Entry-Display-Table"
  132. #define ADDR_TYPE L"Address-Type"
  133. #define ADMIN_DISPLAY_NAME L"Admin-Display-Name"
  134. #define DISPLAY_NAME L"Display-Name"
  135. #define COMMON_NAME L"Common-Name"
  136. #define DELIVERY_MECHANISM L"Delivery-Mechanism"
  137. #define DELIV_EXT_CONT_TYPES L"Deliv-Ext-Cont-Types"
  138. #define EXTENSION_DATA L"Extension-Data"
  139. #define EXTENSION_NAME L"Extension-Name"
  140. #define HELP_FILE_NAME L"Help-File-Name"
  141. #define COMPUTER_NAME L"Computer-Name"
  142. #define GATEWAY_PROXY L"Gateway-Proxy"
  143. #define HOME_SERVER L"Home-Server"
  144. #define FILE_VERSION L"File-Version"
  145. #define PER_MSG_DDT L"Per-Msg-Dialog-Display-Table"
  146. #define PER_RECIP_DDT L"Per-Recip-Dialog-Display-Table"
  147. #define PROXY_GENERATOR_DLL L"Proxy-Generator-DLL"
  148. #define ROUTING_LIST L"Routing-List"
  149. #define OBJ_DIST_NAME L"Obj-Dist-Name"
  150. #define ORGANIZATION L"Organization"
  151. #define ORGANIZATIONAL_UNIT L"Organizational-Unit"
  152. #define CONTAINER L"Container"
  153. #define HELP_DATA16 L"Help-Data16"
  154. #define HELP_DATA32 L"Help-Data32"
  155. #define OBJ_ADMIN L"Obj-Admins"
  156. #define SITE_ADDRESSING L"Site-Addressing"
  157. #define ADMIN_EXTENSION_DLL L"Admin-Extension-Dll"
  158. #define CAN_PRESERVE_DNS L"Can-Preserve-DNs"
  159. #define HEURISTICS L"Heuristics"
  160. #define CONTAINER_INFO L"Container-Info"
  161. //
  162. // Attribute Value Defines
  163. //
  164. #define OBJ_CLASS_GW L"Mail-Gateway"
  165. #define OBJ_CLASS_MB L"Mailbox-Agent"
  166. #define OBJ_CLASS_SITE L"Site-Addressing"
  167. #define OBJ_CLASS_ADDR_TYPE L"Addr-Type"
  168. #define OBJ_CLASS_ADDR_TEMPLATE L"Address-Template"
  169. #define OBJ_CLASS_ADMIN_EXTENSION L"Admin-Extension"
  170. #define OBJ_CLASS_COMPUTER L"Computer"
  171. #define OBJ_CLASS_CONTAINER L"Container"
  172. //
  173. // Container Information Defines
  174. //
  175. #define ADDRESS_TEMPLATE_CONTAINER_INFO L"256"
  176. //
  177. // Import Mode Defines
  178. //
  179. #define MODE_CREATE L"Create"
  180. #define MODE_MODIFY L"Modify"
  181. #define MODE_DELETE L"Delete"
  182. #define DELIVERY_MECHANISM_GW L"2"
  183. #define DELIVERY_MECHANISM_MB L"0"
  184. #define CONTAINER_CONFIGURATION L"/cn=Configuration"
  185. #define CONTAINER_GW L"/cn=Configuration/cn=Connections"
  186. #define CONTAINER_ADDR_TYPE L"/cn=Configuration/cn=Addressing/cn=Address-Types"
  187. #define CONTAINER_ADDR_TEMPLATE L"/cn=Configuration/cn=Addressing/cn=Address-Templates"
  188. #define CONTAINER_SERVERS L"/cn=Configuration/cn=Servers"
  189. #define CONTAINER_SITE_ADDR L"/cn=Configuration/cn=Site-Addressing"
  190. #define CONTAINER_ADD_INS L"/cn=Configuration/cn=Add-Ins"
  191. #define ACCOUNT_NAME L"Obj-Users"
  192. //
  193. // Common macros.
  194. //
  195. #define CREATEKEY(hkParent, pszName, hkOut, dwDisposition) \
  196. RegCreateKeyEx(hkParent, pszName, 0, "", REG_OPTION_NON_VOLATILE, \
  197. KEY_ALL_ACCESS, NULL, &hkOut, &dwDisposition)
  198. #define SETSZVALUE(hk, pszName, pszValue) \
  199. RegSetValueEx(hk, pszName, 0, REG_SZ, pszValue, lstrlen(pszValue)+1)
  200. #define SETMULTISZVALUE(hk, pszName, pszValue) \
  201. RegSetValueEx(hk, pszName, 0, REG_MULTI_SZ, pszValue, \
  202. CbMultiSz(pszValue)+sizeof(CHAR))
  203. #define FREEHKEY(hk) \
  204. if(hk != INVALID_HANDLE_VALUE) \
  205. RegCloseKey(hk);
  206. static CHAR szExport[] = L"Export";
  207. static CHAR szNull[] = L"(null)";
  208. static CHAR szNullDisplayName[] = L"No Display Name!";
  209. #define GLOBALFREE(x) { if((x) != NULL) {GlobalFree((void *)(x)); (x) = NULL;} }
  210. //--HrMAPICreateSizedAddressList------------------------------------------------
  211. // Create a sized address list.
  212. // -----------------------------------------------------------------------------
  213. HRESULT
  214. HrMAPICreateSizedAddressList(
  215. ULONG cEntries, // in - count of entries in address list
  216. LPADRLIST * lppAdrList) // out- pointer to address list pointer
  217. {
  218. HRESULT hr = NOERROR;
  219. SCODE sc = 0;
  220. ULONG cBytes = 0;
  221. *lppAdrList = NULL;
  222. cBytes = CbNewADRLIST(cEntries);
  223. sc = (*pMAPIAllocateBuffer)(cBytes, (void **)lppAdrList);
  224. if(FAILED(sc))
  225. {
  226. hr = HR_LOG(E_OUTOFMEMORY);
  227. goto cleanup;
  228. }
  229. // Initialize ADRLIST structure
  230. ZeroMemory(*lppAdrList, cBytes);
  231. (*lppAdrList)->cEntries = cEntries;
  232. cleanup:
  233. return hr;
  234. }
  235. //--HrMAPISetAddressList--------------------------------------------------------
  236. // Set an address list.
  237. // -----------------------------------------------------------------------------
  238. HRESULT HrMAPISetAddressList(
  239. ULONG iEntry, // in - index of address list entry
  240. ULONG cProps, // in - count of values in address list
  241. // entry
  242. LPSPropValue lpPropValues, // in - pointer to address list entry
  243. LPADRLIST lpAdrList) // i/o - pointer to address list pointer
  244. {
  245. HRESULT hr = NOERROR;
  246. SCODE sc = 0;
  247. LPSPropValue lpNewPropValues = NULL;
  248. // ULONG cBytes = 0;
  249. if(iEntry >= lpAdrList->cEntries)
  250. {
  251. hr = HR_LOG(E_FAIL);
  252. goto cleanup;
  253. }
  254. sc = (*pScDupPropset)(
  255. cProps,
  256. lpPropValues,
  257. (*pMAPIAllocateBuffer),
  258. &lpNewPropValues);
  259. if(FAILED(sc))
  260. {
  261. hr = HR_LOG(E_FAIL);
  262. goto cleanup;
  263. }
  264. if(lpAdrList->aEntries[iEntry].rgPropVals != NULL)
  265. {
  266. MAPIFREEBUFFER(lpAdrList->aEntries[iEntry].rgPropVals);
  267. }
  268. lpAdrList->aEntries[iEntry].cValues = cProps;
  269. lpAdrList->aEntries[iEntry].rgPropVals = lpNewPropValues;
  270. cleanup:
  271. return hr;
  272. }
  273. HRESULT HrGWResolveAddressW(
  274. LPABCONT lpGalABCont, // in - pointer to GAL container
  275. LPCWSTR lpszAddress, // in - pointer to proxy address
  276. BOOL * lpfMapiRecip, // out- MAPI recipient
  277. ULONG * lpcbEntryID, // out- count of bytes in entry ID
  278. LPENTRYID * lppEntryID) // out- pointer to entry ID
  279. {
  280. HRESULT hr = NOERROR;
  281. HRESULT hrT = 0;
  282. SCODE sc = 0;
  283. LPADRLIST lpAdrList = NULL;
  284. LPFlagList lpFlagList = NULL;
  285. SPropValue prop[2] = {0};
  286. ULONG cbEntryID = 0;
  287. LPENTRYID lpEntryID = NULL;
  288. static const SizedSPropTagArray(2, rgPropTags) =
  289. { 2,
  290. {
  291. PR_ENTRYID,
  292. PR_SEND_RICH_INFO
  293. }
  294. };
  295. *lpfMapiRecip = FALSE;
  296. *lpcbEntryID = 0;
  297. *lppEntryID = NULL;
  298. sc = (*pMAPIAllocateBuffer)( CbNewFlagList(1), (LPVOID*)&lpFlagList);
  299. if(FAILED(sc))
  300. {
  301. hr = HR_LOG(E_OUTOFMEMORY);
  302. goto cleanup;
  303. }
  304. lpFlagList->cFlags = 1;
  305. lpFlagList->ulFlag[0] = MAPI_UNRESOLVED;
  306. hr = HrMAPICreateSizedAddressList(1, &lpAdrList);
  307. if(FAILED(hr))
  308. {
  309. hr = HR_LOG(E_FAIL);
  310. goto cleanup;
  311. }
  312. prop[0].ulPropTag = PR_DISPLAY_NAME_W;
  313. prop[0].Value.lpszW = (LPWSTR)lpszAddress;
  314. prop[1].ulPropTag = PR_RECIPIENT_TYPE;
  315. prop[1].Value.ul = MAPI_TO;
  316. hr = HrMAPISetAddressList(
  317. 0,
  318. 2,
  319. prop,
  320. lpAdrList);
  321. if(FAILED(hr))
  322. {
  323. hr = HR_LOG(E_FAIL);
  324. goto cleanup;
  325. }
  326. hrT = lpGalABCont->ResolveNames(
  327. (LPSPropTagArray)&rgPropTags,
  328. EMS_AB_ADDRESS_LOOKUP,
  329. lpAdrList,
  330. lpFlagList);
  331. if(lpFlagList->ulFlag[0] != MAPI_RESOLVED)
  332. {
  333. if(lpFlagList->ulFlag[0] == MAPI_AMBIGUOUS)
  334. {
  335. hrT = MAPI_E_AMBIGUOUS_RECIP;
  336. }
  337. else
  338. {
  339. hrT = MAPI_E_NOT_FOUND;
  340. }
  341. }
  342. if(FAILED(hrT))
  343. {
  344. if(hrT == MAPI_E_NOT_FOUND)
  345. {
  346. hr = HR_LOG(EDK_E_NOT_FOUND);
  347. }
  348. else
  349. {
  350. hr = HR_LOG(E_FAIL);
  351. };
  352. goto cleanup;
  353. }
  354. cbEntryID = lpAdrList->aEntries[0].rgPropVals[0].Value.bin.cb;
  355. lpEntryID = (LPENTRYID)lpAdrList->aEntries[0].rgPropVals[0].Value.bin.lpb;
  356. sc = (*pMAPIAllocateBuffer)( cbEntryID, (LPVOID*)lppEntryID);
  357. if(FAILED(sc))
  358. {
  359. hr = HR_LOG(E_OUTOFMEMORY);
  360. goto cleanup;
  361. }
  362. CopyMemory(*lppEntryID, lpEntryID, cbEntryID);
  363. *lpcbEntryID = cbEntryID;
  364. *lpfMapiRecip = lpAdrList->aEntries[0].rgPropVals[1].Value.b;
  365. cleanup:
  366. MAPIFREEBUFFER(lpFlagList);
  367. FREEPADRLIST(lpAdrList);
  368. return hr;
  369. }
  370. //--HrFindExchangeGlobalAddressList-------------------------------------------------
  371. // Returns the entry ID of the global address list container in the address
  372. // book.
  373. // -----------------------------------------------------------------------------
  374. // CAVEAT: If this function is successful, you must free the buffer returned in lppeid.
  375. HRESULT
  376. HrFindExchangeGlobalAddressList(
  377. LPADRBOOK lpAdrBook, // in - address book pointer
  378. ULONG * lpcbeid, // out- pointer to count of bytes in entry ID
  379. LPENTRYID * lppeid) // out- pointer to entry ID pointer
  380. {
  381. HRESULT hr = NOERROR;
  382. ULONG ulObjType = 0;
  383. // ULONG i = 0;
  384. LPMAPIPROP lpRootContainer = NULL;
  385. LPMAPIPROP lpContainer = NULL;
  386. LPMAPITABLE lpContainerTable = NULL;
  387. LPSRowSet lpRows = NULL;
  388. ULONG cbContainerEntryId = 0;
  389. LPENTRYID lpContainerEntryId = NULL;
  390. LPSPropValue lpCurrProp = NULL;
  391. SRestriction SRestrictAnd[2] = {0};
  392. SRestriction SRestrictGAL = {0};
  393. SPropValue SPropID = {0};
  394. SPropValue SPropProvider = {0};
  395. BYTE muid[] = MUIDEMSAB;
  396. SizedSPropTagArray(1, rgPropTags) =
  397. {
  398. 1,
  399. {
  400. PR_ENTRYID,
  401. }
  402. };
  403. *lpcbeid = 0;
  404. *lppeid = NULL;
  405. // Open the root container of the address book
  406. hr = lpAdrBook->OpenEntry(
  407. 0,
  408. NULL,
  409. NULL,
  410. MAPI_DEFERRED_ERRORS,
  411. &ulObjType,
  412. (LPUNKNOWN FAR *)&lpRootContainer);
  413. if(FAILED(hr))
  414. {
  415. goto cleanup;
  416. }
  417. if(ulObjType != MAPI_ABCONT)
  418. {
  419. hr = E_FAIL;
  420. goto cleanup;
  421. }
  422. // Get the hierarchy table of the root container
  423. hr = ((LPABCONT)lpRootContainer)->GetHierarchyTable(
  424. MAPI_DEFERRED_ERRORS|CONVENIENT_DEPTH,
  425. &lpContainerTable);
  426. if(FAILED(hr))
  427. {
  428. goto cleanup;
  429. }
  430. // Restrict the table to the global address list (GAL)
  431. // ---------------------------------------------------
  432. // Initialize provider restriction to only Exchange providers
  433. SRestrictAnd[0].rt = RES_PROPERTY;
  434. SRestrictAnd[0].res.resProperty.relop = RELOP_EQ;
  435. SRestrictAnd[0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID;
  436. SPropProvider.ulPropTag = PR_AB_PROVIDER_ID;
  437. SPropProvider.Value.bin.cb = 16;
  438. SPropProvider.Value.bin.lpb = (LPBYTE)muid;
  439. SRestrictAnd[0].res.resProperty.lpProp = &SPropProvider;
  440. // Initialize container ID restriction to only GAL container
  441. SRestrictAnd[1].rt = RES_PROPERTY;
  442. SRestrictAnd[1].res.resProperty.relop = RELOP_EQ;
  443. SRestrictAnd[1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID;
  444. SPropID.ulPropTag = PR_EMS_AB_CONTAINERID;
  445. SPropID.Value.l = 0;
  446. SRestrictAnd[1].res.resProperty.lpProp = &SPropID;
  447. // Initialize AND restriction
  448. SRestrictGAL.rt = RES_AND;
  449. SRestrictGAL.res.resAnd.cRes = 2;
  450. SRestrictGAL.res.resAnd.lpRes = &SRestrictAnd[0];
  451. // Restrict the table to the GAL - only a single row should remain
  452. // Get the row corresponding to the GAL
  453. //
  454. // Query all the rows
  455. //
  456. hr = (*pHrQueryAllRows)(
  457. lpContainerTable,
  458. (LPSPropTagArray)&rgPropTags,
  459. &SRestrictGAL,
  460. NULL,
  461. 0,
  462. &lpRows);
  463. if(FAILED(hr) || (lpRows == NULL) || (lpRows->cRows != 1))
  464. {
  465. hr = E_FAIL;
  466. goto cleanup;
  467. }
  468. // Get the entry ID for the GAL
  469. lpCurrProp = &(lpRows->aRow[0].lpProps[0]);
  470. if(lpCurrProp->ulPropTag == PR_ENTRYID)
  471. {
  472. cbContainerEntryId = lpCurrProp->Value.bin.cb;
  473. lpContainerEntryId = (LPENTRYID)lpCurrProp->Value.bin.lpb;
  474. }
  475. else
  476. {
  477. hr = EDK_E_NOT_FOUND;
  478. goto cleanup;
  479. }
  480. hr = (*pMAPIAllocateBuffer)(cbContainerEntryId, (LPVOID *)lppeid);
  481. if(FAILED(hr))
  482. {
  483. *lpcbeid = 0;
  484. *lppeid = NULL;
  485. }
  486. else
  487. {
  488. CopyMemory(
  489. *lppeid,
  490. lpContainerEntryId,
  491. cbContainerEntryId);
  492. *lpcbeid = cbContainerEntryId;
  493. }
  494. cleanup:
  495. if (lpRootContainer)
  496. lpRootContainer->Release();
  497. if (lpContainerTable)
  498. lpContainerTable->Release();
  499. if (lpContainer)
  500. lpContainer->Release();
  501. (*pFreeProws)(lpRows);
  502. if(FAILED(hr))
  503. {
  504. (*pMAPIFreeBuffer)(*lppeid);
  505. *lpcbeid = 0;
  506. *lppeid = NULL;
  507. }
  508. return hr;
  509. }
  510. //--HrSearchGAL----------------------------------------------------------------
  511. // Look for the entry ID by searching for the DN in the global address list.
  512. //
  513. // RETURNS: hr == NOERROR Found
  514. // hr == EDK_E_NOT_FOUND DN Not Found
  515. // hr == (anything else) Other Error
  516. // -----------------------------------------------------------------------------
  517. static HRESULT HrSearchGAL(
  518. LPADRBOOK lpAdrBook, // in - address book (directory) to look in
  519. LPWSTR lpszDN, // in - object distinguished name
  520. ULONG * lpcbEntryID, // out- count of bytes in entry ID
  521. LPENTRYID * lppEntryID) // out- pointer to entry ID
  522. {
  523. HRESULT hr = NOERROR;
  524. LPWSTR lpszAddress = NULL;
  525. ULONG cbGALEntryID = 0;
  526. LPENTRYID lpGALEntryID = NULL;
  527. ULONG ulGALObjectType = 0;
  528. LPABCONT lpGAL = NULL;
  529. BOOL fMapiRecip = FALSE;
  530. // Initially zero out the return variables.
  531. *lpcbEntryID = 0;
  532. *lppEntryID = NULL;
  533. // Create an address string consisting of "EX:" followed by the DN.
  534. hr = (*pMAPIAllocateBuffer)(
  535. wcslen(EXCHANGE_ADDRTYPE L":") + wcslen(lpszDN) + 1,
  536. (void **)&lpszAddress);
  537. if (FAILED(hr))
  538. goto cleanup;
  539. wcscpy(lpszAddress, EXCHANGE_ADDRTYPE L":");
  540. wcscat(lpszAddress, lpszDN);
  541. // Open the global address list.
  542. hr = HrFindExchangeGlobalAddressList(
  543. lpAdrBook,
  544. &cbGALEntryID,
  545. &lpGALEntryID);
  546. if (FAILED(hr))
  547. goto cleanup;
  548. hr = lpAdrBook->OpenEntry(
  549. cbGALEntryID,
  550. lpGALEntryID,
  551. NULL,
  552. MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS,
  553. &ulGALObjectType,
  554. (LPUNKNOWN *) &lpGAL);
  555. if (FAILED(hr))
  556. goto cleanup;
  557. // Make sure it's the right object type.
  558. if (ulGALObjectType != MAPI_ABCONT)
  559. {
  560. //hr = HR_LOG(E_FAIL);
  561. goto cleanup;
  562. }
  563. // Resolve the address (returns EDK_E_NOT_FOUND if not found).
  564. hr = HrGWResolveAddressW(
  565. lpGAL,
  566. lpszAddress,
  567. &fMapiRecip,
  568. lpcbEntryID,
  569. lppEntryID);
  570. if (FAILED(hr))
  571. goto cleanup;
  572. cleanup:
  573. ULRELEASE(lpGAL);
  574. MAPIFREEBUFFER(lpGALEntryID);
  575. MAPIFREEBUFFER(lpszAddress);
  576. return hr;
  577. }
  578. //$--HrCreateDirEntryIdEx-------------------------------------------------------
  579. // Create a directory entry ID given the address of the object
  580. // in the directory.
  581. // -----------------------------------------------------------------------------
  582. HRESULT HrCreateDirEntryIdEx( // RETURNS: HRESULT
  583. IN LPADRBOOK lpAdrBook, // address book (directory) to look in
  584. IN LPWSTR lpszAddress, // object distinguished name
  585. OUT ULONG * lpcbEntryID, // count of bytes in entry ID
  586. OUT LPENTRYID * lppEntryID) // pointer to entry ID
  587. {
  588. HRESULT hr = NOERROR;
  589. // ULONG cbHierarchyEntryID = 0;
  590. // LPENTRYID lpHierarchyEntryID = NULL;
  591. ULONG ulEntryIDType = 0;
  592. // Initially zero out the return variables.
  593. *lpcbEntryID = 0;
  594. *lppEntryID = NULL;
  595. // Look for the DN in the global address list.
  596. hr = HrSearchGAL(
  597. lpAdrBook,
  598. lpszAddress,
  599. lpcbEntryID,
  600. lppEntryID);
  601. if (FAILED(hr))
  602. goto cleanup;
  603. // If the type was DT_AGENT or DT_ORGANIZATION, then we have to
  604. // do a further lookup in the hierarchy table to determine the
  605. // DN's real type.
  606. ulEntryIDType = ((LPDIR_ENTRYID) *lppEntryID)->ulType;
  607. cleanup:
  608. return hr;
  609. }
  610. //$--CbMultiSz------------------------------------------------------------------
  611. // Count of bytes in a REG_MULTI_SZ string (not including terminating NULL).
  612. // -----------------------------------------------------------------------------
  613. static DWORD CbMultiSz( // RETURNS: count of bytes
  614. IN LPWSTR lpszRegMultiSz) // REG_MULTI_SZ string
  615. {
  616. // HRESULT hr = NOERROR;
  617. DWORD cch = 0;
  618. DWORD cb = 0;
  619. LPWSTR lpsz = NULL;
  620. if(lpszRegMultiSz == NULL)
  621. {
  622. goto cleanup;
  623. }
  624. lpsz = lpszRegMultiSz;
  625. while(*lpsz)
  626. {
  627. cch = lstrlenW(lpsz);
  628. cch++;
  629. cb += cch * sizeof(WCHAR);
  630. lpsz += cch;
  631. }
  632. cleanup:
  633. return(cb);
  634. }
  635. //$--HrGetRegistryValue---------------------------------------------------------
  636. // Get a registry value - allocating memory to hold it.
  637. // -----------------------------------------------------------------------------
  638. static HRESULT HrGetRegistryValue( // RETURNS: return code
  639. IN HKEY hk, // the key.
  640. IN LPWSTR lpszValue, // value name in key.
  641. OUT DWORD * lpType, // where to put type info.
  642. OUT DWORD * lpcb, // where to put byte count info.
  643. OUT LPVOID * lppData) // where to put the data.
  644. {
  645. HRESULT hr = E_FAIL;
  646. LONG lRet = 0;
  647. *lppData = NULL;
  648. //
  649. // Get its size
  650. //
  651. lRet = RegQueryValueEx(
  652. hk,
  653. lpszValue,
  654. NULL,
  655. lpType,
  656. NULL,
  657. lpcb);
  658. if(lRet != ERROR_SUCCESS)
  659. {
  660. hr = HR_LOG(HRESULT_FROM_WIN32(lRet));
  661. goto cleanup;
  662. }
  663. //
  664. // Allocate memory for it
  665. //
  666. *lppData = (LPVOID)GlobalAlloc(GMEM_FIXED, *lpcb);
  667. if(*lppData == NULL)
  668. {
  669. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  670. goto cleanup;
  671. }
  672. //
  673. // Get the current value
  674. //
  675. lRet = RegQueryValueEx(hk, lpszValue, NULL, lpType, (UCHAR*)*lppData, lpcb);
  676. if(lRet != ERROR_SUCCESS)
  677. {
  678. hr = HR_LOG(HRESULT_FROM_WIN32(lRet));
  679. goto cleanup;
  680. }
  681. hr = NOERROR;
  682. cleanup:
  683. if(FAILED(hr))
  684. {
  685. if(lppData != NULL)
  686. {
  687. GLOBALFREE(*lppData);
  688. }
  689. }
  690. return hr;
  691. }
  692. //--FCsvGetField---------------------------------------------------------------
  693. // Given a record and a field separator and a field number, this routine
  694. // will extract the field requested.
  695. //------------------------------------------------------------------------------
  696. static BOOL FCsvGetField( // RETURNS: TRUE/FALSE
  697. IN WORD wLen, // maximum length of the field to extract
  698. IN WORD wFieldNum, // field number we want from the record
  699. IN CHAR cFieldSeparator, // character to use as a field separator
  700. IN CHAR *lpszRecord, // record to extract the field from
  701. OUT CHAR *lpszField) // field we have extracted
  702. {
  703. // HRESULT hr = NOERROR;
  704. BOOL fRet = FALSE;
  705. // CHAR *lpszBeginField = lpszField;
  706. while((wFieldNum > 0) && (*lpszRecord != 0))
  707. {
  708. // If we found a field separator, increment current field
  709. if(*lpszRecord == cFieldSeparator)
  710. {
  711. wFieldNum--;
  712. }
  713. // If we are at the desired field, copy the current character into it
  714. else if(wFieldNum == 1 && wLen > 1)
  715. {
  716. *lpszField = *lpszRecord;
  717. lpszField++;
  718. wLen--;
  719. }
  720. lpszRecord++;
  721. }
  722. *lpszField = 0;
  723. // If the requested field # existed, return True,
  724. // otherwise we ran out of fields - return False
  725. if(wFieldNum <= 1)
  726. {
  727. fRet = TRUE;
  728. }
  729. else
  730. {
  731. fRet = FALSE;
  732. }
  733. return(fRet);
  734. }
  735. //$--FCsvGetRecord--------------------------------------------------------------
  736. // Given a buffer, the buffer's length and a file handle, this
  737. // function fills the buffer with a single line read from the file.
  738. // The NL & CR are NOT put into the buffer. No unprintable characters are
  739. // placed in the buffer
  740. // -----------------------------------------------------------------------------
  741. BOOL FCsvGetRecord( // RETURNS: TRUE/FALSE
  742. IN WORD wBufferLen, // length of the record buffer
  743. IN HANDLE hFile, // file handle to read from
  744. OUT CHAR *lpszBuffer) // record we have retrieved
  745. {
  746. // HRESULT hr = NOERROR;
  747. DWORD dwBytesRead = 0;
  748. BOOL fReadData = FALSE;
  749. while((ReadFile(hFile, (LPVOID)lpszBuffer, 1, &dwBytesRead, NULL) == TRUE) &&
  750. (wBufferLen > 1) && (*lpszBuffer != '\n') && (dwBytesRead > 0))
  751. {
  752. fReadData = TRUE;
  753. // Only store character in buffer if it is printable!
  754. if((isprint(*lpszBuffer)) || (*lpszBuffer == EXCHINST_DELIM))
  755. {
  756. lpszBuffer++;
  757. wBufferLen--;
  758. }
  759. }
  760. // If a given record is too long it is a problem!!!
  761. if(wBufferLen <= 0)
  762. {
  763. fReadData = FALSE;
  764. }
  765. *lpszBuffer = 0;
  766. return(fReadData);
  767. }
  768. //$--HrEDKExportObject----------------------------------------------------------
  769. // This function will export an object from an Exchange server.
  770. // -----------------------------------------------------------------------------
  771. static HRESULT HrEDKExportObject( // RETURNS: return code
  772. IN LPWSTR lpszServer, // server name
  773. IN LPWSTR lpszBasePoint, // base point
  774. IN DWORD dwControlFlags, // control flags
  775. IN LPWSTR *rgpszClasses, // classes
  776. IN LPWSTR lpszObjectAttributes, // list of attributes to export
  777. OUT LPWSTR lpszTempName) // temporary file name
  778. {
  779. HRESULT hr = E_FAIL;
  780. ULONG cErrors = 0;
  781. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  782. CHAR szTempPath[MAX_PATH+1] = {0};
  783. DWORD dwNumberOfBytesWritten = 0;
  784. BEXPORT_PARMS BExportParms = {0};
  785. BOOL fRet = FALSE;
  786. // Get temporary directory path
  787. if(!GetTempPath(MAX_PATH, szTempPath))
  788. {
  789. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  790. goto cleanup;
  791. }
  792. // Get temporary file name
  793. if(!GetTempFileName(szTempPath, FILE_PREFIX, 0, lpszTempName))
  794. {
  795. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  796. goto cleanup;
  797. }
  798. // Create the temporary file
  799. hTempFile = CreateFile(lpszTempName,
  800. GENERIC_WRITE,
  801. 0,
  802. (LPSECURITY_ATTRIBUTES)NULL,
  803. CREATE_ALWAYS,
  804. FILE_ATTRIBUTE_NORMAL,
  805. (HANDLE)NULL);
  806. // Check to see if temporary file was created...
  807. if(hTempFile == INVALID_HANDLE_VALUE)
  808. {
  809. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  810. goto cleanup;
  811. }
  812. // Write data to the temporary file & close it
  813. fRet = WriteFile(
  814. hTempFile,
  815. lpszObjectAttributes,
  816. lstrlen(lpszObjectAttributes)*sizeof(CHAR),
  817. &dwNumberOfBytesWritten,
  818. NULL);
  819. if(fRet == FALSE)
  820. {
  821. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  822. goto cleanup;
  823. }
  824. fRet = WriteFile(
  825. hTempFile,
  826. NEW_LINE,
  827. lstrlen(NEW_LINE)*sizeof(CHAR),
  828. &dwNumberOfBytesWritten,
  829. NULL);
  830. if(fRet == FALSE)
  831. {
  832. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  833. goto cleanup;
  834. }
  835. CLOSEHANDLE(hTempFile);
  836. //
  837. // Batch Export
  838. //
  839. BExportParms.dwDAPISignature = DAPI_SIGNATURE;
  840. BExportParms.dwFlags = dwControlFlags |
  841. DAPI_MODIFY_REPLACE_PROPERTIES |
  842. DAPI_SUPPRESS_PROGRESS |
  843. DAPI_SUPPRESS_COMPLETION |
  844. DAPI_SUPPRESS_ARCHIVES |
  845. DAPI_IMPORT_NO_ERR_FILE;
  846. BExportParms.pszExportFile = lpszTempName;
  847. BExportParms.pszBasePoint = lpszBasePoint;
  848. BExportParms.pszDSAName = lpszServer;
  849. BExportParms.rgpszClasses = rgpszClasses;
  850. BExportParms.chColSep = EXCHINST_DELIM;
  851. BExportParms.chQuote = EXCHINST_QUOTE;
  852. BExportParms.chMVSep = EXCHINST_MV_SEP;
  853. cErrors = (*pBatchExport)(&BExportParms);
  854. if(cErrors == 0)
  855. {
  856. hr = NOERROR;
  857. }
  858. else
  859. {
  860. hr = HR_LOG(E_FAIL);
  861. }
  862. cleanup:
  863. CLOSEHANDLE(hTempFile);
  864. return hr;
  865. }
  866. //$--HrEDKEnumDNs---------------------------------------------------------------
  867. // Enumerates the distinguished name(s).
  868. // -----------------------------------------------------------------------------
  869. static HRESULT HrEDKEnumDNs( // RETURNS: return code
  870. IN LPWSTR lpszRootDN, // distinguished name of DIT root
  871. IN LPWSTR lpszServer, // server name
  872. IN DWORD dwControlFlags, // control flags
  873. IN LPWSTR *rgpszClasses, // classes
  874. OUT LPWSTR *lppszDNs) // distinguished names
  875. {
  876. HRESULT hr = NOERROR;
  877. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  878. CHAR szObjectAttributes[MAX_CSV_LINE_SIZ] = {0};
  879. // CHAR szAttributeValues[MAX_CSV_LINE_SIZ] = {0};
  880. // CHAR szCurRecord[MAX_CSV_LINE_SIZ] = {0};
  881. CHAR szCurLine[MAX_CSV_LINE_SIZ] = {0};
  882. CHAR szCurField[MAX_PATH+1] = {0};
  883. CHAR szTempName[MAX_PATH+1] = {0};
  884. WORD wAttribField = MAX_WORD;
  885. WORD wCurrField = 0;
  886. LPWSTR lpsz = NULL;
  887. ULONG ulCurrOffset = 0;
  888. *lppszDNs = NULL;
  889. BEGIN_CSV_LINE (szObjectAttributes, OBJ_CLASS);
  890. APPEND_CSV_LINE (szObjectAttributes, OBJ_DIST_NAME);
  891. hr = HrEDKExportObject(
  892. lpszServer,
  893. lpszRootDN,
  894. dwControlFlags,
  895. rgpszClasses,
  896. szObjectAttributes,
  897. szTempName);
  898. if(SUCCEEDED(hr))
  899. {
  900. // Open the temporary file
  901. hTempFile = CreateFile(
  902. szTempName,
  903. GENERIC_READ,
  904. 0,
  905. (LPSECURITY_ATTRIBUTES)NULL,
  906. OPEN_EXISTING,
  907. FILE_FLAG_DELETE_ON_CLOSE,
  908. (HANDLE)NULL);
  909. if(hTempFile == INVALID_HANDLE_VALUE)
  910. {
  911. hr = HR_LOG(E_FAIL);
  912. goto cleanup;
  913. }
  914. //
  915. // The first line contains the list of fields - find which field has
  916. // the attribute we are looking for.
  917. //
  918. FCsvGetRecord(MAX_CSV_LINE_SIZ, hTempFile, szCurLine);
  919. for(
  920. wCurrField = 1;
  921. FCsvGetField(
  922. MAX_PATH,
  923. wCurrField,
  924. EXCHINST_DELIM,
  925. szCurLine,
  926. szCurField);
  927. wCurrField++)
  928. {
  929. if(wcscmp(szCurField, OBJ_DIST_NAME) == 0)
  930. {
  931. wAttribField = wCurrField;
  932. break;
  933. }
  934. }
  935. // Was the field exported & found above?
  936. if(wAttribField == MAX_WORD)
  937. {
  938. hr = HR_LOG(E_FAIL);
  939. goto cleanup;
  940. }
  941. ulCurrOffset = 0;
  942. while(FCsvGetRecord (MAX_CSV_LINE_SIZ, hTempFile, szCurLine))
  943. {
  944. FCsvGetField(
  945. MAX_PATH,
  946. wAttribField,
  947. EXCHINST_DELIM,
  948. szCurLine,
  949. szCurField);
  950. if( *szCurField)
  951. {
  952. if(lpsz == NULL)
  953. {
  954. lpsz = (LPWSTR)GlobalAlloc(
  955. GMEM_FIXED,
  956. cbStrLen(szCurField) + sizeof(CHAR));
  957. }
  958. else
  959. {
  960. lpsz = (LPWSTR)GlobalReAlloc(
  961. lpsz,
  962. GlobalSize(lpsz) + cbStrLen(szCurField),
  963. GMEM_MOVEABLE);
  964. }
  965. if(lpsz == NULL)
  966. {
  967. hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError()));
  968. goto cleanup;
  969. }
  970. lstrcpy(&lpsz[ulCurrOffset], szCurField);
  971. ulCurrOffset += cbStrLen(szCurField);
  972. lpsz[ulCurrOffset] = 0;
  973. }
  974. }
  975. }
  976. *lppszDNs = lpsz;
  977. cleanup:
  978. CLOSEHANDLE(hTempFile);
  979. if(FAILED(hr))
  980. {
  981. GLOBALFREE(*lppszDNs);
  982. }
  983. return hr;
  984. }
  985. //$--HrEnumOrganizations-----------------------------------------------------
  986. // Enumerates the organization name(s).
  987. // -----------------------------------------------------------------------------
  988. HRESULT HrEnumOrganizations( // RETURNS: return code
  989. IN LPWSTR lpszRootDN, // distinguished name of DIT root
  990. IN LPWSTR lpszServer, // server name
  991. OUT LPWSTR *lppszOrganizations) // organizations
  992. {
  993. HRESULT hr = NOERROR;
  994. LPWSTR rgpszClasses[2] = {0};
  995. rgpszClasses[0] = ORGANIZATION;
  996. rgpszClasses[1] = NULL;
  997. hr = HrEDKEnumDNs(
  998. lpszRootDN,
  999. lpszServer,
  1000. DAPI_EXPORT_SUBTREE,
  1001. rgpszClasses,
  1002. lppszOrganizations);
  1003. return hr;
  1004. }
  1005. //$--HrEnumSites-------------------------------------------------------------
  1006. // Enumerates the site name(s).
  1007. // -----------------------------------------------------------------------------
  1008. HRESULT HrEnumSites( // RETURNS: return code
  1009. IN LPWSTR lpszServer, // server name
  1010. IN LPWSTR lpszOrganizationDN, // distinguished name of organization
  1011. OUT LPWSTR *lppszSites) // sites
  1012. {
  1013. HRESULT hr = NOERROR;
  1014. LPWSTR rgpszClasses[2] = {0};
  1015. rgpszClasses[0] = ORGANIZATIONAL_UNIT;
  1016. rgpszClasses[1] = NULL;
  1017. hr = HrEDKEnumDNs(
  1018. lpszOrganizationDN,
  1019. lpszServer,
  1020. 0,
  1021. rgpszClasses,
  1022. lppszSites);
  1023. return hr;
  1024. }
  1025. //$--HrEnumContainers--------------------------------------------------------
  1026. // Enumerates the container name(s).
  1027. // -----------------------------------------------------------------------------
  1028. HRESULT HrEnumContainers( // RETURNS: return code
  1029. IN LPWSTR lpszServer, // server name
  1030. IN LPWSTR lpszSiteDN, // distinguished name of site
  1031. IN BOOL fSubtree, // sub-tree?
  1032. OUT LPWSTR *lppszContainers) // containers
  1033. {
  1034. HRESULT hr = NOERROR;
  1035. LPWSTR rgpszClasses[2] = {0};
  1036. DWORD dwControlFlags = 0;
  1037. rgpszClasses[0] = CONTAINER;
  1038. rgpszClasses[1] = NULL;
  1039. if(fSubtree == TRUE)
  1040. {
  1041. dwControlFlags = DAPI_EXPORT_SUBTREE;
  1042. }
  1043. hr = HrEDKEnumDNs(
  1044. lpszSiteDN,
  1045. lpszServer,
  1046. dwControlFlags,
  1047. rgpszClasses,
  1048. lppszContainers);
  1049. return hr;
  1050. }
  1051. /**/