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.

2229 lines
80 KiB

  1. /*
  2. * LDIF.C
  3. *
  4. * Migrate LDIF <-> WAB
  5. *
  6. * Copyright 1997 Microsoft Corporation. All Rights Reserved.
  7. *
  8. * To Do:
  9. * ObjectClass recognition
  10. * Attribute mapping
  11. * Groups
  12. * Base64
  13. * URLs
  14. * Reject Change List LDIF
  15. *
  16. */
  17. #include "_comctl.h"
  18. #include <windows.h>
  19. #include <commctrl.h>
  20. #include <mapix.h>
  21. #include <wab.h>
  22. #include <wabguid.h>
  23. #include <wabdbg.h>
  24. #include <wabmig.h>
  25. #include <emsabtag.h>
  26. #include "wabimp.h"
  27. #include "..\..\wab32res\resrc2.h"
  28. #include "dbgutil.h"
  29. #include "initguid.h"
  30. #include <shlwapi.h>
  31. #define CR_CHAR 0x0d
  32. #define LF_CHAR 0x0a
  33. #define CCH_READ_BUFFER 1024
  34. #define NUM_ITEM_SLOTS 32
  35. BOOL decodeBase64(char * bufcoded, char * pbuffdecoded, DWORD * pcbDecoded);
  36. // for conferencing stuff
  37. #define CHANGE_PROP_TYPE(ulPropTag, ulPropType) \
  38. (((ULONG)0xFFFF0000 & ulPropTag) | ulPropType)
  39. HRESULT HrLoadPrivateWABProps(LPADRBOOK );
  40. /*
  41. - The following IDs and tags are for the conferencing named properties
  42. -
  43. - The GUID for these props is PS_Conferencing
  44. */
  45. DEFINE_OLEGUID(PS_Conferencing, 0x00062004, 0, 0);
  46. enum _ConferencingTags
  47. {
  48. prWABConfServers = 0,
  49. prWABConfMax
  50. };
  51. #define CONF_SERVERS 0x8056
  52. #define OLK_NAMEDPROPS_START CONF_SERVERS
  53. ULONG PR_SERVERS;
  54. SizedSPropTagArray(prWABConfMax, ptaUIDetlsPropsConferencing);
  55. // end conferencing duplication
  56. // Index into LDIF_ATTR_TABLE
  57. //
  58. // IMPORTANT: This is an intentionally ordered list!
  59. // Within synonyms, the earlier attributes listed take precedence over those that follow. For
  60. // example, if the record contains both "co" and "o" attributes, the value in the "co" attribute
  61. // will be used for PR_COMPANY_NAME.
  62. typedef enum _LDIF_ATTRIBUTES {
  63. // PR_OBJECT_TYPE
  64. ela_objectclass = 0, // object class (required)
  65. // PR_COUNTRY
  66. ela_c, // country
  67. ela_countryname,
  68. // PR_DISPLAY_NAME
  69. ela_display_name, // (Microsoft servers use this)
  70. ela_cn, // common name (display name)
  71. ela_commonName, // (display name)
  72. // PR_COMPANY_NAME
  73. ela_co, // company
  74. ela_organizationName, // (company)
  75. ela_o, // organization (company)
  76. // PR_MIDDLE_NAME
  77. ela_initials,
  78. // PR_SURNAME
  79. ela_sn, // surname
  80. ela_surname,
  81. // PR_GIVEN_NAME
  82. ela_givenname,
  83. ela_uid, // (given name) ?
  84. // PR_DEPARTMENT_NAME
  85. ela_department,
  86. ela_ou, // organizational unit (department)
  87. ela_organizationalUnitName, // (department)
  88. // PR_COMMENT
  89. ela_comment,
  90. ela_description, // description
  91. ela_info, // info
  92. // PR_LOCALITY
  93. ela_l, // locality (city)
  94. ela_locality, // locality (city)
  95. // no mapping
  96. ela_dn, // distinguished name
  97. // PR_NICKNAME
  98. ela_xmozillanickname, // Netscape nickname
  99. // no mapping
  100. ela_conferenceInformation, // conference server
  101. ela_xmozillaconference, // Netscape conference server
  102. // PR_HOME_FAX_NUMBER
  103. ela_facsimiletelephonenumber, // home fax number
  104. // PR_BUSINESS_FAX_NUMBER
  105. ela_OfficeFax,
  106. // PR_BUSINESS_TELEPHONE_NUMBER
  107. ela_telephonenumber,
  108. // PR_HOME_TELEPHONE_NUMBER
  109. ela_homephonenumber,
  110. // PR_MOBILE_TELEPHONE_NUMBER
  111. ela_mobile, // cellular phone number
  112. // PR_PAGER_TELEPHONE_NUMBER
  113. ela_OfficePager,
  114. ela_pager,
  115. // PR_OFFICE_LOCATION
  116. ela_physicalDeliveryOfficeName, // office location
  117. // PR_HOME_ADDRESS_STREET
  118. ela_homePostalAddress,
  119. // PR_STREET_ADDRESS
  120. ela_streetAddress, // business street address
  121. ela_street, // business street address
  122. ela_postalAddress, // business street address
  123. // PR_STATE_OR_PROVINCE
  124. ela_st, // business address state
  125. // PR_POST_OFFICE_BOX
  126. ela_postOfficeBox, // business PO Box
  127. // PR_POSTAL_CODE
  128. ela_postalcode, // business address zip code
  129. // PR_PERSONAL_HOME_PAGE
  130. ela_homepage, // personal home page
  131. // PR_BUSINESS_HOME_PAGE
  132. ela_URL, // business home page
  133. // PR_EMAIL_ADDRESS
  134. ela_mail, // email address
  135. // PR_CONTACT_EMAIL_ADDRESSES
  136. ela_otherMailbox, // secondary email addresses
  137. // PR_TITLE
  138. ela_title, // title
  139. // no mapping
  140. ela_member, // DL member
  141. // no mapping
  142. ela_userCertificate, // certificate
  143. // no mapping
  144. ela_labeledURI, // labelled URI URL
  145. // no mapping
  146. ela_xmozillauseconferenceserver, // Netscape conference info
  147. // no mapping
  148. ela_xmozillausehtmlmail, // Netscape HTML mail flag
  149. ela_Max,
  150. } LDIF_ATTRIBUTES, *LPLDIF_ATTRIBUTES;
  151. typedef struct _LDIF_ATTR_TABLE {
  152. const BYTE * lpName; // LDIF attribute name
  153. ULONG index; // attribute index within LDIF record
  154. ULONG ulPropTag; // prop tag mapping
  155. ULONG ulPropIndex; // index in prop array
  156. } LDIF_ATTR_TABLE, *LPLDIF_ATTR_TABLE;
  157. typedef enum _LDIF_PROPERTIES {
  158. elp_OBJECT_TYPE,
  159. elp_DISPLAY_NAME,
  160. elp_EMAIL_ADDRESS,
  161. elp_SURNAME,
  162. elp_GIVEN_NAME,
  163. elp_TITLE,
  164. elp_COMPANY_NAME,
  165. elp_OFFICE_LOCATION,
  166. elp_HOME_ADDRESS_STREET,
  167. elp_STREET_ADDRESS,
  168. elp_STATE_OR_PROVINCE,
  169. elp_POST_OFFICE_BOX,
  170. elp_POSTAL_CODE,
  171. elp_LOCALITY,
  172. elp_COUNTRY,
  173. elp_MIDDLE_NAME,
  174. elp_DEPARTMENT_NAME,
  175. elp_COMMENT,
  176. elp_NICKNAME,
  177. elp_HOME_FAX_NUMBER,
  178. elp_BUSINESS_FAX_NUMBER,
  179. elp_BUSINESS_TELEPHONE_NUMBER,
  180. elp_HOME_TELEPHONE_NUMBER,
  181. elp_MOBILE_TELEPHONE_NUMBER,
  182. elp_PAGER_TELEPHONE_NUMBER,
  183. elp_PERSONAL_HOME_PAGE,
  184. elp_BUSINESS_HOME_PAGE,
  185. elp_CONTACT_EMAIL_ADDRESSES,
  186. elp_CONFERENCE_SERVERS,
  187. elp_Max
  188. } LDIF_ATTRIBUTES, *LPLDIF_ATTRIBUTES;
  189. // Must have
  190. // PR_DISPLAY_NAME
  191. #define NUM_MUST_HAVE_PROPS 1
  192. typedef enum _LDIF_DATA_TYPE {
  193. LDIF_ASCII,
  194. LDIF_BASE64,
  195. LDIF_URL
  196. } LDIF_DATA_TYPE, *LPLDIF_DATA_TYPE;
  197. typedef struct _LDIF_RECORD_ATTRIBUTE {
  198. LPBYTE lpName;
  199. LPBYTE lpData;
  200. ULONG cbData;
  201. LDIF_DATA_TYPE Type;
  202. } LDIF_RECORD_ATTRIBUTE, * LPLDIF_RECORD_ATTRIBUTE;
  203. const TCHAR szLDIFFilter[] = "*.ldf;*.ldif";
  204. const TCHAR szLDIFExt[] = "ldf";
  205. // LDAP attribute names
  206. const BYTE sz_c[] = "c";
  207. const BYTE sz_cn[] = "cn";
  208. const BYTE sz_co[] = "co";
  209. const BYTE sz_comment[] = "comment";
  210. const BYTE sz_commonName[] = "commonName";
  211. const BYTE sz_conferenceInformation[] = "conferenceInformation";
  212. const BYTE sz_countryname[] = "countryname";
  213. const BYTE sz_department[] = "department";
  214. const BYTE sz_description[] = "description";
  215. const BYTE sz_display_name[] = "display-name";
  216. const BYTE sz_dn[] = "dn";
  217. const BYTE sz_facsimiletelephonenumber[] = "facsimiletelephonenumber";
  218. const BYTE sz_givenname[] = "givenname";
  219. const BYTE sz_homePostalAddress[] = "homePostalAddress";
  220. const BYTE sz_homepage[] = "homepage";
  221. const BYTE sz_info[] = "info";
  222. const BYTE sz_initials[] = "initials";
  223. const BYTE sz_l[] = "l";
  224. const BYTE sz_labeledURI[] = "labeledURI";
  225. const BYTE sz_locality[] = "locality";
  226. const BYTE sz_mail[] = "mail";
  227. const BYTE sz_member[] = "member";
  228. const BYTE sz_mobile[] = "mobile";
  229. const BYTE sz_o[] = "o";
  230. const BYTE sz_objectclass[] = "objectclass";
  231. const BYTE sz_OfficeFax[] = "OfficeFax";
  232. const BYTE sz_OfficePager[] = "OfficePager";
  233. const BYTE sz_organizationName[] = "organizationName";
  234. const BYTE sz_organizationalUnitName[] = "organizationalUnitName";
  235. const BYTE sz_otherMailbox[] = "otherMailbox";
  236. const BYTE sz_ou[] = "ou";
  237. const BYTE sz_pager[] = "pager";
  238. const BYTE sz_physicalDeliveryOfficeName[] = "physicalDeliveryOfficeName";
  239. const BYTE sz_postOfficeBox[] = "postOfficeBox";
  240. const BYTE sz_postalAddress[] = "postalAddress";
  241. const BYTE sz_postalcode[] = "postalcode";
  242. const BYTE sz_sn[] = "sn";
  243. const BYTE sz_st[] = "st";
  244. const BYTE sz_streetAddress[] = "streetAddress";
  245. const BYTE sz_street[] = "street";
  246. const BYTE sz_surname[] = "surname";
  247. const BYTE sz_telephonenumber[] = "telephonenumber";
  248. const BYTE sz_homephonenumber[] = "homephone";
  249. const BYTE sz_title[] = "title";
  250. const BYTE sz_uid[] = "uid";
  251. const BYTE sz_URL[] = "URL";
  252. const BYTE sz_userCertificate[] = "userCertificate";
  253. const BYTE sz_xmozillaconference[] = "xmozillaconference";
  254. const BYTE sz_xmozillanickname[] = "xmozillanickname";
  255. const BYTE sz_xmozillauseconferenceserver[] = "xmozillauseconferenceserver";
  256. const BYTE sz_xmozillausehtmlmail[] = "xmozillausehtmlmail";
  257. // LDAP objectclass values
  258. const BYTE sz_groupOfNames[] = "groupOfNames";
  259. const BYTE sz_person[] = "person";
  260. const BYTE sz_organizationalPerson[] = "organizationalPerson";
  261. // since defs aren't shared -- these are also defined in ui_detls.c
  262. const LPTSTR szCallto = TEXT("callto://");
  263. const LPTSTR szFwdSlash = "/";
  264. BOOL HandleImportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
  265. LPTSTR lpEmailAddress, LPWAB_IMPORT_OPTIONS lpImportOptions);
  266. BOOL HandleExportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
  267. LPTSTR lpEmailAddress, LPWAB_EXPORT_OPTIONS lpExportOptions);
  268. /***************************************************************************
  269. Name : FreeLDIFRecord
  270. Purpose : Frees an LDIF record structure
  271. Parameters: lpLDIFRecord -> record to clean up
  272. ulAttributes = number of attributes in lpLDIFRecord
  273. Returns : none
  274. Comment :
  275. ***************************************************************************/
  276. void FreeLDIFRecord(LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord, ULONG ulAttributes) {
  277. ULONG i;
  278. if (lpLDIFRecord) {
  279. for (i = 0; i < ulAttributes; i++) {
  280. if (lpLDIFRecord[i].lpName) {
  281. LocalFree(lpLDIFRecord[i].lpName);
  282. lpLDIFRecord[i].lpName = NULL;
  283. }
  284. if (lpLDIFRecord[i].lpData) {
  285. LocalFree(lpLDIFRecord[i].lpData);
  286. lpLDIFRecord[i].lpData = NULL;
  287. }
  288. }
  289. LocalFree(lpLDIFRecord);
  290. }
  291. }
  292. /***************************************************************************
  293. Name : OpenLDIFFile
  294. Purpose : Opens a LDIF file for import
  295. Parameters: hwnd = main dialog window
  296. lpFileName = filename to create
  297. lphFile -> returned file handle
  298. Returns : HRESULT
  299. Comment :
  300. ***************************************************************************/
  301. HRESULT OpenLDIFFile(HWND hwnd, LPTSTR lpFileName, LPHANDLE lphFile) {
  302. LPTSTR lpFilter;
  303. TCHAR szFileName[MAX_PATH + 1] = "";
  304. OPENFILENAME ofn;
  305. HANDLE hFile = INVALID_HANDLE_VALUE;
  306. HRESULT hResult = hrSuccess;
  307. DWORD ec;
  308. if (INVALID_HANDLE_VALUE == (hFile = CreateFile(lpFileName,
  309. GENERIC_READ,
  310. 0, // sharing
  311. NULL,
  312. CREATE_NEW,
  313. FILE_FLAG_SEQUENTIAL_SCAN,
  314. NULL))) {
  315. ec = GetLastError();
  316. DebugTrace("CreateFile(%s) -> %u\n", lpFileName, ec);
  317. switch (ec) {
  318. case ERROR_FILE_NOT_FOUND:
  319. case ERROR_PATH_NOT_FOUND:
  320. default:
  321. ShowMessageBoxParam(hwnd, IDE_LDIF_IMPORT_FILE_ERROR, MB_ICONERROR, lpFileName);
  322. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  323. break;
  324. }
  325. }
  326. if (! hResult) {
  327. *lphFile = hFile;
  328. }
  329. return(hResult);
  330. }
  331. /***************************************************************************
  332. Name : ReadLDIFLine
  333. Purpose : Reads a line from and LDIF file
  334. Parameters: hFile = File handle
  335. lppBuffer -> In/Out start of read buffer (return line data here)
  336. lpcbBuffer = In/Out size of buffer
  337. Returns : number of bytes read from file
  338. Comment :
  339. ***************************************************************************/
  340. ULONG ReadLDIFLine(HANDLE hFile, LPBYTE * lppBuffer, LPULONG lpcbBuffer) {
  341. ULONG cbRead = 0;
  342. ULONG cbReadFile = 0;
  343. BOOL fDone = FALSE;
  344. BOOL fColumn1 = TRUE;
  345. BOOL fComment = FALSE;
  346. BOOL fComent = FALSE;
  347. ULONG ulSavePosition = 0;
  348. LPBYTE lpRead = *lppBuffer; // current read pointer
  349. LPBYTE lpT;
  350. while (! fDone) {
  351. if (cbRead >= (*lpcbBuffer - 1)) { // leave room for null
  352. ULONG cbOffset = (ULONG) (lpRead - *lppBuffer);
  353. // Buffer is too small. Reallocate!
  354. *lpcbBuffer += CCH_READ_BUFFER;
  355. if (! (lpT = LocalReAlloc(*lppBuffer, *lpcbBuffer, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
  356. DebugTrace("LocalReAlloc(%u) -> %u\n", *lpcbBuffer, GetLastError());
  357. break;
  358. }
  359. *lppBuffer = lpT;
  360. lpRead = *lppBuffer + cbOffset;
  361. }
  362. if ((! ReadFile(hFile,
  363. lpRead,
  364. 1, // 1 character at a time
  365. &cbReadFile,
  366. NULL)) || cbReadFile == 0) {
  367. DebugTrace("ReadFile -> EOF\n");
  368. fDone = TRUE;
  369. } else {
  370. cbReadFile++;
  371. // Got a character
  372. // Is it interesting?
  373. switch (*lpRead) {
  374. case '#': // Comment line
  375. if (fColumn1) {
  376. // This is a comment line. Dump the whole line
  377. fComment = TRUE;
  378. } else {
  379. cbRead++;
  380. lpRead++;
  381. }
  382. fColumn1 = FALSE;
  383. break;
  384. case ' ':
  385. if (fColumn1 || fComment) {
  386. // This is a continuation or a comment, eat this space.
  387. } else {
  388. cbRead++;
  389. lpRead++;
  390. }
  391. fColumn1 = FALSE;
  392. break;
  393. case '\n': // LDIF SEP character
  394. if (fColumn1) {
  395. // This is not a continuation, we've gone too far. Back up!
  396. if (ulSavePosition) {
  397. if (0xFFFFFFFF == (SetFilePointer(hFile, ulSavePosition, NULL, FILE_BEGIN))) {
  398. DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
  399. return(ResultFromScode(MAPI_E_CALL_FAILED));
  400. }
  401. }
  402. fDone = TRUE;
  403. } else {
  404. fColumn1 = TRUE;
  405. fComment = FALSE;
  406. // Should check if next line starts with continuation character (space)
  407. // Save the current position in case it isn't.
  408. if (0xFFFFFFFF == (ulSavePosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT))) {
  409. DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
  410. }
  411. }
  412. break;
  413. case '\r': // Eat the Carriage Return character
  414. break;
  415. default:
  416. if (! fComment) {
  417. if (cbRead && fColumn1) {
  418. // This is not a continuation, we've gone too far. Back up!
  419. Assert(ulSavePosition);
  420. if (ulSavePosition) {
  421. if (0xFFFFFFFF == (SetFilePointer(hFile, ulSavePosition, NULL, FILE_BEGIN))) {
  422. DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
  423. return(ResultFromScode(MAPI_E_CALL_FAILED));
  424. }
  425. }
  426. fDone = TRUE;
  427. } else {
  428. cbRead++;
  429. lpRead++;
  430. }
  431. }
  432. fColumn1 = FALSE;
  433. break;
  434. }
  435. }
  436. }
  437. *lpRead = '\0'; // Terminate the string
  438. //DebugTrace("LDIF Line: %s\n", *lppBuffer);
  439. return(cbReadFile);
  440. }
  441. /***************************************************************************
  442. Name : ParseLDIFLine
  443. Purpose : Parse the LDIF input line into Name and Data
  444. Parameters: lpBuffer -> input buffer
  445. lppName -> returned name pointer (pointer into lpBuffer)
  446. lppData -> returned data pointer (pointer into lpBuffer)
  447. lpcbData -> returned data size
  448. lpType -> returned LDIF data type
  449. Returns : HRESULT
  450. Comment : Caller should not free the *lppName and *lppData pointers
  451. since they are just pointers into the input buffer.
  452. Assume that lpBuffer is NULL terminated.
  453. LDIF attrval is formed like this:
  454. attrname ((":") / (":" *SPACE value) /
  455. ("::" *SPACE base64-value) /
  456. (":<" *SPACE url))
  457. ***************************************************************************/
  458. HRESULT ParseLDIFLine(LPBYTE lpBuffer, PUCHAR * lppName, PUCHAR * lppData,
  459. LPULONG lpcbData, LPLDIF_DATA_TYPE lpType) {
  460. HRESULT hResult = hrSuccess;
  461. LPBYTE lpTemp = lpBuffer;
  462. // Strip of leading white space
  463. while (*lpTemp == ' ' || *lpTemp == '\r' || *lpTemp == '\n') {
  464. lpTemp++;
  465. }
  466. if (*lpTemp) {
  467. *lppName = lpTemp;
  468. // Look for the end of the name
  469. while (lpTemp && *lpTemp && *lpTemp != ':') {
  470. lpTemp++;
  471. }
  472. if (*lpTemp != ':') {
  473. // Hmm, this isn't very good LDIF. Error out.
  474. hResult = ResultFromScode(MAPI_E_BAD_VALUE);
  475. goto exit;
  476. }
  477. // now pointing to the ':', put a NULL there to terminate the name
  478. *lpTemp = '\0';
  479. // What type of encoding is it?
  480. lpTemp++;
  481. switch (*lpTemp) {
  482. case ':':
  483. *lpType = LDIF_BASE64;
  484. lpTemp++;
  485. break;
  486. case '<':
  487. *lpType = LDIF_URL;
  488. lpTemp++;
  489. break;
  490. case '\0':
  491. // No data. This is legitimate.
  492. // Fall through to default.
  493. default: // anything else implies ASCII value
  494. *lpType = LDIF_ASCII;
  495. break;
  496. }
  497. // Strip of spaces leading the data
  498. while (*lpTemp == ' ') {
  499. lpTemp++;
  500. }
  501. // Now pointing at data
  502. *lppData = lpTemp;
  503. // Count bytes of data
  504. *lpcbData = lstrlen(lpTemp) + 1;
  505. }
  506. exit:
  507. return(hResult);
  508. }
  509. /***************************************************************************
  510. Name : ReadLDIFRecord
  511. Purpose : Reads a record from an LDIF file with fixups for special characters
  512. Parameters: hFile = file handle
  513. lpcItems -> Returned number of items
  514. lprgItems -> Returned array of item strings. Caller is
  515. responsible for LocalFree'ing each string pointer and
  516. this array pointer.
  517. Returns : HRESULT
  518. Comment : LDIF special characters are '#', ' ', CR and LF.
  519. Rules:
  520. 1) A line which starts with '#' is a comment
  521. 2) A line which starts with a ' ' is a continuation
  522. ***************************************************************************/
  523. HRESULT ReadLDIFRecord(HANDLE hFile, ULONG * lpcItems, LPLDIF_RECORD_ATTRIBUTE * lppLDIFRecord) {
  524. HRESULT hResult = hrSuccess;
  525. PUCHAR lpBuffer = NULL;
  526. ULONG cbBuffer = 0;
  527. ULONG cbReadFile = 1;
  528. ULONG iItem = 0;
  529. ULONG cAttributes = 0;
  530. BOOL fEOR = FALSE;
  531. LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord = NULL;
  532. LDIF_DATA_TYPE Type;
  533. LPBYTE lpData = NULL;
  534. LPTSTR lpName = NULL;
  535. ULONG cbData = 0;
  536. TCHAR szTemp[2048]; // 2k limit
  537. LPLDIF_RECORD_ATTRIBUTE lpLDIFRecordT;
  538. // Start out with 1024 character buffer. Realloc as necesary.
  539. cbBuffer = CCH_READ_BUFFER;
  540. if (! (lpBuffer = LocalAlloc(LPTR, cbBuffer))) {
  541. DebugTrace("LocalAlloc(%u) -> %u\n", cbBuffer, GetLastError());
  542. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  543. goto exit;
  544. }
  545. // Start out with 32 item slots. Realloc as necesary.
  546. cAttributes = NUM_ITEM_SLOTS;
  547. if (! (lpLDIFRecord = LocalAlloc(LPTR, cAttributes * sizeof(LDIF_RECORD_ATTRIBUTE)))) {
  548. DebugTrace("LocalAlloc(%u) -> %u\n", cAttributes * sizeof(PUCHAR), GetLastError());
  549. LocalFree(lpBuffer);
  550. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  551. goto exit;
  552. }
  553. // Read attributes lines until you get end of record or EOF
  554. while (! fEOR) {
  555. // Read the next line (merges continuation)
  556. if (cbReadFile = ReadLDIFLine(hFile, &lpBuffer, &cbBuffer))
  557. {
  558. ULONG cchSize = 0;
  559. // Got another attribute, parse it
  560. if (hResult = ParseLDIFLine(lpBuffer, &lpName, &lpData, &cbData, &Type)) {
  561. goto exit;
  562. }
  563. // End of record?
  564. if (! lpName || ! lstrlen(lpName)) {
  565. fEOR = TRUE;
  566. break;
  567. }
  568. // Make sure there's room in the returned table for this attribute
  569. if (iItem >= cAttributes) {
  570. // Array is too small. Reallocate!
  571. cAttributes += 1; // NUM_ITEM_SLOTS; // Allocate another batch
  572. if (! (lpLDIFRecordT = LocalReAlloc(lpLDIFRecord, cAttributes * sizeof(LDIF_RECORD_ATTRIBUTE), LMEM_MOVEABLE | LMEM_ZEROINIT)))
  573. {
  574. DebugTrace("LocalReAlloc(%u) -> %u\n", cAttributes * sizeof(PUCHAR), GetLastError());
  575. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  576. goto exit;
  577. }
  578. lpLDIFRecord = lpLDIFRecordT;
  579. }
  580. // Fill in the attribute in the structure
  581. // BUGBUG: Here's where we should decode BASE64
  582. if(Type == LDIF_BASE64)
  583. {
  584. ULONG cb = sizeof(szTemp);
  585. *szTemp = '\0';
  586. decodeBase64( lpData, szTemp, &cb);
  587. if(szTemp && lstrlen(szTemp))
  588. {
  589. lpData = szTemp;
  590. cbData = cb;
  591. szTemp[cb] = '\0';
  592. }
  593. }
  594. lpLDIFRecord[iItem].Type = Type;
  595. lpLDIFRecord[iItem].cbData = cbData;
  596. if (! (lpLDIFRecord[iItem].lpData = LocalAlloc(LPTR, cbData)))
  597. {
  598. DebugTrace("LocalAlloc(%u) -> %u\n", cbData, GetLastError());
  599. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  600. goto exit;
  601. }
  602. memcpy(lpLDIFRecord[iItem].lpData, lpData, cbData);
  603. cchSize = lstrlen(lpName) + 1;
  604. if (! (lpLDIFRecord[iItem].lpName = LocalAlloc(LPTR, cchSize)))
  605. {
  606. DebugTrace("LocalAlloc(%u) -> %u\n", cchSize, GetLastError());
  607. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  608. goto exit;
  609. }
  610. StrCpyN(lpLDIFRecord[iItem].lpName, lpName, cchSize);
  611. } else {
  612. fEOR = TRUE;
  613. hResult = ResultFromScode(WAB_W_END_OF_FILE);
  614. }
  615. iItem++;
  616. }
  617. exit:
  618. if (lpBuffer) {
  619. LocalFree(lpBuffer);
  620. }
  621. if (hResult) {
  622. if (lpLDIFRecord) {
  623. FreeLDIFRecord(lpLDIFRecord, iItem);
  624. lpLDIFRecord = NULL;
  625. }
  626. }
  627. *lppLDIFRecord = lpLDIFRecord;
  628. *lpcItems = iItem;
  629. return(hResult);
  630. }
  631. /***************************************************************************
  632. Name : CountLDIFRows
  633. Purpose : Counts the rows in the LDIF file
  634. Parameters: hFile = open LDIF file
  635. lpulcEntries -> returned count of rows
  636. Returns : HRESULT
  637. Comment : File pointer should be positioned past the version string prior
  638. to calling this function. This function leaves the file
  639. pointer where it found it.
  640. ***************************************************************************/
  641. HRESULT CountLDIFRecords(HANDLE hFile, LPULONG lpulcEntries) {
  642. HRESULT hResult = hrSuccess;
  643. PUCHAR * rgItems = NULL;
  644. ULONG ulStart;
  645. ULONG cProps, i;
  646. LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord = NULL;
  647. *lpulcEntries = 0;
  648. Assert(hFile != INVALID_HANDLE_VALUE);
  649. if (0xFFFFFFFF == (ulStart = SetFilePointer(hFile, 0, NULL, FILE_CURRENT))) {
  650. DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
  651. return(ResultFromScode(MAPI_E_CALL_FAILED));
  652. }
  653. while (hResult == hrSuccess) {
  654. // Read the line
  655. if (ReadLDIFRecord(hFile, &cProps, &lpLDIFRecord)) {
  656. // End of file
  657. break;
  658. }
  659. (*lpulcEntries)++;
  660. if (lpLDIFRecord) {
  661. FreeLDIFRecord(lpLDIFRecord, cProps);
  662. lpLDIFRecord = NULL;
  663. }
  664. }
  665. if (0xFFFFFFFF == SetFilePointer(hFile, ulStart, NULL, FILE_BEGIN)) {
  666. DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
  667. }
  668. DebugTrace("LDIF file contains %u entries\n", ulcEntries);
  669. return(hResult);
  670. }
  671. /***************************************************************************
  672. Name : InitLDIFAttrTable
  673. Purpose : Initialize the LDIF attribute table
  674. Parameters: LDIFAttrTable = table of attribute mappings
  675. Returns : none
  676. ***************************************************************************/
  677. void InitLDIFAttrTable(LPLDIF_ATTR_TABLE LDIFAttrTable) {
  678. ULONG i;
  679. for (i = 0; i < ela_Max; i++) {
  680. LDIFAttrTable[i].index = NOT_FOUND;
  681. LDIFAttrTable[i].ulPropTag = PR_NULL;
  682. }
  683. LDIFAttrTable[ela_c].lpName = sz_c;
  684. LDIFAttrTable[ela_cn].lpName = sz_cn;
  685. LDIFAttrTable[ela_co].lpName = sz_co;
  686. LDIFAttrTable[ela_comment].lpName = sz_comment;
  687. LDIFAttrTable[ela_commonName].lpName = sz_commonName;
  688. LDIFAttrTable[ela_conferenceInformation].lpName = sz_conferenceInformation;
  689. LDIFAttrTable[ela_countryname].lpName = sz_countryname;
  690. LDIFAttrTable[ela_department].lpName = sz_department;
  691. LDIFAttrTable[ela_description].lpName = sz_description;
  692. LDIFAttrTable[ela_display_name].lpName = sz_display_name;
  693. LDIFAttrTable[ela_dn].lpName = sz_dn;
  694. LDIFAttrTable[ela_facsimiletelephonenumber].lpName = sz_facsimiletelephonenumber;
  695. LDIFAttrTable[ela_givenname].lpName = sz_givenname;
  696. LDIFAttrTable[ela_homePostalAddress].lpName = sz_homePostalAddress;
  697. LDIFAttrTable[ela_homepage].lpName = sz_homepage;
  698. LDIFAttrTable[ela_info].lpName = sz_info;
  699. LDIFAttrTable[ela_initials].lpName = sz_initials;
  700. LDIFAttrTable[ela_l].lpName = sz_l;
  701. LDIFAttrTable[ela_labeledURI].lpName = sz_labeledURI;
  702. LDIFAttrTable[ela_locality].lpName = sz_locality;
  703. LDIFAttrTable[ela_mail].lpName = sz_mail;
  704. LDIFAttrTable[ela_member].lpName = sz_member;
  705. LDIFAttrTable[ela_mobile].lpName = sz_mobile;
  706. LDIFAttrTable[ela_o].lpName = sz_o;
  707. LDIFAttrTable[ela_objectclass].lpName = sz_objectclass;
  708. LDIFAttrTable[ela_OfficeFax].lpName = sz_OfficeFax;
  709. LDIFAttrTable[ela_OfficePager].lpName = sz_OfficePager;
  710. LDIFAttrTable[ela_organizationName].lpName = sz_organizationName;
  711. LDIFAttrTable[ela_organizationalUnitName].lpName = sz_organizationalUnitName;
  712. LDIFAttrTable[ela_otherMailbox].lpName = sz_otherMailbox;
  713. LDIFAttrTable[ela_ou].lpName = sz_ou;
  714. LDIFAttrTable[ela_pager].lpName = sz_pager;
  715. LDIFAttrTable[ela_physicalDeliveryOfficeName].lpName = sz_physicalDeliveryOfficeName;
  716. LDIFAttrTable[ela_postOfficeBox].lpName = sz_postOfficeBox;
  717. LDIFAttrTable[ela_postalAddress].lpName = sz_postalAddress;
  718. LDIFAttrTable[ela_postalcode].lpName = sz_postalcode;
  719. LDIFAttrTable[ela_sn].lpName = sz_sn;
  720. LDIFAttrTable[ela_st].lpName = sz_st;
  721. LDIFAttrTable[ela_streetAddress].lpName = sz_streetAddress;
  722. LDIFAttrTable[ela_street].lpName = sz_street;
  723. LDIFAttrTable[ela_surname].lpName = sz_surname;
  724. LDIFAttrTable[ela_telephonenumber].lpName = sz_telephonenumber;
  725. LDIFAttrTable[ela_homephonenumber].lpName = sz_homephonenumber;
  726. LDIFAttrTable[ela_title].lpName = sz_title;
  727. LDIFAttrTable[ela_uid].lpName = sz_uid;
  728. LDIFAttrTable[ela_URL].lpName = sz_URL;
  729. LDIFAttrTable[ela_userCertificate].lpName = sz_userCertificate;
  730. LDIFAttrTable[ela_xmozillaconference].lpName = sz_xmozillaconference;
  731. LDIFAttrTable[ela_xmozillanickname].lpName = sz_xmozillanickname;
  732. LDIFAttrTable[ela_xmozillauseconferenceserver].lpName = sz_xmozillauseconferenceserver;
  733. LDIFAttrTable[ela_xmozillausehtmlmail].lpName = sz_xmozillausehtmlmail;
  734. LDIFAttrTable[ela_c].ulPropTag = PR_COUNTRY;
  735. LDIFAttrTable[ela_c].ulPropIndex = elp_COUNTRY;
  736. LDIFAttrTable[ela_cn].ulPropTag = PR_DISPLAY_NAME;
  737. LDIFAttrTable[ela_cn].ulPropIndex = elp_DISPLAY_NAME;
  738. LDIFAttrTable[ela_co].ulPropTag = PR_COMPANY_NAME;
  739. LDIFAttrTable[ela_co].ulPropIndex = elp_COMPANY_NAME;
  740. LDIFAttrTable[ela_comment].ulPropTag = PR_COMMENT;
  741. LDIFAttrTable[ela_comment].ulPropIndex = elp_COMMENT;
  742. LDIFAttrTable[ela_commonName].ulPropTag = PR_DISPLAY_NAME;
  743. LDIFAttrTable[ela_commonName].ulPropIndex = elp_DISPLAY_NAME;
  744. LDIFAttrTable[ela_conferenceInformation].ulPropTag = PR_NULL; // bugbug?
  745. LDIFAttrTable[ela_conferenceInformation].ulPropIndex = NOT_FOUND;
  746. LDIFAttrTable[ela_countryname].ulPropTag = PR_COUNTRY;
  747. LDIFAttrTable[ela_countryname].ulPropIndex = elp_COUNTRY;
  748. LDIFAttrTable[ela_department].ulPropTag = PR_DEPARTMENT_NAME;
  749. LDIFAttrTable[ela_department].ulPropIndex = elp_DEPARTMENT_NAME;
  750. LDIFAttrTable[ela_description].ulPropTag = PR_COMMENT;
  751. LDIFAttrTable[ela_description].ulPropIndex = elp_COMMENT;
  752. LDIFAttrTable[ela_display_name].ulPropTag = PR_DISPLAY_NAME;
  753. LDIFAttrTable[ela_display_name].ulPropIndex = elp_DISPLAY_NAME;
  754. LDIFAttrTable[ela_dn].ulPropTag = PR_DISPLAY_NAME;
  755. LDIFAttrTable[ela_dn].ulPropIndex = elp_DISPLAY_NAME;
  756. LDIFAttrTable[ela_facsimiletelephonenumber].ulPropTag = PR_HOME_FAX_NUMBER;
  757. LDIFAttrTable[ela_facsimiletelephonenumber].ulPropIndex = elp_HOME_FAX_NUMBER;
  758. LDIFAttrTable[ela_givenname].ulPropTag = PR_GIVEN_NAME;
  759. LDIFAttrTable[ela_givenname].ulPropIndex = elp_GIVEN_NAME;
  760. LDIFAttrTable[ela_homePostalAddress].ulPropTag = PR_HOME_ADDRESS_STREET;
  761. LDIFAttrTable[ela_homePostalAddress].ulPropIndex = elp_HOME_ADDRESS_STREET;
  762. LDIFAttrTable[ela_homepage].ulPropTag = PR_PERSONAL_HOME_PAGE;
  763. LDIFAttrTable[ela_homepage].ulPropIndex = elp_PERSONAL_HOME_PAGE;
  764. LDIFAttrTable[ela_info].ulPropTag = PR_COMMENT;
  765. LDIFAttrTable[ela_info].ulPropIndex = elp_COMMENT;
  766. LDIFAttrTable[ela_initials].ulPropTag = PR_MIDDLE_NAME;
  767. LDIFAttrTable[ela_initials].ulPropIndex = elp_MIDDLE_NAME;
  768. LDIFAttrTable[ela_l].ulPropTag = PR_LOCALITY;
  769. LDIFAttrTable[ela_l].ulPropIndex = elp_LOCALITY;
  770. LDIFAttrTable[ela_labeledURI].ulPropTag = PR_NULL; // Labeled URI. Don't save now.
  771. LDIFAttrTable[ela_labeledURI].ulPropIndex = NOT_FOUND;
  772. LDIFAttrTable[ela_locality].ulPropTag = PR_LOCALITY;
  773. LDIFAttrTable[ela_locality].ulPropIndex = elp_LOCALITY;
  774. LDIFAttrTable[ela_mail].ulPropTag = PR_EMAIL_ADDRESS;
  775. LDIFAttrTable[ela_mail].ulPropIndex = elp_EMAIL_ADDRESS;
  776. LDIFAttrTable[ela_member].ulPropTag = PR_NULL; // member of DL
  777. LDIFAttrTable[ela_member].ulPropIndex = NOT_FOUND;
  778. LDIFAttrTable[ela_mobile].ulPropTag = PR_MOBILE_TELEPHONE_NUMBER;
  779. LDIFAttrTable[ela_mobile].ulPropIndex = elp_MOBILE_TELEPHONE_NUMBER;
  780. LDIFAttrTable[ela_o].ulPropTag = PR_COMPANY_NAME;
  781. LDIFAttrTable[ela_o].ulPropIndex = elp_COMPANY_NAME;
  782. LDIFAttrTable[ela_objectclass].ulPropTag = PR_NULL; // special case object class
  783. LDIFAttrTable[ela_objectclass].ulPropIndex = NOT_FOUND;
  784. LDIFAttrTable[ela_OfficeFax].ulPropTag = PR_BUSINESS_FAX_NUMBER;
  785. LDIFAttrTable[ela_OfficeFax].ulPropIndex = elp_BUSINESS_FAX_NUMBER;
  786. LDIFAttrTable[ela_OfficePager].ulPropTag = PR_PAGER_TELEPHONE_NUMBER;
  787. LDIFAttrTable[ela_OfficePager].ulPropIndex = elp_PAGER_TELEPHONE_NUMBER;
  788. LDIFAttrTable[ela_organizationName].ulPropTag = PR_COMPANY_NAME;
  789. LDIFAttrTable[ela_organizationName].ulPropIndex = elp_COMPANY_NAME;
  790. LDIFAttrTable[ela_organizationalUnitName].ulPropTag = PR_DEPARTMENT_NAME;
  791. LDIFAttrTable[ela_organizationalUnitName].ulPropIndex = elp_DEPARTMENT_NAME;
  792. LDIFAttrTable[ela_otherMailbox].ulPropTag = PR_NULL; // BUGBUG
  793. LDIFAttrTable[ela_otherMailbox].ulPropIndex = NOT_FOUND;
  794. LDIFAttrTable[ela_ou].ulPropTag = PR_DEPARTMENT_NAME;
  795. LDIFAttrTable[ela_ou].ulPropIndex = elp_DEPARTMENT_NAME;
  796. LDIFAttrTable[ela_pager].ulPropTag = PR_PAGER_TELEPHONE_NUMBER;
  797. LDIFAttrTable[ela_pager].ulPropIndex = elp_PAGER_TELEPHONE_NUMBER;
  798. LDIFAttrTable[ela_physicalDeliveryOfficeName].ulPropTag = PR_OFFICE_LOCATION;
  799. LDIFAttrTable[ela_physicalDeliveryOfficeName].ulPropIndex = elp_OFFICE_LOCATION;
  800. LDIFAttrTable[ela_postOfficeBox].ulPropTag = PR_POST_OFFICE_BOX;
  801. LDIFAttrTable[ela_postOfficeBox].ulPropIndex = elp_POST_OFFICE_BOX;
  802. LDIFAttrTable[ela_postalAddress].ulPropTag = PR_STREET_ADDRESS;
  803. LDIFAttrTable[ela_postalAddress].ulPropIndex = elp_STREET_ADDRESS;
  804. LDIFAttrTable[ela_postalcode].ulPropTag = PR_POSTAL_CODE;
  805. LDIFAttrTable[ela_postalcode].ulPropIndex = elp_POSTAL_CODE;
  806. LDIFAttrTable[ela_sn].ulPropTag = PR_SURNAME;
  807. LDIFAttrTable[ela_sn].ulPropIndex = elp_SURNAME;
  808. LDIFAttrTable[ela_st].ulPropTag = PR_STATE_OR_PROVINCE;
  809. LDIFAttrTable[ela_st].ulPropIndex = elp_STATE_OR_PROVINCE;
  810. LDIFAttrTable[ela_streetAddress].ulPropTag = PR_STREET_ADDRESS;
  811. LDIFAttrTable[ela_streetAddress].ulPropIndex = elp_STREET_ADDRESS;
  812. LDIFAttrTable[ela_street].ulPropTag = PR_STREET_ADDRESS;
  813. LDIFAttrTable[ela_street].ulPropIndex = elp_STREET_ADDRESS;
  814. LDIFAttrTable[ela_surname].ulPropTag = PR_SURNAME;
  815. LDIFAttrTable[ela_surname].ulPropIndex = elp_SURNAME;
  816. LDIFAttrTable[ela_telephonenumber].ulPropTag = PR_BUSINESS_TELEPHONE_NUMBER;
  817. LDIFAttrTable[ela_telephonenumber].ulPropIndex = elp_BUSINESS_TELEPHONE_NUMBER;
  818. LDIFAttrTable[ela_homephonenumber].ulPropTag = PR_HOME_TELEPHONE_NUMBER;
  819. LDIFAttrTable[ela_homephonenumber].ulPropIndex = elp_HOME_TELEPHONE_NUMBER;
  820. LDIFAttrTable[ela_title].ulPropTag = PR_TITLE;
  821. LDIFAttrTable[ela_title].ulPropIndex = elp_TITLE;
  822. LDIFAttrTable[ela_uid].ulPropTag = PR_GIVEN_NAME; // ?? Matches in LDIF spec
  823. LDIFAttrTable[ela_uid].ulPropIndex = elp_GIVEN_NAME;
  824. LDIFAttrTable[ela_URL].ulPropTag = PR_BUSINESS_HOME_PAGE;
  825. LDIFAttrTable[ela_URL].ulPropIndex = elp_BUSINESS_HOME_PAGE;
  826. LDIFAttrTable[ela_userCertificate].ulPropTag = PR_NULL; // BUGBUG
  827. LDIFAttrTable[ela_userCertificate].ulPropIndex = NOT_FOUND;
  828. LDIFAttrTable[ela_xmozillaconference].ulPropTag = PR_SERVERS; //PR_NULL; // BUGBUG?
  829. LDIFAttrTable[ela_xmozillaconference].ulPropIndex = elp_CONFERENCE_SERVERS;
  830. LDIFAttrTable[ela_xmozillanickname].ulPropTag = PR_NICKNAME;
  831. LDIFAttrTable[ela_xmozillanickname].ulPropIndex = elp_NICKNAME;
  832. LDIFAttrTable[ela_xmozillauseconferenceserver].ulPropTag = PR_NULL; // BUGBUG
  833. LDIFAttrTable[ela_xmozillauseconferenceserver].ulPropIndex = NOT_FOUND;
  834. LDIFAttrTable[ela_xmozillausehtmlmail].ulPropTag = PR_NULL; // BUGBUG
  835. LDIFAttrTable[ela_xmozillausehtmlmail].ulPropIndex = NOT_FOUND;
  836. }
  837. /***************************************************************************
  838. Name : FindAttributeName
  839. Purpose : Find the attribute mapping in the LDIF attribute table
  840. Parameters: lpName = name of attribute to find
  841. LDIFAttrTable = table of LDIF attribute mappings
  842. Returns : index in LDIFAttrTable (or NOT_FOUND)
  843. Comment : Could perhaps benefit from a binary search algorithm.
  844. ***************************************************************************/
  845. ULONG FindAttributeName(LPBYTE lpName, LPLDIF_ATTR_TABLE LDIFAttrTable) {
  846. ULONG i;
  847. ULONG ulIndex = NOT_FOUND;
  848. for (i = 0; i < ela_Max; i++) {
  849. if (lpName && LDIFAttrTable[i].lpName && ! lstrcmpi(lpName, LDIFAttrTable[i].lpName)) {
  850. ulIndex = i;
  851. break;
  852. }
  853. }
  854. return(ulIndex);
  855. }
  856. /***************************************************************************
  857. Name : MapLDIFtoProps
  858. Purpose : Map the LDIF record attributes to WAB properties
  859. Parameters: lpLDIFRecord -> LDIF record
  860. cAttributes = number of attributes in LDIF record
  861. lpspv -> prop value array (pre-allocated)
  862. lpcProps -> returned number of properties
  863. lppDisplayName -> returned display name
  864. lppEmailAddress -> returned email address (or NULL)
  865. Returns : HRESULT
  866. ***************************************************************************/
  867. HRESULT MapLDIFtoProps(LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord, ULONG cAttributes,
  868. LPSPropValue * lppspv, LPULONG lpcProps, LPTSTR * lppDisplayName, LPTSTR *lppEmailAddress,
  869. ULONG * lpulObjType) {
  870. HRESULT hResult = hrSuccess;
  871. ULONG cPropVals = cPropVals = cAttributes + NUM_MUST_HAVE_PROPS;
  872. ULONG iProp = 0;
  873. ULONG i;
  874. LDIF_ATTR_TABLE LDIFAttrTable[ela_Max];
  875. ULONG iTable;
  876. ULONG cProps = elp_Max;
  877. SCODE sc;
  878. LONG iEmailAddr = -1;
  879. LONG iServers = -1;
  880. LPSPropValue lpspv = NULL;
  881. ULONG ulIndex = 0;
  882. *lpulObjType = MAPI_MAILUSER;
  883. // Allocate prop value array
  884. if (hResult = ResultFromScode(WABAllocateBuffer(cProps * sizeof(SPropValue), &lpspv))) {
  885. DebugTrace("WABAllocateBuffer -> %x\n", GetScode(hResult));
  886. goto exit;
  887. }
  888. // Fill with PR_NULL
  889. for (i = 0; i < cProps; i++) {
  890. lpspv[i].ulPropTag = PR_NULL;
  891. }
  892. InitLDIFAttrTable(LDIFAttrTable);
  893. // Loop through attributes, looking for interesting stuff
  894. for (i = 0; i < cAttributes; i++) {
  895. iTable = NOT_FOUND;
  896. if ((iTable = FindAttributeName(lpLDIFRecord[i].lpName, LDIFAttrTable)) != NOT_FOUND) {
  897. // Found the attribute name
  898. // mark the data index in the table
  899. LDIFAttrTable[iTable].index = i;
  900. }
  901. // Some special cases need to be examined now.
  902. switch (iTable) {
  903. case ela_cn:
  904. case ela_dn:
  905. // if we have both cn and dn, cn takes precedence
  906. if(LDIFAttrTable[ela_cn].index != NOT_FOUND && LDIFAttrTable[ela_dn].index != NOT_FOUND)
  907. LDIFAttrTable[ela_dn].index = NOT_FOUND;
  908. break;
  909. case ela_objectclass:
  910. // objectclass may appear multiple times. It is up to us to decide which
  911. // one is meaningful.
  912. // We recognize several different types:
  913. // objectclass: person
  914. // objectclass: organizationalPerson
  915. // objectclass: groupofnames
  916. // What objectclass is it?
  917. if(lpLDIFRecord[i].lpData)
  918. {
  919. if (! lstrcmpi(lpLDIFRecord[i].lpData, sz_person) ||
  920. ! lstrcmpi(lpLDIFRecord[i].lpData, sz_organizationalPerson)) {
  921. *lpulObjType = MAPI_MAILUSER;
  922. } else if (! lstrcmpi(lpLDIFRecord[i].lpData, sz_groupOfNames)) {
  923. *lpulObjType = MAPI_DISTLIST;
  924. } else {
  925. // Ignore this objectclass
  926. }
  927. }
  928. break;
  929. case ela_member: // DL member name or address
  930. Assert(*lpulObjType == MAPI_DISTLIST);
  931. // BUGBUG: NYI
  932. break;
  933. }
  934. }
  935. // look through the attr table for props to use
  936. for (i = 0; i < ela_Max; i++)
  937. {
  938. if (LDIFAttrTable[i].ulPropTag != PR_NULL &&
  939. lpspv[ulIndex].ulPropTag == PR_NULL &&
  940. LDIFAttrTable[i].index != NOT_FOUND)
  941. {
  942. if( LDIFAttrTable[i].ulPropTag == PR_SERVERS )
  943. {
  944. ULONG cchData;
  945. ULONG cStrToAdd = 2;
  946. LPTSTR * lppszServers;
  947. ULONG index = (iServers >= 0 ? iServers : ulIndex); //LDIFAttrTable[i].ulPropIndex;
  948. LONG cCurrentStrs = (iServers >= 0 ? lpspv[index].Value.MVSZ.cValues : 0);
  949. LPTSTR lpEmailAddress = NULL;
  950. lpspv[index].ulPropTag = PR_SERVERS;
  951. if( cCurrentStrs >= (LONG)cStrToAdd )
  952. {
  953. // will not handle more than 2 netmtgs addresses
  954. lpspv[index].ulPropTag = PR_NULL;
  955. }
  956. else
  957. {
  958. if( cCurrentStrs <= 0 )
  959. {
  960. sc = WABAllocateMore(sizeof(LPTSTR), lpspv,
  961. (LPVOID *)&(lpspv[index].Value.MVSZ.LPPSZ));
  962. if (sc)
  963. {
  964. hResult = ResultFromScode(sc);
  965. goto exit;
  966. }
  967. cCurrentStrs = 0;
  968. }
  969. cchData = 2 + lstrlen(szCallto) + lstrlen( lpLDIFRecord[LDIFAttrTable[i].index].lpData );
  970. if ( iEmailAddr >= 0 ){
  971. lpEmailAddress = lpspv[iEmailAddr].Value.LPSZ;
  972. cchData += lstrlen( lpEmailAddress) + 2;
  973. }
  974. // allocate enough space for two Server names
  975. lppszServers = lpspv[index].Value.MVSZ.LPPSZ;
  976. // Allocate more space for the email address and copy it.
  977. sc = WABAllocateMore( sizeof(TCHAR) * cchData, lpspv,
  978. (LPVOID *)&(lppszServers[cCurrentStrs]));
  979. if( sc )
  980. {
  981. hResult = ResultFromScode(sc);
  982. goto exit;
  983. }
  984. StrCpyN(lppszServers[cCurrentStrs], szCallto, cchData);
  985. StrCatBuff(lppszServers[cCurrentStrs], lpLDIFRecord[LDIFAttrTable[i].index].lpData, cchData);
  986. // now we need to check if email address has already been set
  987. if ( iEmailAddr >= 0 )
  988. {
  989. StrCatBuff(lppszServers[cCurrentStrs], szFwdSlash, cchData);
  990. StrCatBuff(lppszServers[cCurrentStrs], lpEmailAddress, cchData);
  991. }
  992. else
  993. iServers = index;
  994. lpspv[index].Value.MVSZ.cValues = ++cCurrentStrs;
  995. }
  996. }
  997. else
  998. {
  999. int index = LDIFAttrTable[i].index;
  1000. LPTSTR lp = lpLDIFRecord[index].lpData;
  1001. if(lp && lstrlen(lp))
  1002. {
  1003. lpspv[ulIndex].ulPropTag = LDIFAttrTable[i].ulPropTag;
  1004. // BUGBUG: assumes string data
  1005. // Allocate more space for the email address and copy it.
  1006. sc = WABAllocateMore( sizeof(TCHAR)*(lstrlen(lp)+1), lpspv, (LPVOID *)&(lpspv[ulIndex].Value.LPSZ));
  1007. if( sc )
  1008. {
  1009. hResult = ResultFromScode(sc);
  1010. goto exit;
  1011. }
  1012. StrCpyN(lpspv[ulIndex].Value.LPSZ, lp, lstrlen(lp)+1);
  1013. }
  1014. }
  1015. // Get the special display strings to return
  1016. switch (LDIFAttrTable[i].ulPropTag) {
  1017. case PR_DISPLAY_NAME:
  1018. *lppDisplayName = lpspv[ulIndex].Value.LPSZ;
  1019. break;
  1020. case PR_EMAIL_ADDRESS:
  1021. {
  1022. LPTSTR * lppszServerStr, lpszOldServerStr;
  1023. LONG cNumStrs;
  1024. ULONG cchData;
  1025. *lppEmailAddress = lpspv[ulIndex].Value.LPSZ;
  1026. // if servers has has already been set, append email address
  1027. if ( iServers >= 0 )
  1028. {
  1029. if( lpspv[iServers].ulPropTag != PR_SERVERS )
  1030. break;
  1031. cNumStrs = lpspv[iServers].Value.MVSZ.cValues - 1;
  1032. if( cNumStrs >= 0 && cNumStrs < 3)
  1033. {
  1034. lppszServerStr = lpspv[iServers].Value.MVSZ.LPPSZ;
  1035. lpszOldServerStr = lppszServerStr[cNumStrs];
  1036. cchData = lstrlen(*lppszServerStr) + lstrlen(*lppEmailAddress) + 2;
  1037. sc = WABAllocateMore( sizeof(TCHAR) * cchData, lpspv,
  1038. (LPVOID *)&(lppszServerStr[cNumStrs]));
  1039. if( sc )
  1040. {
  1041. hResult = ResultFromScode(sc);
  1042. goto exit;
  1043. }
  1044. StrCpyN(lppszServerStr[cNumStrs],lpszOldServerStr, cchData);
  1045. StrCatBuff(lppszServerStr[cNumStrs], szFwdSlash, cchData);
  1046. StrCatBuff(lppszServerStr[cNumStrs], *lppEmailAddress, cchData);
  1047. }
  1048. }
  1049. else
  1050. iEmailAddr = ulIndex;
  1051. }
  1052. break;
  1053. }
  1054. ulIndex++;
  1055. }
  1056. }
  1057. /*
  1058. // Get rid of PR_NULL props
  1059. for (i = 0; i < cProps; i++) {
  1060. if (lpspv[i].ulPropTag == PR_NULL) {
  1061. // Slide the props down.
  1062. if (i + 1 < cProps) { // Are there any higher props to copy?
  1063. CopyMemory(&(lpspv[i]),
  1064. &(lpspv[i + 1]),
  1065. ((cProps - i) - 1) * sizeof(*lppspv[i]));
  1066. }
  1067. // decrement count
  1068. cProps--;
  1069. i--; // You overwrote the current propval. Look at it again.
  1070. }
  1071. }
  1072. */
  1073. *lpcProps = ulIndex;
  1074. *lppspv = lpspv;
  1075. exit:
  1076. return(hResult);
  1077. }
  1078. /*********************************************************
  1079. HraddLDIFMailUser - adds a mailuser to the WAB
  1080. **********************************************************/
  1081. HRESULT HrAddLDIFMailUser(HWND hWnd,
  1082. LPABCONT lpContainer,
  1083. LPTSTR lpDisplayName,
  1084. LPTSTR lpEmailAddress,
  1085. ULONG cProps,
  1086. LPSPropValue lpspv,
  1087. LPWAB_PROGRESS_CALLBACK lpProgressCB,
  1088. LPWAB_EXPORT_OPTIONS lpOptions)
  1089. {
  1090. HRESULT hResult = S_OK;
  1091. LPMAPIPROP lpMailUserWAB = NULL;
  1092. ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
  1093. REPLACE_INFO RI;
  1094. if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
  1095. {
  1096. ulCreateFlags |= CREATE_REPLACE;
  1097. }
  1098. retry:
  1099. // Create a new wab mailuser
  1100. if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
  1101. lpContainer,
  1102. lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
  1103. (LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
  1104. ulCreateFlags,
  1105. &lpMailUserWAB)))
  1106. {
  1107. DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
  1108. goto exit;
  1109. }
  1110. {
  1111. ULONG i,k;
  1112. for(i=0;i<cProps;i++)
  1113. {
  1114. if(PROP_TYPE(lpspv[i].ulPropTag)==PT_MV_TSTRING)
  1115. {
  1116. DebugTrace("\t0x%.8x = %d\n",lpspv[i].ulPropTag, lpspv[i].Value.MVSZ.cValues);
  1117. for(k=0;k<lpspv[i].Value.MVSZ.cValues;k++)
  1118. DebugTrace("\t%s\n",lpspv[i].Value.MVSZ.LPPSZ[k]);
  1119. }
  1120. else
  1121. DebugTrace("0x%.8x = %s\n",lpspv[i].ulPropTag,lpspv[i].Value.LPSZ);
  1122. }
  1123. }
  1124. // Set the properties on the new WAB entry
  1125. if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SetProps( lpMailUserWAB,
  1126. cProps, // cValues
  1127. lpspv, // property array
  1128. NULL))) // problems array
  1129. {
  1130. DebugTrace("LDIFImport:SetProps(WAB) -> %x\n", GetScode(hResult));
  1131. goto exit;
  1132. }
  1133. // Save the new wab mailuser or distlist
  1134. if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SaveChanges(lpMailUserWAB,
  1135. KEEP_OPEN_READONLY | FORCE_SAVE)))
  1136. {
  1137. if (GetScode(hResult) == MAPI_E_COLLISION)
  1138. {
  1139. // Find the display name
  1140. Assert(lpDisplayName);
  1141. if (! lpDisplayName)
  1142. {
  1143. DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
  1144. goto exit;
  1145. }
  1146. // Do we need to prompt?
  1147. if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
  1148. {
  1149. // Prompt user with dialog. If they say YES, we should try again
  1150. RI.lpszDisplayName = lpDisplayName;
  1151. RI.lpszEmailAddress = lpEmailAddress;
  1152. RI.ConfirmResult = CONFIRM_ERROR;
  1153. RI.lpImportOptions = lpOptions;
  1154. DialogBoxParam(hInst,
  1155. MAKEINTRESOURCE(IDD_ImportReplace),
  1156. hWnd,
  1157. ReplaceDialogProc,
  1158. (LPARAM)&RI);
  1159. switch (RI.ConfirmResult)
  1160. {
  1161. case CONFIRM_YES:
  1162. case CONFIRM_YES_TO_ALL:
  1163. // YES
  1164. // NOTE: recursive Migrate will fill in the SeenList entry
  1165. // go try again!
  1166. lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
  1167. lpMailUserWAB = NULL;
  1168. ulCreateFlags |= CREATE_REPLACE;
  1169. goto retry;
  1170. break;
  1171. case CONFIRM_ABORT:
  1172. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  1173. goto exit;
  1174. default:
  1175. // NO
  1176. break;
  1177. }
  1178. }
  1179. hResult = hrSuccess;
  1180. } else
  1181. {
  1182. DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
  1183. }
  1184. }
  1185. exit:
  1186. if(lpMailUserWAB)
  1187. lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
  1188. return hResult;
  1189. }
  1190. /*****************************************************************
  1191. HrCreateAdrListFromLDIFRecord
  1192. Scans an LDIF record and turns all the "members" into an
  1193. unresolved AdrList
  1194. ******************************************************************/
  1195. HRESULT HrCreateAdrListFromLDIFRecord(ULONG cAttributes,
  1196. LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord,
  1197. LPADRLIST * lppAdrList)
  1198. {
  1199. HRESULT hr = S_OK;
  1200. ULONG nMembers = 0, i;
  1201. LPADRLIST lpAdrList = NULL;
  1202. *lppAdrList = NULL;
  1203. // Count the members in this group
  1204. for(i=0;i<cAttributes;i++)
  1205. {
  1206. if(lpLDIFRecord[i].cbData && lpLDIFRecord[i].lpName && !lstrcmpi(lpLDIFRecord[i].lpName, sz_member))
  1207. {
  1208. nMembers++;
  1209. }
  1210. }
  1211. if(!nMembers)
  1212. goto exit;
  1213. // Now create a adrlist from these members
  1214. // Allocate prop value array
  1215. if (hr = ResultFromScode(WABAllocateBuffer(sizeof(ADRLIST) + nMembers * sizeof(ADRENTRY), &lpAdrList)))
  1216. goto exit;
  1217. lpAdrList->cEntries = nMembers;
  1218. nMembers = 0;
  1219. for(i=0;i<cAttributes;i++)
  1220. {
  1221. if(lpLDIFRecord[i].cbData && lpLDIFRecord[i].lpData
  1222. && !lstrcmpi(lpLDIFRecord[i].lpName, sz_member))
  1223. {
  1224. // This is a member .. break out its lpData into
  1225. // Name and Email
  1226. LPTSTR lpName = NULL;
  1227. LPTSTR lpEmail = NULL;
  1228. lpName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lpLDIFRecord[i].cbData + 1));
  1229. lpEmail = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lpLDIFRecord[i].cbData + 1));
  1230. if(lpName && lpEmail)
  1231. {
  1232. LPTSTR lp = NULL;
  1233. StrCpyN(lpName, lpLDIFRecord[i].lpData, lpLDIFRecord[i].cbData + 1);
  1234. StrCpyN(lpEmail, lpName, lpLDIFRecord[i].cbData + 1);
  1235. lp = lpName;
  1236. // BUGBUG - we are looking for two pieces of data Name and Email
  1237. // this code is assuming it will get 'cn=' first and then 'mail='
  1238. // second .. this is all a poor hack assuming too many things
  1239. if(*lp == 'c' && *(lp+1) == 'n' && *(lp+2) == '=')
  1240. lp += 3;
  1241. StrCpyN(lpName, lp, lpLDIFRecord[i].cbData + 1);
  1242. while (lp && *lp && *lp!=',')
  1243. lp++;
  1244. if(!*lp) // there is a comma, sometimes there isnt
  1245. {
  1246. LocalFree(lpEmail);
  1247. lpEmail = NULL;
  1248. }
  1249. else
  1250. {
  1251. *lp = '\0';
  1252. lp++;
  1253. StrCpyN(lpEmail, lp, lpLDIFRecord[i].cbData + 1);
  1254. lp = lpEmail;
  1255. if(*lp == 'm' && *(lp+1) == 'a' && *(lp+2) == 'i' && *(lp+3) == 'l' && *(lp+4) == '=')
  1256. lp += 5;
  1257. StrCpyN(lpEmail, lp, lpLDIFRecord[i].cbData + 1);
  1258. while (lp && *lp && *lp!=',')
  1259. lp++;
  1260. if(*lp)
  1261. {
  1262. // terminate on this
  1263. *lp = '\0';
  1264. }
  1265. }
  1266. if(lpName)// && lpEmail)
  1267. {
  1268. LPSPropValue lpProp = NULL;
  1269. ULONG ulcProps = 2;
  1270. if (hr = ResultFromScode(WABAllocateBuffer(2 * sizeof(SPropValue), &lpProp)))
  1271. goto exit;
  1272. lpProp[0].ulPropTag = PR_DISPLAY_NAME;
  1273. if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpName)+1, lpProp, &(lpProp[0].Value.lpszA))))
  1274. goto exit;
  1275. StrCpyN(lpProp[0].Value.lpszA, lpName, lstrlen(lpName)+1);
  1276. if(lpEmail)
  1277. {
  1278. lpProp[1].ulPropTag = PR_EMAIL_ADDRESS;
  1279. if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpEmail)+1, lpProp, &(lpProp[1].Value.lpszA))))
  1280. goto exit;
  1281. StrCpyN(lpProp[1].Value.lpszA, lpEmail, lstrlen(lpEmail)+1);
  1282. }
  1283. lpAdrList->aEntries[nMembers].cValues = (lpEmail ? 2 : 1);
  1284. lpAdrList->aEntries[nMembers].rgPropVals = lpProp;
  1285. nMembers++;
  1286. }
  1287. if(lpName)
  1288. LocalFree(lpName);
  1289. if(lpEmail)
  1290. LocalFree(lpEmail);
  1291. }
  1292. }
  1293. }
  1294. *lppAdrList = lpAdrList;
  1295. exit:
  1296. if(HR_FAILED(hr) && lpAdrList)
  1297. WABFreePadrlist(lpAdrList);
  1298. return hr;
  1299. }
  1300. /*****************************************************************
  1301. HraddLDIFDistList - adds a distlist and its members to the WAB
  1302. Sequence of events will be:
  1303. - Create a DistList object
  1304. - Set the properties on the DistList object
  1305. - Scan the list of members for the given dist list object
  1306. - Add each member to the wab .. if member already exists,
  1307. prompt to replace etc ...if it doesnt exist, create new
  1308. ******************************************************************/
  1309. HRESULT HrAddLDIFDistList(HWND hWnd,
  1310. LPABCONT lpContainer,
  1311. ULONG cAttributes,
  1312. LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord,
  1313. LPTSTR lpDisplayName,
  1314. LPTSTR lpEmailAddress,
  1315. ULONG cProps,
  1316. LPSPropValue lpspv,
  1317. LPWAB_PROGRESS_CALLBACK lpProgressCB,
  1318. LPWAB_EXPORT_OPTIONS lpOptions)
  1319. {
  1320. HRESULT hResult = S_OK;
  1321. LPMAPIPROP lpDistListWAB = NULL;
  1322. LPDISTLIST lpDLWAB = NULL;
  1323. ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
  1324. REPLACE_INFO RI;
  1325. LPADRLIST lpAdrList = NULL;
  1326. LPFlagList lpfl = NULL;
  1327. ULONG ulcValues = 0;
  1328. LPSPropValue lpPropEID = NULL;
  1329. ULONG i, cbEIDNew;
  1330. LPENTRYID lpEIDNew;
  1331. ULONG ulObjectTypeOpen;
  1332. if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
  1333. {
  1334. ulCreateFlags |= CREATE_REPLACE;
  1335. }
  1336. retry:
  1337. // Create a new wab distlist
  1338. if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
  1339. lpContainer,
  1340. lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.cb,
  1341. (LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.lpb,
  1342. ulCreateFlags,
  1343. (LPMAPIPROP *) &lpDistListWAB)))
  1344. {
  1345. DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
  1346. goto exit;
  1347. }
  1348. // Set the properties on the new WAB entry
  1349. if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SetProps( lpDistListWAB,
  1350. cProps, // cValues
  1351. lpspv, // property array
  1352. NULL))) // problems array
  1353. {
  1354. DebugTrace("LDIFImport:SetProps(WAB) -> %x\n", GetScode(hResult));
  1355. goto exit;
  1356. }
  1357. // Save the new wab mailuser or distlist
  1358. if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SaveChanges(lpDistListWAB,
  1359. KEEP_OPEN_READWRITE | FORCE_SAVE)))
  1360. {
  1361. if (GetScode(hResult) == MAPI_E_COLLISION)
  1362. {
  1363. // Find the display name
  1364. Assert(lpDisplayName);
  1365. if (! lpDisplayName)
  1366. {
  1367. DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
  1368. goto exit;
  1369. }
  1370. // Do we need to prompt?
  1371. if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
  1372. {
  1373. // Prompt user with dialog. If they say YES, we should try again
  1374. RI.lpszDisplayName = lpDisplayName;
  1375. RI.lpszEmailAddress = NULL; //lpEmailAddress;
  1376. RI.ConfirmResult = CONFIRM_ERROR;
  1377. RI.lpImportOptions = lpOptions;
  1378. DialogBoxParam(hInst,
  1379. MAKEINTRESOURCE(IDD_ImportReplace),
  1380. hWnd,
  1381. ReplaceDialogProc,
  1382. (LPARAM)&RI);
  1383. switch (RI.ConfirmResult)
  1384. {
  1385. case CONFIRM_YES:
  1386. case CONFIRM_YES_TO_ALL:
  1387. // YES
  1388. // NOTE: recursive Migrate will fill in the SeenList entry
  1389. // go try again!
  1390. lpDistListWAB->lpVtbl->Release(lpDistListWAB);
  1391. lpDistListWAB = NULL;
  1392. ulCreateFlags |= CREATE_REPLACE;
  1393. goto retry;
  1394. break;
  1395. case CONFIRM_ABORT:
  1396. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  1397. goto exit;
  1398. default:
  1399. // NO
  1400. break;
  1401. }
  1402. }
  1403. hResult = hrSuccess;
  1404. } else
  1405. {
  1406. DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
  1407. }
  1408. }
  1409. // Now we've created the Distribution List object .. we need to add members to it ..
  1410. //
  1411. // What is the ENTRYID of our new entry?
  1412. if ((hResult = lpDistListWAB->lpVtbl->GetProps(lpDistListWAB,
  1413. (LPSPropTagArray)&ptaEid,
  1414. 0,
  1415. &ulcValues,
  1416. &lpPropEID)))
  1417. {
  1418. goto exit;
  1419. }
  1420. cbEIDNew = lpPropEID->Value.bin.cb;
  1421. lpEIDNew = (LPENTRYID) lpPropEID->Value.bin.lpb;
  1422. if(!cbEIDNew || !lpEIDNew)
  1423. goto exit;
  1424. // Open the new WAB DL as a DISTLIST object
  1425. if (HR_FAILED(hResult = lpContainer->lpVtbl->OpenEntry(lpContainer,
  1426. cbEIDNew,
  1427. lpEIDNew,
  1428. (LPIID)&IID_IDistList,
  1429. MAPI_MODIFY,
  1430. &ulObjectTypeOpen,
  1431. (LPUNKNOWN*)&lpDLWAB)))
  1432. {
  1433. goto exit;
  1434. }
  1435. // First we create a lpAdrList with all the members of this dist list and try to resolve
  1436. // the members against the container .. entries that already exist in the WAB will come
  1437. // back as resolved .. entries that dont exist in the container will come back as unresolved
  1438. // We can then add the unresolved entries as fresh entries to the wab (since they are
  1439. // unresolved, there will be no collision) .. and then we can do another resolvenames to
  1440. // resolve everything and get a lpAdrList full of EntryIDs .. we can then take this list of
  1441. // entryids and call CreateEntry or CopyEntry on the DistList object to copy the entryid into
  1442. // the distlist ...
  1443. hResult = HrCreateAdrListFromLDIFRecord(cAttributes, lpLDIFRecord, &lpAdrList);
  1444. if(HR_FAILED(hResult))
  1445. goto exit;
  1446. if(!lpAdrList || !(lpAdrList->cEntries))
  1447. goto exit;
  1448. // Create a corresponding flaglist
  1449. lpfl = LocalAlloc(LMEM_ZEROINIT, sizeof(FlagList) + (lpAdrList->cEntries)*sizeof(ULONG));
  1450. if(!lpfl)
  1451. {
  1452. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  1453. goto exit;
  1454. }
  1455. lpfl->cFlags = lpAdrList->cEntries;
  1456. // set all the flags to unresolved
  1457. for(i=0;i<lpAdrList->cEntries;i++)
  1458. lpfl->ulFlag[i] = MAPI_UNRESOLVED;
  1459. hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
  1460. if(HR_FAILED(hResult))
  1461. goto exit;
  1462. // All the entries in the list that are resolved, already exist in the address book.
  1463. // The ones that are not resolved need to be added silently to the address book ..
  1464. for(i=0;i<lpAdrList->cEntries;i++)
  1465. {
  1466. if(lpfl->ulFlag[i] == MAPI_UNRESOLVED)
  1467. {
  1468. LPMAPIPROP lpMailUser = NULL;
  1469. if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
  1470. lpContainer,
  1471. lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
  1472. (LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
  1473. 0,
  1474. &lpMailUser)))
  1475. {
  1476. continue;
  1477. //goto exit;
  1478. }
  1479. if(lpMailUser)
  1480. {
  1481. // Set the properties on the new WAB entry
  1482. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1483. lpAdrList->aEntries[i].cValues,
  1484. lpAdrList->aEntries[i].rgPropVals,
  1485. NULL)))
  1486. {
  1487. goto exit;
  1488. }
  1489. // Save the new wab mailuser or distlist
  1490. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SaveChanges(lpMailUser,
  1491. KEEP_OPEN_READONLY | FORCE_SAVE)))
  1492. {
  1493. goto exit;
  1494. }
  1495. lpMailUser->lpVtbl->Release(lpMailUser);
  1496. }
  1497. }
  1498. }
  1499. // now that we've added all the unresolved members to the WAB, we call ResolveNames
  1500. // again .. as a result, every member in this list will be resolved and we will
  1501. // have entryids for all of them
  1502. // We will then take these entryids and add them to the DistList object
  1503. hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
  1504. if(HR_FAILED(hResult))
  1505. goto exit;
  1506. for(i=0;i<lpAdrList->cEntries;i++)
  1507. {
  1508. if(lpfl->ulFlag[i] == MAPI_RESOLVED)
  1509. {
  1510. ULONG j = 0;
  1511. LPSPropValue lpProp = lpAdrList->aEntries[i].rgPropVals;
  1512. for(j=0; j<lpAdrList->aEntries[i].cValues; j++)
  1513. {
  1514. if(lpProp[j].ulPropTag == PR_ENTRYID)
  1515. {
  1516. LPMAPIPROP lpMapiProp = NULL;
  1517. //ignore errors
  1518. lpDLWAB->lpVtbl->CreateEntry(lpDLWAB,
  1519. lpProp[j].Value.bin.cb,
  1520. (LPENTRYID) lpProp[j].Value.bin.lpb,
  1521. 0,
  1522. &lpMapiProp);
  1523. if(lpMapiProp)
  1524. {
  1525. lpMapiProp->lpVtbl->SaveChanges(lpMapiProp, KEEP_OPEN_READWRITE | FORCE_SAVE);
  1526. lpMapiProp->lpVtbl->Release(lpMapiProp);
  1527. }
  1528. break;
  1529. }
  1530. }
  1531. }
  1532. }
  1533. exit:
  1534. if (lpPropEID)
  1535. WABFreeBuffer(lpPropEID);
  1536. if (lpDLWAB)
  1537. lpDLWAB->lpVtbl->Release(lpDLWAB);
  1538. if(lpDistListWAB)
  1539. lpDistListWAB->lpVtbl->Release(lpDistListWAB);
  1540. if(lpAdrList)
  1541. WABFreePadrlist(lpAdrList);
  1542. if(lpfl)
  1543. LocalFree(lpfl);
  1544. return hResult;
  1545. }
  1546. HRESULT LDIFImport(HWND hWnd,
  1547. LPADRBOOK lpAdrBook,
  1548. LPWABOBJECT lpWABObject,
  1549. LPWAB_PROGRESS_CALLBACK lpProgressCB,
  1550. LPWAB_EXPORT_OPTIONS lpOptions) {
  1551. HRESULT hResult = hrSuccess;
  1552. TCHAR szFileName[MAX_PATH + 1] = "";
  1553. register ULONG i;
  1554. ULONG ulObjType;
  1555. ULONG index;
  1556. ULONG ulLastChosenProp = 0;
  1557. ULONG ulcFields = 0;
  1558. ULONG cAttributes = 0;
  1559. TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
  1560. WAB_PROGRESS Progress;
  1561. LPABCONT lpContainer = NULL;
  1562. HANDLE hFile = INVALID_HANDLE_VALUE;
  1563. LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord = NULL;
  1564. LPSPropValue lpspv = NULL;
  1565. ULONG cProps;
  1566. BOOL fSkipSetProps;
  1567. LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
  1568. BOOL fDoDistLists = FALSE;
  1569. SetGlobalBufferFunctions(lpWABObject);
  1570. // Get LDIF file name
  1571. OpenFileDialog(hWnd,
  1572. szFileName,
  1573. szLDIFFilter,
  1574. IDS_LDIF_FILE_SPEC,
  1575. szAllFilter,
  1576. IDS_ALL_FILE_SPEC,
  1577. NULL,
  1578. 0,
  1579. szLDIFExt,
  1580. OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
  1581. hInst,
  1582. 0, //idsTitle
  1583. 0); // idsSaveButton
  1584. // Open the file
  1585. if ((hFile = CreateFile(szFileName,
  1586. GENERIC_READ,
  1587. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1588. NULL,
  1589. OPEN_EXISTING,
  1590. FILE_FLAG_SEQUENTIAL_SCAN,
  1591. NULL)) == INVALID_HANDLE_VALUE) {
  1592. DebugTrace("Couldn't open file %s -> %u\n", szFileName, GetLastError());
  1593. return(ResultFromScode(MAPI_E_NOT_FOUND));
  1594. }
  1595. Assert(hFile != INVALID_HANDLE_VALUE);
  1596. // Read in the LDIF version if there is one
  1597. // BUGBUG: NYI
  1598. //
  1599. // Open the WAB's PAB container: fills global lpCreateEIDsWAB
  1600. //
  1601. if (hResult = LoadWABEIDs(lpAdrBook, &lpContainer)) {
  1602. goto exit;
  1603. }
  1604. if( HR_FAILED(hResult = HrLoadPrivateWABProps(lpAdrBook) ))
  1605. {
  1606. goto exit;
  1607. }
  1608. //
  1609. // All set... now loop through the records, adding each to the WAB
  1610. //
  1611. // How many records are there?
  1612. if (hResult = CountLDIFRecords(hFile, &ulcEntries)) {
  1613. goto exit;
  1614. }
  1615. // Initialize the Progress Bar
  1616. Progress.denominator = max(ulcEntries, 1);
  1617. Progress.numerator = 0;
  1618. if (LoadString(hInst, IDS_STATE_IMPORT_MU, szBuffer, sizeof(szBuffer))) {
  1619. DebugTrace("Status Message: %s\n", szBuffer);
  1620. Progress.lpText = szBuffer;
  1621. } else {
  1622. DebugTrace("Cannot load resource string %u\n", IDS_STATE_IMPORT_MU);
  1623. Progress.lpText = NULL;
  1624. }
  1625. lpProgressCB(hWnd, &Progress);
  1626. // We will make 2 passes over the file - in the first pass we will import all the
  1627. // contacts. In the second pass we will import all the distribution lists .. the
  1628. // advantage of doing 2 passes is that when importing contacts, we will prompt on
  1629. // conflict and then when importing distlists, we will assume all contacts in the
  1630. // WAB are correct and just point to the relevant ones
  1631. fDoDistLists = FALSE;
  1632. DoDistLists:
  1633. SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  1634. while (HR_SUCCEEDED(hResult))
  1635. {
  1636. lpDisplayName = NULL;
  1637. lpEmailAddress = NULL;
  1638. lpspv = NULL;
  1639. cAttributes = cProps = 0;
  1640. lpLDIFRecord = NULL;
  1641. // Read the LDIF attributes
  1642. if (hResult = ReadLDIFRecord(hFile, &cAttributes, &lpLDIFRecord)) {
  1643. DebugTrace("ReadLDIFRecord -> %x\n", GetScode(hResult));
  1644. if (GetScode(hResult) == MAPI_E_NOT_FOUND) {
  1645. // EOF
  1646. hResult = hrSuccess;
  1647. }
  1648. break; // nothing more to read
  1649. }
  1650. // Map the LDIF attributes to WAB properties
  1651. if (hResult = MapLDIFtoProps(lpLDIFRecord, cAttributes, &lpspv, &cProps,
  1652. &lpDisplayName, &lpEmailAddress, &ulObjType)) {
  1653. goto exit;
  1654. }
  1655. DebugTrace("..Importing..%s..%s..\n",lpDisplayName?lpDisplayName:"",lpEmailAddress?lpEmailAddress:"");
  1656. if(ulObjType == MAPI_MAILUSER && !fDoDistLists)
  1657. {
  1658. hResult = HrAddLDIFMailUser(hWnd, lpContainer,
  1659. lpDisplayName, lpEmailAddress,
  1660. cProps, lpspv,
  1661. lpProgressCB, lpOptions);
  1662. // Update progress bar
  1663. Progress.numerator++;
  1664. }
  1665. else if(ulObjType == MAPI_DISTLIST && fDoDistLists)
  1666. {
  1667. hResult = HrAddLDIFDistList(hWnd, lpContainer,
  1668. cAttributes, lpLDIFRecord,
  1669. lpDisplayName, lpEmailAddress,
  1670. cProps, lpspv,
  1671. lpProgressCB, lpOptions);
  1672. // Update progress bar
  1673. Progress.numerator++;
  1674. }
  1675. if(HR_FAILED(hResult))
  1676. goto exit;
  1677. // Clean up
  1678. if (lpLDIFRecord)
  1679. {
  1680. FreeLDIFRecord(lpLDIFRecord, cAttributes);
  1681. lpLDIFRecord = NULL;
  1682. }
  1683. Assert(Progress.numerator <= Progress.denominator);
  1684. if (lpspv)
  1685. {
  1686. WABFreeBuffer(lpspv);
  1687. lpspv = NULL;
  1688. }
  1689. lpProgressCB(hWnd, &Progress);
  1690. }
  1691. if(!fDoDistLists)
  1692. {
  1693. // Make a second pass doing only distlists this time
  1694. fDoDistLists = TRUE;
  1695. goto DoDistLists;
  1696. }
  1697. if (! HR_FAILED(hResult)) {
  1698. hResult = hrSuccess;
  1699. }
  1700. exit:
  1701. if (hFile) {
  1702. CloseHandle(hFile);
  1703. }
  1704. if (lpspv) {
  1705. WABFreeBuffer(lpspv);
  1706. lpspv = NULL;
  1707. }
  1708. if (lpLDIFRecord) {
  1709. FreeLDIFRecord(lpLDIFRecord, cAttributes);
  1710. lpLDIFRecord = NULL;
  1711. }
  1712. if (lpContainer) {
  1713. lpContainer->lpVtbl->Release(lpContainer);
  1714. lpContainer = NULL;
  1715. }
  1716. if (lpCreateEIDsWAB) {
  1717. WABFreeBuffer(lpCreateEIDsWAB);
  1718. lpCreateEIDsWAB = NULL;
  1719. }
  1720. return(hResult);
  1721. }
  1722. const int base642six[256]={
  1723. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1724. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  1725. 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  1726. 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  1727. 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  1728. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1729. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1730. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1731. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1732. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1733. 64,64,64,64,64,64,64,64,64,64,64,64,64
  1734. };
  1735. //-------------------------------------------------------------------------------------------
  1736. // Function: decode()
  1737. //-------------------------------------------------------------------------------------------
  1738. BOOL decodeBase64( char * bufcoded, // in
  1739. char * pbuffdecoded, // out
  1740. DWORD * pcbDecoded) // in out
  1741. {
  1742. int nbytesdecoded;
  1743. char *bufin;
  1744. unsigned char *bufout;
  1745. int nprbytes;
  1746. const int *rgiDict = base642six;
  1747. /* Strip leading whitespace. */
  1748. while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
  1749. /* Figure out how many characters are in the input buffer.
  1750. * If this would decode into more bytes than would fit into
  1751. * the output buffer, adjust the number of input bytes downwards.
  1752. */
  1753. bufin = bufcoded;
  1754. while(rgiDict[*(bufin++)] <= 63);
  1755. nprbytes = (int) (bufin - bufcoded - 1);
  1756. nbytesdecoded = ((nprbytes+3)/4) * 3;
  1757. if ( pcbDecoded )
  1758. *pcbDecoded = nbytesdecoded;
  1759. bufout = (unsigned char *)pbuffdecoded;
  1760. bufin = bufcoded;
  1761. while (nprbytes > 0) {
  1762. *(bufout++) =
  1763. (unsigned char) (rgiDict[*bufin] << 2 | rgiDict[bufin[1]] >> 4);
  1764. *(bufout++) =
  1765. (unsigned char) (rgiDict[bufin[1]] << 4 | rgiDict[bufin[2]] >> 2);
  1766. *(bufout++) =
  1767. (unsigned char) (rgiDict[bufin[2]] << 6 | rgiDict[bufin[3]]);
  1768. bufin += 4;
  1769. nprbytes -= 4;
  1770. }
  1771. if(nprbytes & 03) {
  1772. if(rgiDict[bufin[-2]] > 63)
  1773. nbytesdecoded -= 2;
  1774. else
  1775. nbytesdecoded -= 1;
  1776. }
  1777. ((CHAR *)pbuffdecoded)[nbytesdecoded] = '\0';
  1778. return TRUE;
  1779. }
  1780. /*
  1781. - HrLoadPrivateWABProps
  1782. -
  1783. * Private function to load Conferencing Named properties
  1784. * as globals up front
  1785. *
  1786. *
  1787. */
  1788. HRESULT HrLoadPrivateWABProps(LPADRBOOK lpIAB)
  1789. {
  1790. HRESULT hr = E_FAIL;
  1791. LPSPropTagArray lpta = NULL;
  1792. SCODE sc = 0;
  1793. ULONG i, uMax = prWABConfMax, nStartIndex = OLK_NAMEDPROPS_START;
  1794. LPMAPINAMEID *lppConfPropNames = NULL;
  1795. sc = WABAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
  1796. //sc = WABAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
  1797. if( (HR_FAILED(hr = ResultFromScode(sc))) )
  1798. goto err;
  1799. for(i=0;i< uMax;i++)
  1800. {
  1801. //sc = WABAllocateMore(sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
  1802. sc = WABAllocateMore( sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
  1803. if(sc)
  1804. {
  1805. hr = ResultFromScode(sc);
  1806. goto err;
  1807. }
  1808. lppConfPropNames[i]->lpguid = (LPGUID) &PS_Conferencing;
  1809. lppConfPropNames[i]->ulKind = MNID_ID;
  1810. lppConfPropNames[i]->Kind.lID = nStartIndex + i;
  1811. }
  1812. // Load the set of conferencing named props
  1813. //
  1814. if( HR_FAILED(hr = (lpIAB)->lpVtbl->GetIDsFromNames(lpIAB, uMax, lppConfPropNames,
  1815. MAPI_CREATE, &lpta) ))
  1816. goto err;
  1817. if(lpta)
  1818. // Set the property types on the returned props
  1819. PR_SERVERS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfServers], PT_MV_TSTRING);
  1820. rgPropNames[NUM_MORE_EXPORT_PROPS-1].ulPropTag = PR_SERVERS;
  1821. rgPropNames[NUM_MORE_EXPORT_PROPS-1].fChosen = FALSE;
  1822. rgPropNames[NUM_MORE_EXPORT_PROPS-1].ids = ids_ExportConfServer;
  1823. rgPropNames[NUM_MORE_EXPORT_PROPS-1].lpszName = NULL;
  1824. rgPropNames[NUM_MORE_EXPORT_PROPS-1].lpszCSVName = NULL;
  1825. err:
  1826. if(lpta)
  1827. WABFreeBuffer( lpta );
  1828. if( lppConfPropNames )
  1829. WABFreeBuffer( lppConfPropNames );
  1830. //WABFreeBuffer(lpta);
  1831. return hr;
  1832. }