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.

1749 lines
50 KiB

  1. /*
  2. * Messengr.C
  3. *
  4. * Migrate Communicator Messenger NAB <-> 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 MESS
  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 <shlwapi.h>
  30. #define CR_CHAR 0x0d
  31. #define LF_CHAR 0x0a
  32. #define CCH_READ_BUFFER 1024
  33. #define NUM_ITEM_SLOTS 32
  34. /* Messenger address header
  35. 8-Display Name.
  36. 8-Nickname.
  37. 2-?
  38. 8-First Name.
  39. 8-?
  40. 8-last Name
  41. 8-Organization
  42. 8- City
  43. 8-State
  44. 8-e-mail
  45. 8- Notes
  46. 1- FF
  47. 8-Title
  48. 8-Address1
  49. 8-Zip
  50. 8-Work Phone
  51. 8-Fax
  52. 8- House phone.
  53. 18-?
  54. 8-Address
  55. 8-Country.
  56. */
  57. typedef enum _MESS_ATTRIBUTES {
  58. // PR_DISPLAY_NAME
  59. m_DisplayName,
  60. // PR_NICKNAME
  61. m_Nickname, // Netscape nickname
  62. //PR_GIVEN_NAME
  63. m_FirstName,
  64. //PR_SURNAME
  65. m_LastName,
  66. //PR_COMPANY_NAME
  67. m_Organization,
  68. // PR_LOCALITY
  69. m_City, // locality (city)
  70. // PR_STATE_OR_PROVINCE
  71. m_State, // business address state
  72. // PR_EMAIL_ADDRESS
  73. m_Email, // email address
  74. // PR_COMMENT
  75. m_Notes,
  76. //PR_TITLE,
  77. m_Title,
  78. // PR_STREET_ADDRESS
  79. m_StreetAddress2,
  80. // PR_POSTAL_CODE
  81. m_Zip, // business address zip code
  82. // PR_BUSINESS_TELEPHONE_NUMBER
  83. m_WorkPhone,
  84. // PR_BUSINESS_FAX_NUMBER
  85. m_Fax,
  86. // PR_HOME_TELEPHONE_NUMBER
  87. m_HomePhone,
  88. // PR_STREET_ADDRESS
  89. m_StreetAddress1,
  90. // PR_COUNTRY
  91. m_Country, // country
  92. m_Max,
  93. } MESS_ATTRIBUTES, *LPMESS_ATTRIBUTES;
  94. ULONG ulDefPropTags[] =
  95. {
  96. PR_DISPLAY_NAME,
  97. PR_NICKNAME,
  98. PR_GIVEN_NAME,
  99. PR_SURNAME,
  100. PR_COMPANY_NAME,
  101. PR_LOCALITY,
  102. PR_STATE_OR_PROVINCE,
  103. PR_EMAIL_ADDRESS,
  104. PR_COMMENT,
  105. PR_TITLE,
  106. PR_STREET_ADDRESS,
  107. PR_POSTAL_CODE,
  108. PR_BUSINESS_TELEPHONE_NUMBER,
  109. PR_BUSINESS_FAX_NUMBER,
  110. PR_HOME_TELEPHONE_NUMBER,
  111. PR_STREET_ADDRESS,
  112. PR_COUNTRY,
  113. };
  114. // All props are string props
  115. typedef struct _MESS_RECORD {
  116. LPTSTR lpData[m_Max];
  117. ULONG ulObjectType;
  118. } MESS_RECORD, *LPMESS_RECORD;
  119. typedef struct _MESS_HEADER_ATTRIBUTES {
  120. ULONG ulOffSet;
  121. ULONG ulSize;
  122. } MH_ATTR, * LPMH_ATTR;
  123. typedef struct _MESS_BASIC_PROPS {
  124. LPTSTR lpName;
  125. LPTSTR lpEmail;
  126. LPTSTR lpComment;
  127. } MP_BASIC, * LPMP_BASIC;
  128. typedef struct _MESS_STUFF {
  129. ULONG ulOffSet;
  130. ULONG ulNum;
  131. MP_BASIC bp;
  132. } MH_STUFF, * LPMH_STUFF;
  133. typedef struct _MESS_ADDRESS_HEADER {
  134. MH_ATTR prop[m_Max];
  135. } MESS_HEADER, * LPMESS_HEADER;
  136. // Must have
  137. // PR_DISPLAY_NAME
  138. #define NUM_MUST_HAVE_PROPS 1
  139. const TCHAR szMESSFilter[] = "*.nab";
  140. const TCHAR szMESSExt[] = "nab";
  141. /*****************************************************************
  142. HrCreateAdrListFromMESSRecord
  143. Scans an MESS record and turns all the "members" into an
  144. unresolved AdrList
  145. ******************************************************************/
  146. HRESULT HrCreateAdrListFromMESSRecord(ULONG nMembers,
  147. LPMP_BASIC lpmp,
  148. LPADRLIST * lppAdrList)
  149. {
  150. HRESULT hr = S_OK;
  151. ULONG i;
  152. LPADRLIST lpAdrList = NULL;
  153. ULONG ulCount = 0;
  154. *lppAdrList = NULL;
  155. if(!nMembers)
  156. goto exit;
  157. // Now create a adrlist from these members
  158. // Allocate prop value array
  159. if (hr = ResultFromScode(WABAllocateBuffer(sizeof(ADRLIST) + nMembers * sizeof(ADRENTRY), &lpAdrList)))
  160. goto exit;
  161. ulCount = nMembers;
  162. nMembers = 0;
  163. for(i=0;i<ulCount;i++)
  164. {
  165. LPTSTR lpName = lpmp[i].lpName;
  166. LPTSTR lpEmail = lpmp[i].lpEmail;
  167. if(lpName)
  168. {
  169. LPSPropValue lpProp = NULL;
  170. ULONG ulcProps = 2;
  171. if (hr = ResultFromScode(WABAllocateBuffer(2 * sizeof(SPropValue), &lpProp)))
  172. goto exit;
  173. lpProp[0].ulPropTag = PR_DISPLAY_NAME;
  174. if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpName)+1, lpProp, &(lpProp[0].Value.lpszA))))
  175. goto exit;
  176. StrCpyN(lpProp[0].Value.lpszA, lpName, lstrlen(lpName)+1);
  177. if(lpEmail)
  178. {
  179. lpProp[1].ulPropTag = PR_EMAIL_ADDRESS;
  180. if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpEmail)+1, lpProp, &(lpProp[1].Value.lpszA))))
  181. goto exit;
  182. StrCpyN(lpProp[1].Value.lpszA, lpEmail, lstrlen(lpEmail)+1);
  183. }
  184. lpAdrList->aEntries[nMembers].cValues = (lpEmail ? 2 : 1);
  185. lpAdrList->aEntries[nMembers].rgPropVals = lpProp;
  186. nMembers++;
  187. }
  188. }
  189. lpAdrList->cEntries = nMembers;
  190. *lppAdrList = lpAdrList;
  191. exit:
  192. if(HR_FAILED(hr) && lpAdrList)
  193. WABFreePadrlist(lpAdrList);
  194. return hr;
  195. }
  196. /*****************************************************************
  197. HraddMESSDistList - adds a distlist and its members to the WAB
  198. Sequence of events will be:
  199. - Create a DistList object
  200. - Set the properties on the DistList object
  201. - Scan the list of members for the given dist list object
  202. - Add each member to the wab .. if member already exists,
  203. prompt to replace etc ...if it doesnt exist, create new
  204. ******************************************************************/
  205. HRESULT HrAddMESSDistList(HWND hWnd,
  206. LPABCONT lpContainer,
  207. MH_STUFF HeadDL,
  208. ULONG ulcNumDLMembers,
  209. LPMP_BASIC lpmp,
  210. LPWAB_PROGRESS_CALLBACK lpProgressCB,
  211. LPWAB_EXPORT_OPTIONS lpOptions)
  212. {
  213. HRESULT hResult = S_OK;
  214. LPMAPIPROP lpDistListWAB = NULL;
  215. LPDISTLIST lpDLWAB = NULL;
  216. ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
  217. REPLACE_INFO RI;
  218. LPADRLIST lpAdrList = NULL;
  219. LPFlagList lpfl = NULL;
  220. ULONG ulcValues = 0;
  221. LPSPropValue lpPropEID = NULL;
  222. ULONG i, cbEIDNew;
  223. LPENTRYID lpEIDNew;
  224. ULONG ulObjectTypeOpen;
  225. SPropValue Prop[3];
  226. ULONG cProps = 0;
  227. LPTSTR lpDisplayName = HeadDL.bp.lpName;
  228. Prop[cProps].ulPropTag = PR_DISPLAY_NAME;
  229. Prop[cProps].Value.LPSZ = HeadDL.bp.lpName;
  230. if(!HeadDL.bp.lpName)
  231. return MAPI_E_INVALID_PARAMETER;
  232. cProps++;
  233. Prop[cProps].ulPropTag = PR_OBJECT_TYPE;
  234. Prop[cProps].Value.l = MAPI_DISTLIST;
  235. cProps++;
  236. if(HeadDL.bp.lpComment)
  237. {
  238. Prop[cProps].ulPropTag = PR_COMMENT;
  239. Prop[cProps].Value.LPSZ = HeadDL.bp.lpComment;
  240. cProps++;
  241. }
  242. //if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
  243. // Force a replace - collision will only be for groups and we dont care really
  244. {
  245. ulCreateFlags |= CREATE_REPLACE;
  246. }
  247. retry:
  248. // Create a new wab distlist
  249. if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
  250. lpContainer,
  251. lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.cb,
  252. (LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.lpb,
  253. ulCreateFlags,
  254. (LPMAPIPROP *) &lpDistListWAB)))
  255. {
  256. DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
  257. goto exit;
  258. }
  259. // Set the properties on the new WAB entry
  260. if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SetProps( lpDistListWAB,
  261. cProps, // cValues
  262. (LPSPropValue) &Prop, // property array
  263. NULL))) // problems array
  264. {
  265. goto exit;
  266. }
  267. // Save the new wab mailuser or distlist
  268. if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SaveChanges(lpDistListWAB,
  269. KEEP_OPEN_READWRITE | FORCE_SAVE)))
  270. {
  271. if (GetScode(hResult) == MAPI_E_COLLISION)
  272. {
  273. // Find the display name
  274. Assert(lpDisplayName);
  275. if (! lpDisplayName)
  276. {
  277. DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
  278. goto exit;
  279. }
  280. // Do we need to prompt?
  281. if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
  282. {
  283. // Prompt user with dialog. If they say YES, we should try again
  284. RI.lpszDisplayName = lpDisplayName;
  285. RI.lpszEmailAddress = NULL; //lpEmailAddress;
  286. RI.ConfirmResult = CONFIRM_ERROR;
  287. RI.lpImportOptions = lpOptions;
  288. DialogBoxParam(hInst,
  289. MAKEINTRESOURCE(IDD_ImportReplace),
  290. hWnd,
  291. ReplaceDialogProc,
  292. (LPARAM)&RI);
  293. switch (RI.ConfirmResult)
  294. {
  295. case CONFIRM_YES:
  296. case CONFIRM_YES_TO_ALL:
  297. // YES
  298. // NOTE: recursive Migrate will fill in the SeenList entry
  299. // go try again!
  300. lpDistListWAB->lpVtbl->Release(lpDistListWAB);
  301. lpDistListWAB = NULL;
  302. ulCreateFlags |= CREATE_REPLACE;
  303. goto retry;
  304. break;
  305. case CONFIRM_ABORT:
  306. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  307. goto exit;
  308. default:
  309. // NO
  310. break;
  311. }
  312. }
  313. hResult = hrSuccess;
  314. } else
  315. {
  316. DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
  317. }
  318. }
  319. // Now we've created the Distribution List object .. we need to add members to it ..
  320. //
  321. // What is the ENTRYID of our new entry?
  322. if ((hResult = lpDistListWAB->lpVtbl->GetProps(lpDistListWAB,
  323. (LPSPropTagArray)&ptaEid,
  324. 0,
  325. &ulcValues,
  326. &lpPropEID)))
  327. {
  328. goto exit;
  329. }
  330. cbEIDNew = lpPropEID->Value.bin.cb;
  331. lpEIDNew = (LPENTRYID) lpPropEID->Value.bin.lpb;
  332. if(!cbEIDNew || !lpEIDNew)
  333. goto exit;
  334. // Open the new WAB DL as a DISTLIST object
  335. if (HR_FAILED(hResult = lpContainer->lpVtbl->OpenEntry(lpContainer,
  336. cbEIDNew,
  337. lpEIDNew,
  338. (LPIID)&IID_IDistList,
  339. MAPI_MODIFY,
  340. &ulObjectTypeOpen,
  341. (LPUNKNOWN*)&lpDLWAB)))
  342. {
  343. goto exit;
  344. }
  345. if(!ulcNumDLMembers)
  346. {
  347. hResult = S_OK;
  348. goto exit;
  349. }
  350. // First we create a lpAdrList with all the members of this dist list and try to resolve
  351. // the members against the container .. entries that already exist in the WAB will come
  352. // back as resolved .. entries that dont exist in the container will come back as unresolved
  353. // We can then add the unresolved entries as fresh entries to the wab (since they are
  354. // unresolved, there will be no collision) .. and then we can do another resolvenames to
  355. // resolve everything and get a lpAdrList full of EntryIDs .. we can then take this list of
  356. // entryids and call CreateEntry or CopyEntry on the DistList object to copy the entryid into
  357. // the distlist ...
  358. hResult = HrCreateAdrListFromMESSRecord(ulcNumDLMembers, lpmp, &lpAdrList);
  359. if(HR_FAILED(hResult))
  360. goto exit;
  361. if(!lpAdrList || !(lpAdrList->cEntries))
  362. goto exit;
  363. // Create a corresponding flaglist
  364. lpfl = LocalAlloc(LMEM_ZEROINIT, sizeof(FlagList) + (lpAdrList->cEntries)*sizeof(ULONG));
  365. if(!lpfl)
  366. {
  367. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  368. goto exit;
  369. }
  370. lpfl->cFlags = lpAdrList->cEntries;
  371. // set all the flags to unresolved
  372. for(i=0;i<lpAdrList->cEntries;i++)
  373. lpfl->ulFlag[i] = MAPI_UNRESOLVED;
  374. hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
  375. if(HR_FAILED(hResult))
  376. goto exit;
  377. // All the entries in the list that are resolved, already exist in the address book.
  378. // The ones that are not resolved need to be added silently to the address book ..
  379. for(i=0;i<lpAdrList->cEntries;i++)
  380. {
  381. if(lpfl->ulFlag[i] == MAPI_UNRESOLVED)
  382. {
  383. LPMAPIPROP lpMailUser = NULL;
  384. if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
  385. lpContainer,
  386. lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
  387. (LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
  388. 0,
  389. &lpMailUser)))
  390. {
  391. continue;
  392. //goto exit;
  393. }
  394. if(lpMailUser)
  395. {
  396. // Set the properties on the new WAB entry
  397. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  398. lpAdrList->aEntries[i].cValues,
  399. lpAdrList->aEntries[i].rgPropVals,
  400. NULL)))
  401. {
  402. goto exit;
  403. }
  404. // Save the new wab mailuser or distlist
  405. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SaveChanges(lpMailUser,
  406. KEEP_OPEN_READONLY | FORCE_SAVE)))
  407. {
  408. goto exit;
  409. }
  410. lpMailUser->lpVtbl->Release(lpMailUser);
  411. }
  412. }
  413. }
  414. // now that we've added all the unresolved members to the WAB, we call ResolveNames
  415. // again .. as a result, every member in this list will be resolved and we will
  416. // have entryids for all of them
  417. // We will then take these entryids and add them to the DistList object
  418. hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
  419. if(hResult==MAPI_E_AMBIGUOUS_RECIP)
  420. hResult = S_OK;
  421. if(HR_FAILED(hResult))
  422. goto exit;
  423. for(i=0;i<lpAdrList->cEntries;i++)
  424. {
  425. if(lpfl->ulFlag[i] == MAPI_RESOLVED)
  426. {
  427. ULONG j = 0;
  428. LPSPropValue lpProp = lpAdrList->aEntries[i].rgPropVals;
  429. for(j=0; j<lpAdrList->aEntries[i].cValues; j++)
  430. {
  431. if(lpProp[j].ulPropTag == PR_ENTRYID)
  432. {
  433. LPMAPIPROP lpMapiProp = NULL;
  434. //ignore errors
  435. lpDLWAB->lpVtbl->CreateEntry(lpDLWAB,
  436. lpProp[j].Value.bin.cb,
  437. (LPENTRYID) lpProp[j].Value.bin.lpb,
  438. 0,
  439. &lpMapiProp);
  440. if(lpMapiProp)
  441. {
  442. lpMapiProp->lpVtbl->SaveChanges(lpMapiProp, KEEP_OPEN_READWRITE | FORCE_SAVE);
  443. lpMapiProp->lpVtbl->Release(lpMapiProp);
  444. }
  445. break;
  446. }
  447. }
  448. }
  449. }
  450. exit:
  451. if (lpPropEID)
  452. WABFreeBuffer(lpPropEID);
  453. if (lpDLWAB)
  454. lpDLWAB->lpVtbl->Release(lpDLWAB);
  455. if(lpDistListWAB)
  456. lpDistListWAB->lpVtbl->Release(lpDistListWAB);
  457. if(lpAdrList)
  458. WABFreePadrlist(lpAdrList);
  459. if(lpfl)
  460. LocalFree(lpfl);
  461. return hResult;
  462. }
  463. /*********************************************************
  464. HraddMESSMailUser - adds a mailuser to the WAB
  465. **********************************************************/
  466. HRESULT HrAddMESSMailUser(HWND hWnd,
  467. LPABCONT lpContainer,
  468. LPTSTR lpDisplayName,
  469. LPTSTR lpEmailAddress,
  470. ULONG cProps,
  471. LPSPropValue lpspv,
  472. LPWAB_PROGRESS_CALLBACK lpProgressCB,
  473. LPWAB_EXPORT_OPTIONS lpOptions)
  474. {
  475. HRESULT hResult = S_OK;
  476. LPMAPIPROP lpMailUserWAB = NULL;
  477. ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
  478. REPLACE_INFO RI;
  479. if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
  480. {
  481. ulCreateFlags |= CREATE_REPLACE;
  482. }
  483. retry:
  484. // Create a new wab mailuser
  485. if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
  486. lpContainer,
  487. lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
  488. (LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
  489. ulCreateFlags,
  490. &lpMailUserWAB)))
  491. {
  492. DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
  493. goto exit;
  494. }
  495. // Set the properties on the new WAB entry
  496. if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SetProps( lpMailUserWAB,
  497. cProps, // cValues
  498. lpspv, // property array
  499. NULL))) // problems array
  500. {
  501. goto exit;
  502. }
  503. // Save the new wab mailuser or distlist
  504. if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SaveChanges(lpMailUserWAB,
  505. KEEP_OPEN_READONLY | FORCE_SAVE)))
  506. {
  507. if (GetScode(hResult) == MAPI_E_COLLISION)
  508. {
  509. // Find the display name
  510. Assert(lpDisplayName);
  511. if (! lpDisplayName)
  512. {
  513. DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
  514. goto exit;
  515. }
  516. // Do we need to prompt?
  517. if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
  518. {
  519. // Prompt user with dialog. If they say YES, we should try again
  520. RI.lpszDisplayName = lpDisplayName;
  521. RI.lpszEmailAddress = lpEmailAddress;
  522. RI.ConfirmResult = CONFIRM_ERROR;
  523. RI.lpImportOptions = lpOptions;
  524. DialogBoxParam(hInst,
  525. MAKEINTRESOURCE(IDD_ImportReplace),
  526. hWnd,
  527. ReplaceDialogProc,
  528. (LPARAM)&RI);
  529. switch (RI.ConfirmResult)
  530. {
  531. case CONFIRM_YES:
  532. case CONFIRM_YES_TO_ALL:
  533. // YES
  534. // NOTE: recursive Migrate will fill in the SeenList entry
  535. // go try again!
  536. lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
  537. lpMailUserWAB = NULL;
  538. ulCreateFlags |= CREATE_REPLACE;
  539. goto retry;
  540. break;
  541. case CONFIRM_ABORT:
  542. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  543. goto exit;
  544. default:
  545. // NO
  546. break;
  547. }
  548. }
  549. hResult = hrSuccess;
  550. } else
  551. {
  552. DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
  553. }
  554. }
  555. exit:
  556. if(lpMailUserWAB)
  557. lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
  558. return hResult;
  559. }
  560. /***************************************************************************
  561. Name : MapMESSRecordtoProps
  562. Purpose : Map the MESS record attributes to WAB properties
  563. Parameters: lpMESSRecord -> MESS record
  564. lpspv -> prop value array (pre-allocated)
  565. lpcProps -> returned number of properties
  566. lppDisplayName -> returned display name
  567. lppEmailAddress -> returned email address (or NULL)
  568. Returns : HRESULT
  569. ***************************************************************************/
  570. HRESULT MapMESSRecordtoProps( LPMESS_RECORD lpMESSRecord,
  571. LPSPropValue * lppspv, LPULONG lpcProps,
  572. LPTSTR * lppDisplayName, LPTSTR *lppEmailAddress)
  573. {
  574. HRESULT hResult = hrSuccess;
  575. ULONG cPropVals = m_Max + 1; // PR_OBJECT_TYPE
  576. ULONG iProp = 0;
  577. ULONG i;
  578. ULONG iTable;
  579. ULONG cProps = cPropVals;
  580. // Allocate prop value array
  581. if (hResult = ResultFromScode(WABAllocateBuffer(cProps * sizeof(SPropValue), lppspv))) {
  582. DebugTrace("WABAllocateBuffer -> %x\n", GetScode(hResult));
  583. goto exit;
  584. }
  585. // Fill with PR_NULL
  586. for (i = 0; i < cProps; i++) {
  587. (*lppspv)[i].ulPropTag = PR_NULL;
  588. }
  589. iProp = 0;
  590. for(i=0; i<m_Max; i++)
  591. {
  592. if(lpMESSRecord->lpData[i] && lstrlen(lpMESSRecord->lpData[i]))
  593. {
  594. (*lppspv)[iProp].ulPropTag = ulDefPropTags[i];
  595. (*lppspv)[iProp].Value.LPSZ = lpMESSRecord->lpData[i];
  596. switch((*lppspv)[iProp].ulPropTag)
  597. {
  598. case PR_DISPLAY_NAME:
  599. *lppDisplayName = (*lppspv)[iProp].Value.LPSZ;
  600. break;
  601. case PR_EMAIL_ADDRESS:
  602. *lppEmailAddress = (*lppspv)[iProp].Value.LPSZ;
  603. break;
  604. }
  605. iProp++;
  606. }
  607. }
  608. (*lppspv)[iProp].ulPropTag = PR_OBJECT_TYPE;
  609. (*lppspv)[iProp].Value.l = lpMESSRecord->ulObjectType;
  610. *lpcProps = iProp;
  611. exit:
  612. return(hResult);
  613. }
  614. /***************************************************************************
  615. Name : FreeMESSRecord
  616. Purpose : Frees an MESS record structure
  617. Parameters: lpMESSRecord -> record to clean up
  618. ulAttributes = number of attributes in lpMESSRecord
  619. Returns : none
  620. Comment :
  621. ***************************************************************************/
  622. void FreeMESSRecord(LPMESS_RECORD lpMESSRecord)
  623. {
  624. ULONG i;
  625. if (lpMESSRecord)
  626. {
  627. for (i = 0; i < m_Max; i++)
  628. {
  629. if (lpMESSRecord->lpData[i])
  630. LocalFree(lpMESSRecord->lpData[i]);
  631. }
  632. LocalFree(lpMESSRecord);
  633. }
  634. }
  635. /***************************************************************************
  636. FunctionName: GetOffSet
  637. Purpose : Gets 4 bytes from the offset specified.
  638. Parameters : hFile -pointer to the file
  639. Offset-Offset of the
  640. OffSetValue -the returned 4 bytes.
  641. Returns :
  642. Note :
  643. ***************************************************************************/
  644. BOOL GetOffSet(HANDLE hFile, DWORD Offset, ULONG* lpOffSetValue)
  645. {
  646. BYTE Value[4];
  647. DWORD dwRead = 0;
  648. SetFilePointer(hFile, Offset, NULL, FILE_BEGIN);
  649. ReadFile(hFile, Value, 4, &dwRead, NULL);
  650. *(lpOffSetValue)= (ULONG)Value[0]*16777216 + (ULONG)Value[1]*65536 + (ULONG)Value[2]*256 + (ULONG)Value[3];
  651. return TRUE;
  652. }
  653. /******************************************************************************
  654. * FUNCTION NAME:GetMESSFileName
  655. *
  656. * PURPOSE: Gets the Messenger Address book file name
  657. *
  658. * PARAMETERS: szFileName = buffer containing the installation path
  659. // Messenger abook is generally abook.nab
  660. // Location can be found under
  661. // HKLM\Software\Netscape\Netscape Navigator\Users\defaultuser
  662. // Look for "DirRoot"
  663. *
  664. * RETURNS: HRESULT
  665. ******************************************************************************/
  666. HRESULT GetNABPath(LPTSTR szFileName, DWORD cbFileName)
  667. {
  668. HKEY phkResult = NULL;
  669. LONG Registry;
  670. BOOL bResult;
  671. TCHAR *lpData = NULL, *RegPath = NULL, *path = NULL;
  672. DWORD dwSize = cbFileName;
  673. LPTSTR lpRegMess = TEXT("Software\\Netscape\\Netscape Navigator\\Users");
  674. LPTSTR lpRegUser = TEXT("CurrentUser");
  675. LPTSTR lpRegKey = TEXT("DirRoot");
  676. LPTSTR lpNABFile = TEXT("\\abook.nab");
  677. HRESULT hResult = S_OK;
  678. TCHAR szUser[MAX_PATH];
  679. TCHAR szUserPath[2*MAX_PATH];
  680. *szFileName = '\0';
  681. *szUser ='\0';
  682. // Open the Netscape..Users key
  683. Registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegMess, 0, KEY_QUERY_VALUE, &phkResult);
  684. if (Registry != ERROR_SUCCESS)
  685. {
  686. hResult = E_FAIL;
  687. goto error;
  688. }
  689. // Look for the CurrentUser
  690. dwSize = sizeof(szUser);
  691. Registry = RegQueryValueEx(phkResult, lpRegUser, NULL, NULL, (LPBYTE)szUser, &dwSize);
  692. if (Registry != ERROR_SUCCESS)
  693. {
  694. hResult = E_FAIL;
  695. goto error;
  696. }
  697. if(!lstrlen(szUser))
  698. {
  699. hResult = E_FAIL;
  700. goto error;
  701. }
  702. if (phkResult) {
  703. RegCloseKey(phkResult);
  704. }
  705. //Now concatenate the currentuser to the end of the Netscape key and reopen
  706. StrCpyN(szUserPath, lpRegMess, ARRAYSIZE(szUserPath));
  707. StrCatBuff(szUserPath, TEXT("\\"), ARRAYSIZE(szUserPath));
  708. StrCatBuff(szUserPath, szUser, ARRAYSIZE(szUserPath));
  709. // Open the Netscape..Users key
  710. Registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szUserPath, 0, KEY_QUERY_VALUE, &phkResult);
  711. if (Registry != ERROR_SUCCESS)
  712. {
  713. hResult = E_FAIL;
  714. goto error;
  715. }
  716. dwSize = cbFileName;
  717. Registry = RegQueryValueEx(phkResult, lpRegKey, NULL, NULL, (LPBYTE)szFileName, &dwSize);
  718. if (Registry != ERROR_SUCCESS)
  719. {
  720. hResult = E_FAIL;
  721. goto error;
  722. }
  723. // concatenate the file name to this directory path
  724. StrCatBuff(szFileName,lpNABFile, cbFileName/sizeof(szFileName[0]));
  725. error:
  726. if (phkResult) {
  727. RegCloseKey(phkResult);
  728. }
  729. return(hResult);
  730. }
  731. HRESULT ReadMESSHeader(HANDLE hFile, LPMESS_HEADER lpmh, ULONG ulOffSet)
  732. {
  733. ULONG ulMagicNumber = 0;
  734. HRESULT hr = E_FAIL;
  735. DWORD dwRead;
  736. ULONG i = 0;
  737. // Skip 2 bytes
  738. SetFilePointer(hFile, 2, NULL, FILE_CURRENT);
  739. ulOffSet += 2;
  740. GetOffSet(hFile, ulOffSet, &ulMagicNumber);
  741. if(ulMagicNumber != 0x00000001 )
  742. goto exit;
  743. ulOffSet += 4;
  744. for(i=0;i<m_Max;i++)
  745. {
  746. switch(i)
  747. {
  748. case m_FirstName:
  749. ulOffSet += 2;
  750. break;
  751. case m_LastName:
  752. ulOffSet += 8;
  753. break;
  754. case m_Title:
  755. ulOffSet += 1;
  756. break;
  757. case m_StreetAddress1:
  758. ulOffSet += 18;
  759. break;
  760. }
  761. GetOffSet(hFile, ulOffSet, &(lpmh->prop[i].ulOffSet));
  762. ulOffSet += 4;
  763. GetOffSet(hFile, ulOffSet, &(lpmh->prop[i].ulSize));
  764. ulOffSet += 4;
  765. }
  766. hr = S_OK;
  767. exit:
  768. return hr;
  769. }
  770. /***************************************************************************
  771. FunctionName: GetHeaders
  772. Purpose :Reads the binary trees ( address binary tree or Dls binary tree) into an array.
  773. Parameters : nLayer= Number of layers in the binary tree.
  774. Offset= Primary offset of the binary tree.
  775. pHeaders= Array in which the Address entry header offsets and their numbers are to be stored.
  776. bflag = 1 should be passed when this recursive function is called for the first time.
  777. Returns :
  778. Note : //This function is a recursive function which reads the binary tree and stores the Offset values
  779. and the address numbers in a Array.
  780. ***************************************************************************/
  781. BOOL GetHeaders(HANDLE pFile, int nLayer, ULONG Offset, LPMH_STUFF pHeaders, BOOL bflag)
  782. {
  783. static ULONG ulCount =0; //keeps trecat of the number of element
  784. ULONG nLoops =0;
  785. ULONG ulNewOffset =0;
  786. ULONG ulElement = 0;
  787. if(bflag==1)
  788. ulCount =0;
  789. //get the number of elements in this header
  790. if(Offset==0)
  791. nLoops=32;
  792. else
  793. {
  794. GetOffSet( pFile, Offset+4,&nLoops);
  795. nLoops &= 0x0000FFFF;
  796. }
  797. for(ulElement = 0; ulElement < nLoops; ulElement++)
  798. {
  799. if(nLayer > 0)
  800. {
  801. ulNewOffset=0;
  802. if(Offset!=0)
  803. {
  804. GetOffSet(pFile, Offset+8+(ulElement*4), &ulNewOffset);
  805. {
  806. ULONG ulMagicNumber=0;
  807. GetOffSet(pFile,ulNewOffset+2,&ulMagicNumber);
  808. if(ulMagicNumber != 1)
  809. ulNewOffset = 0;
  810. }
  811. }
  812. //call this function recursively
  813. GetHeaders( pFile, nLayer-1, ulNewOffset, pHeaders, 0);
  814. }
  815. else
  816. {
  817. //fill the array here (offset)
  818. pHeaders[ulCount].ulOffSet=pHeaders[ulCount].ulNum=0;
  819. if(Offset!=0)
  820. {
  821. GetOffSet(pFile, Offset+8+(ulElement*8),& (pHeaders[ulCount].ulOffSet));
  822. //fill the array element here (address number in case of addresses and size in case of messages)
  823. if(!GetOffSet(pFile, Offset+12+(ulElement*8), &(pHeaders[ulCount].ulNum)))
  824. {
  825. pHeaders[ulCount].ulNum=0;
  826. }
  827. }
  828. ulCount++; //increment the count
  829. }
  830. }
  831. return TRUE;
  832. }
  833. /***************************************************************************
  834. Name : ReadMESSRecord
  835. Purpose : Reads a record from an MESS file with fixups for special characters
  836. Parameters: hFile = file handle
  837. Returns : HRESULT
  838. ***************************************************************************/
  839. HRESULT ReadMESSRecord(HANDLE hFile, LPMESS_RECORD * lppMESSRecord, ULONG ulContactOffset)
  840. {
  841. HRESULT hResult = hrSuccess;
  842. PUCHAR lpBuffer = NULL;
  843. ULONG cbBuffer = 0;
  844. ULONG cbReadFile = 1;
  845. ULONG iItem = 0;
  846. ULONG cAttributes = 0;
  847. BOOL fEOR = FALSE;
  848. LPMESS_RECORD lpMESSRecord = NULL;
  849. LPBYTE lpData = NULL;
  850. LPTSTR lpName = NULL;
  851. ULONG cbData;
  852. TCHAR szTemp[2048]; // 2k limit
  853. ULONG i = 0;
  854. DWORD dwRead = 0;
  855. ULONG cchSize = 0;
  856. MESS_HEADER mh = {0};
  857. // The Contact Offset gives us the offset of the header for this record - the
  858. // header contains the offset and the size of each property for that address
  859. if(hResult = ReadMESSHeader(hFile, &mh, ulContactOffset))
  860. goto exit;
  861. lpMESSRecord = LocalAlloc(LMEM_ZEROINIT, sizeof(MESS_RECORD));
  862. if(!lpMESSRecord)
  863. {
  864. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  865. goto exit;
  866. }
  867. lpMESSRecord->ulObjectType = MAPI_MAILUSER;
  868. for(i=0;i<m_Max;i++)
  869. {
  870. if(mh.prop[i].ulSize)
  871. {
  872. if(i == m_StreetAddress1)
  873. {
  874. cchSize = mh.prop[i].ulSize + mh.prop[m_StreetAddress2].ulSize + 8;
  875. lpMESSRecord->lpData[i] = LocalAlloc(LMEM_ZEROINIT, cchSize);
  876. }
  877. else
  878. lpMESSRecord->lpData[i] = LocalAlloc(LMEM_ZEROINIT, mh.prop[i].ulSize);
  879. if(lpMESSRecord->lpData[i])
  880. {
  881. SetFilePointer(hFile, mh.prop[i].ulOffSet, NULL, FILE_BEGIN);
  882. ReadFile(hFile, (LPVOID) lpMESSRecord->lpData[i], mh.prop[i].ulSize, &dwRead, NULL);
  883. lpMESSRecord->lpData[i][mh.prop[i].ulSize-1] = '\0';
  884. }
  885. }
  886. }
  887. //Fix the fact that the street address is split into street1 and street2
  888. if(lpMESSRecord->lpData[m_StreetAddress1] && lpMESSRecord->lpData[m_StreetAddress2] &&
  889. lstrlen(lpMESSRecord->lpData[m_StreetAddress1]) && lstrlen(lpMESSRecord->lpData[m_StreetAddress2]))
  890. {
  891. StrCatBuff(lpMESSRecord->lpData[m_StreetAddress1], TEXT("\r\n"), cchSize);
  892. StrCatBuff(lpMESSRecord->lpData[m_StreetAddress1], lpMESSRecord->lpData[m_StreetAddress2], cchSize);
  893. LocalFree(lpMESSRecord->lpData[m_StreetAddress2]);
  894. lpMESSRecord->lpData[m_StreetAddress2] = NULL;
  895. }
  896. *lppMESSRecord = lpMESSRecord;
  897. exit:
  898. return(hResult);
  899. }
  900. /***************************************************************************
  901. GetAllDLNames
  902. Purpose : Gets the Names of all the DLs.
  903. Note :
  904. ***************************************************************************/
  905. BOOL GetAllDLNames(HANDLE pFile, ULONG nDLs, LPMH_STUFF pHeadersDL)
  906. {
  907. ULONG i = 0;
  908. for(i=0;i<nDLs;i++)
  909. {
  910. ULONG ulDLDispNameOffset=0;
  911. ULONG ulDLDispNameSize=0;
  912. ULONG ulDLCommentOffSet = 0;
  913. ULONG ulDLCommentSize = 0;
  914. DWORD dwRead = 0;
  915. LPTSTR szComment = 0;
  916. LPTSTR szSubject = NULL;
  917. ULONG ulDLOffset = pHeadersDL[i].ulOffSet;
  918. //get the diplay name of the DL.
  919. if(FALSE==GetOffSet(pFile, ulDLOffset+6,&ulDLDispNameOffset))
  920. return FALSE;
  921. if(FALSE==GetOffSet(pFile,ulDLOffset+10,&ulDLDispNameSize))
  922. return FALSE;
  923. if(ulDLDispNameSize)
  924. {
  925. if((szSubject= LocalAlloc(LMEM_ZEROINIT, ulDLDispNameSize))==NULL)
  926. return FALSE;
  927. SetFilePointer(pFile, ulDLDispNameOffset, NULL, FILE_BEGIN);
  928. ReadFile(pFile, (LPVOID) szSubject, ulDLDispNameSize, &dwRead, NULL);
  929. szSubject[ulDLDispNameSize-1] = '\0';
  930. pHeadersDL[i].bp.lpName = szSubject;
  931. }
  932. // Get the Comment for the DL
  933. if(FALSE==GetOffSet(pFile,ulDLOffset+44,&ulDLCommentOffSet))
  934. return FALSE;
  935. if(FALSE==GetOffSet(pFile,ulDLOffset+48,&ulDLCommentSize))
  936. return FALSE;
  937. if(ulDLCommentSize)
  938. {
  939. if((szComment= LocalAlloc(LMEM_ZEROINIT, ulDLCommentSize))==NULL)
  940. return FALSE;
  941. SetFilePointer(pFile, ulDLCommentOffSet, NULL, FILE_BEGIN);
  942. ReadFile(pFile, (LPVOID) szComment, ulDLCommentSize, &dwRead, NULL);
  943. szComment[ulDLCommentSize-1] = '\0';
  944. pHeadersDL[i].bp.lpComment = szComment;
  945. }
  946. }
  947. return TRUE;
  948. }
  949. /***************************************************************************
  950. GetDLEntryNumbers - reads the DL member numbers (ids) from the binary tree
  951. in the NAB file
  952. /***************************************************************************/
  953. BOOL GetDLEntryNumbers(HANDLE pFile, int nLayer, ULONG POffset,ULONG* ulNumOfEntries,ULONG *pEntryNumbers,BOOL bflag)
  954. {
  955. static ULONG ulCount =0; //keeps trecat of the number of element
  956. ULONG nLoops =0;
  957. ULONG ulNewOffset =0;
  958. ULONG ulElement = 0;
  959. if(bflag==1)
  960. ulCount =0;
  961. if(POffset==0)
  962. nLoops=32;
  963. else
  964. {
  965. GetOffSet(pFile,POffset+4,&nLoops);
  966. nLoops &= 0x0000FFFF;
  967. }
  968. for(ulElement = 0; ulElement < nLoops; ulElement++)
  969. {
  970. if(nLayer > 0)
  971. {
  972. ulNewOffset=0;
  973. if(POffset!=0)
  974. GetOffSet(pFile, POffset+8+(ulElement*4), &ulNewOffset);
  975. //call this function recursively
  976. GetDLEntryNumbers(pFile,nLayer-1, ulNewOffset,ulNumOfEntries,pEntryNumbers,0);
  977. }
  978. else
  979. {
  980. //fill the array here (offset)
  981. pEntryNumbers[ulCount]=0;
  982. if(POffset!=0)
  983. GetOffSet(pFile, POffset+8+(ulElement*4),&(pEntryNumbers[ulCount]));
  984. ulCount++; //increment the count
  985. if(ulCount>(*ulNumOfEntries))
  986. {
  987. *ulNumOfEntries=ulCount;
  988. return TRUE;
  989. }
  990. }
  991. }
  992. return TRUE;
  993. }
  994. /***************************************************************************
  995. FunctionName: GetDLEntries
  996. Purpose : Gets the entries of a DL.
  997. Note :
  998. ***************************************************************************/
  999. BOOL GetDLEntries(HANDLE pFile,
  1000. LPMH_STUFF pHeadAdd, ULONG ulAddCount,
  1001. LPMH_STUFF pHeadDL, ULONG ulDLCount,
  1002. ULONG ulDLOffset, ULONG nIndex,
  1003. ULONG * lpulDLNum, LPMP_BASIC * lppmp)
  1004. {
  1005. ULONG ulDLEntHeaderOffSet=0;//offset of the header of DL entries(Header which has the entry numbers
  1006. ULONG ulDLEntriesCount=0;
  1007. ULONG ulDLEntryOffSet=0; //offset of the Dl entry
  1008. ULONG ulDLEntryNumber=0; //Number of DL entry
  1009. ULONG ulDLEntryNameOffSet=0;
  1010. ULONG ulDLEntryNameSize=0;
  1011. ULONG * lpulDLEntryNumbers = NULL;
  1012. int nLevelCount=0;
  1013. int utemp=32;
  1014. DWORD dwRead = 0;
  1015. ULONG i, j;
  1016. LPMP_BASIC lpmp = NULL;
  1017. if(FALSE==GetOffSet(pFile,ulDLOffset+24,&ulDLEntriesCount))
  1018. return FALSE;
  1019. if(!ulDLEntriesCount) // no members
  1020. return TRUE;
  1021. *lpulDLNum = ulDLEntriesCount;
  1022. //alocate the array of string pointers which hold the names of the DL entries.
  1023. lpmp = LocalAlloc(LMEM_ZEROINIT, sizeof(MP_BASIC) * ulDLEntriesCount);
  1024. //get the entries here
  1025. //first get the offset of the header which has the DL entry numbers.
  1026. if(FALSE==GetOffSet(pFile,ulDLOffset+28,&ulDLEntHeaderOffSet))
  1027. return FALSE;
  1028. lpulDLEntryNumbers = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG) * ulDLEntriesCount);
  1029. if(!lpulDLEntryNumbers)
  1030. return FALSE;
  1031. nLevelCount=0;
  1032. utemp=32;
  1033. while(utemp <(int) ulDLEntriesCount)
  1034. {
  1035. utemp *= 32;
  1036. nLevelCount++;
  1037. }
  1038. if(!(GetDLEntryNumbers(pFile, nLevelCount, ulDLEntHeaderOffSet, &ulDLEntriesCount, lpulDLEntryNumbers, 1)))
  1039. {
  1040. return FALSE;
  1041. }
  1042. for(i=0;i<ulDLEntriesCount;i++)
  1043. {
  1044. ULONG j=0;
  1045. LPTSTR lp = NULL;
  1046. LPTSTR lpE = NULL;
  1047. ulDLEntryOffSet=0;
  1048. lpmp[i].lpName=NULL;
  1049. lpmp[i].lpEmail=NULL;
  1050. lpmp[i].lpComment=NULL;
  1051. //get the entry number ulDLentryNumber
  1052. ulDLEntryNumber = lpulDLEntryNumbers[i];
  1053. //search out address array to get the display name....
  1054. for(j=0;j<ulAddCount;j++)
  1055. {
  1056. if(pHeadAdd[j].ulNum == ulDLEntryNumber)
  1057. {
  1058. lpmp[i].lpName = pHeadAdd[j].bp.lpName;
  1059. lpmp[i].lpEmail = pHeadAdd[j].bp.lpEmail;
  1060. break;
  1061. }
  1062. }
  1063. //search the DL array now...
  1064. if(!lpmp[i].lpName)
  1065. {
  1066. ULONG k;
  1067. for(k=0;k<ulDLCount;k++)
  1068. {
  1069. if(pHeadDL[k].ulNum == ulDLEntryNumber)
  1070. {
  1071. lpmp[i].lpName = pHeadDL[k].bp.lpName;
  1072. lpmp[i].lpEmail = NULL; // DLs dont have emails
  1073. break;
  1074. }
  1075. }
  1076. }
  1077. }
  1078. *lppmp = lpmp;
  1079. return TRUE;
  1080. }
  1081. /****************************************************************
  1082. *
  1083. *
  1084. *
  1085. *****************************************************************/
  1086. HRESULT MessengerImport( HWND hWnd,
  1087. LPADRBOOK lpAdrBook,
  1088. LPWABOBJECT lpWABObject,
  1089. LPWAB_PROGRESS_CALLBACK lpProgressCB,
  1090. LPWAB_EXPORT_OPTIONS lpOptions)
  1091. {
  1092. HRESULT hResult = hrSuccess;
  1093. TCHAR szFileName[MAX_PATH + 1];
  1094. register ULONG i;
  1095. ULONG ulObjType, j;
  1096. ULONG index;
  1097. ULONG ulLastChosenProp = 0;
  1098. ULONG ulcFields = 0;
  1099. ULONG cAttributes = 0;
  1100. TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
  1101. WAB_PROGRESS Progress;
  1102. LPABCONT lpContainer = NULL;
  1103. HANDLE hFile = INVALID_HANDLE_VALUE;
  1104. LPMESS_RECORD lpMESSRecord = NULL;
  1105. LPSPropValue lpspv = NULL;
  1106. ULONG cProps;
  1107. BOOL fSkipSetProps;
  1108. LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
  1109. BOOL fDoDistLists = FALSE;
  1110. ULONG nEntries = 0;
  1111. ULONG nDLs = 0;
  1112. ULONG nContactOffset = 0;
  1113. ULONG nDLOffset = 0;
  1114. int utemp=32;
  1115. LPMH_STUFF pHeadersAdd = NULL;
  1116. LPMH_STUFF pHeadersDL = NULL;
  1117. int nLevelCountAdd=0;
  1118. SetGlobalBufferFunctions(lpWABObject);
  1119. *szFileName = '\0';
  1120. hResult = GetNABPath(szFileName, sizeof(szFileName));
  1121. if( hResult != S_OK || !lstrlen(szFileName) ||
  1122. GetFileAttributes(szFileName) == 0xFFFFFFFF)
  1123. {
  1124. // The file was not correctly detected
  1125. // Prompt to find it manually ...
  1126. StrCpyN(szFileName, LoadStringToGlobalBuffer(IDS_STRING_SELECTPATH), ARRAYSIZE(szFileName));
  1127. if (IDNO == MessageBox( hWnd,
  1128. szFileName, //temporarily overloaded
  1129. LoadStringToGlobalBuffer(IDS_MESSAGE),
  1130. MB_YESNO))
  1131. {
  1132. return(ResultFromScode(MAPI_E_USER_CANCEL));
  1133. }
  1134. else
  1135. {
  1136. *szFileName = '\0';
  1137. // Get MESS file name
  1138. OpenFileDialog(hWnd,
  1139. szFileName,
  1140. szMESSFilter,
  1141. IDS_MESS_FILE_SPEC,
  1142. szAllFilter,
  1143. IDS_ALL_FILE_SPEC,
  1144. NULL,
  1145. 0,
  1146. szMESSExt,
  1147. OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
  1148. hInst,
  1149. 0, //idsTitle
  1150. 0); // idsSaveButton
  1151. if(!lstrlen(szFileName))
  1152. return(ResultFromScode(E_FAIL));
  1153. }
  1154. }
  1155. // Open the file
  1156. if ((hFile = CreateFile(szFileName,
  1157. GENERIC_READ,
  1158. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1159. NULL,
  1160. OPEN_EXISTING,
  1161. FILE_FLAG_SEQUENTIAL_SCAN,
  1162. NULL)) == INVALID_HANDLE_VALUE)
  1163. {
  1164. DWORD err = GetLastError();
  1165. DebugTrace("Couldn't open file %s -> %u\n", szFileName, err);
  1166. // BEGIN DELTA for BUG 1804
  1167. // if the file is locked (e.g. netscape AB in use)
  1168. if( err == ERROR_SHARING_VIOLATION )
  1169. return(ResultFromScode(MAPI_E_BUSY));
  1170. // else return a generic error for generic msg
  1171. return(ResultFromScode(MAPI_E_NOT_FOUND));
  1172. // END DELTA for BUG 1804
  1173. }
  1174. Assert(hFile != INVALID_HANDLE_VALUE);
  1175. //
  1176. // Open the WAB's PAB container: fills global lpCreateEIDsWAB
  1177. //
  1178. if (hResult = LoadWABEIDs(lpAdrBook, &lpContainer)) {
  1179. goto exit;
  1180. }
  1181. //
  1182. // All set... now loop through the records, adding each to the WAB
  1183. //
  1184. GetOffSet(hFile,0x185,&nEntries);
  1185. GetOffSet(hFile,0x1d8,&nDLs);
  1186. GetOffSet(hFile,0x195,&nContactOffset);
  1187. GetOffSet(hFile,0x1e8,&nDLOffset);
  1188. ulcEntries = nEntries + nDLs;
  1189. if(!ulcEntries)
  1190. {
  1191. hResult = S_OK;
  1192. goto exit;
  1193. }
  1194. // Initialize the Progress Bar
  1195. Progress.denominator = max(ulcEntries, 1);
  1196. Progress.numerator = 0;
  1197. if (LoadString(hInst, IDS_STATE_IMPORT_MU, szBuffer, sizeof(szBuffer))) {
  1198. DebugTrace("Status Message: %s\n", szBuffer);
  1199. Progress.lpText = szBuffer;
  1200. } else {
  1201. DebugTrace("Cannot load resource string %u\n", IDS_STATE_IMPORT_MU);
  1202. Progress.lpText = NULL;
  1203. }
  1204. lpProgressCB(hWnd, &Progress);
  1205. // We will make 2 passes over the file - in the first pass we will import all the
  1206. // contacts. In the second pass we will import all the distribution lists .. the
  1207. // advantage of doing 2 passes is that when importing contacts, we will prompt on
  1208. // conflict and then when importing distlists, we will assume all contacts in the
  1209. // WAB are correct and just point to the relevant ones
  1210. if(nEntries)
  1211. {
  1212. SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  1213. pHeadersAdd = LocalAlloc(LMEM_ZEROINIT, nEntries * sizeof(MH_STUFF));
  1214. if(!pHeadersAdd)
  1215. {
  1216. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  1217. goto exit;
  1218. }
  1219. utemp = 32;
  1220. nLevelCountAdd = 0;
  1221. while(utemp <(int) nEntries)
  1222. {
  1223. utemp *= 32;
  1224. nLevelCountAdd++;
  1225. }
  1226. if(!GetHeaders(hFile ,nLevelCountAdd, nContactOffset, pHeadersAdd, 1))
  1227. {
  1228. goto exit;
  1229. }
  1230. for(i=0;i<nEntries;i++)
  1231. {
  1232. if (hResult = ReadMESSRecord(hFile, &lpMESSRecord, pHeadersAdd[i].ulOffSet))
  1233. {
  1234. DebugTrace("ReadMESSRecord -> %x\n", GetScode(hResult));
  1235. continue;
  1236. }
  1237. if (hResult = MapMESSRecordtoProps( lpMESSRecord,
  1238. &lpspv, &cProps,
  1239. &lpDisplayName, &lpEmailAddress))
  1240. {
  1241. DebugTrace("MapMESSRecordtoProps -> %x\n", GetScode(hResult));
  1242. continue;
  1243. }
  1244. hResult = HrAddMESSMailUser(hWnd,
  1245. lpContainer,
  1246. lpDisplayName,
  1247. lpEmailAddress,
  1248. cProps, lpspv,
  1249. lpProgressCB, lpOptions);
  1250. //if(HR_FAILED(hResult))
  1251. if(hResult == MAPI_E_USER_CANCEL)
  1252. goto exit;
  1253. // Update progress bar
  1254. Progress.numerator++;
  1255. Assert(Progress.numerator <= Progress.denominator);
  1256. if(lpDisplayName && lstrlen(lpDisplayName))
  1257. {
  1258. pHeadersAdd[i].bp.lpName = LocalAlloc(LMEM_ZEROINIT, lstrlen(lpDisplayName)+1);
  1259. if(pHeadersAdd[i].bp.lpName)
  1260. StrCpyN(pHeadersAdd[i].bp.lpName, lpDisplayName, lstrlen(lpDisplayName)+1);
  1261. }
  1262. if(lpEmailAddress && lstrlen(lpEmailAddress))
  1263. {
  1264. pHeadersAdd[i].bp.lpEmail = LocalAlloc(LMEM_ZEROINIT, lstrlen(lpEmailAddress)+1);
  1265. if(pHeadersAdd[i].bp.lpEmail)
  1266. StrCpyN(pHeadersAdd[i].bp.lpEmail, lpEmailAddress, lstrlen(lpEmailAddress)+1);
  1267. }
  1268. if (lpMESSRecord)
  1269. {
  1270. FreeMESSRecord(lpMESSRecord);
  1271. lpMESSRecord = NULL;
  1272. }
  1273. if (lpspv)
  1274. {
  1275. int j;
  1276. for(j=0;j<m_Max;j++)
  1277. {
  1278. lpspv[j].ulPropTag = PR_NULL;
  1279. lpspv[j].Value.LPSZ = NULL;
  1280. }
  1281. WABFreeBuffer(lpspv);
  1282. lpspv = NULL;
  1283. }
  1284. lpProgressCB(hWnd, &Progress);
  1285. }
  1286. }
  1287. // NOW do the DISTLISTS
  1288. if(nDLs)
  1289. {
  1290. SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  1291. pHeadersDL = LocalAlloc(LMEM_ZEROINIT, nDLs * sizeof(MH_STUFF));
  1292. if(!pHeadersDL)
  1293. {
  1294. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  1295. goto exit;
  1296. }
  1297. utemp = 32;
  1298. nLevelCountAdd = 0;
  1299. while(utemp <(int) nDLs)
  1300. {
  1301. utemp *= 32;
  1302. nLevelCountAdd++;
  1303. }
  1304. if(!GetHeaders(hFile ,nLevelCountAdd, nDLOffset, pHeadersDL, 1))
  1305. {
  1306. goto exit;
  1307. }
  1308. // read all the names of the DLs upfront ... this makes it easier to
  1309. // associate member DLs with the DL
  1310. if(!GetAllDLNames(hFile, nDLs, pHeadersDL))
  1311. {
  1312. goto exit;
  1313. }
  1314. // 54263: Theres some kind of bug in the NAB file where we get nDLs == 1 even when there are no DLs
  1315. // Need to skip over that case
  1316. if(nDLs == 1 && !pHeadersDL[0].bp.lpName)
  1317. {
  1318. hResult = S_OK;
  1319. goto exit;
  1320. }
  1321. for(i=0;i<nDLs;i++)
  1322. {
  1323. ULONG ulcNumDLEntries = 0;
  1324. LPMP_BASIC lpmp = NULL;
  1325. GetDLEntries(hFile,
  1326. pHeadersAdd, nEntries,
  1327. pHeadersDL, nDLs,
  1328. pHeadersDL[i].ulOffSet, i,
  1329. &ulcNumDLEntries, &lpmp);
  1330. hResult = HrAddMESSDistList(hWnd, lpContainer,
  1331. pHeadersDL[i],
  1332. ulcNumDLEntries, lpmp,
  1333. lpProgressCB, lpOptions);
  1334. //if(HR_FAILED(hResult))
  1335. // goto exit;
  1336. // Update progress bar
  1337. Progress.numerator++;
  1338. Assert(Progress.numerator <= Progress.denominator);
  1339. lpProgressCB(hWnd, &Progress);
  1340. // Dont need to free lpmp since it only contains pointers and not allocated memory
  1341. if(lpmp)
  1342. LocalFree(lpmp);
  1343. }
  1344. }
  1345. if (! HR_FAILED(hResult))
  1346. hResult = hrSuccess;
  1347. exit:
  1348. if(pHeadersAdd)
  1349. {
  1350. for(i=0;i<nEntries;i++)
  1351. {
  1352. if(pHeadersAdd[i].bp.lpName)
  1353. LocalFree(pHeadersAdd[i].bp.lpName);
  1354. if(pHeadersAdd[i].bp.lpEmail)
  1355. LocalFree(pHeadersAdd[i].bp.lpEmail);
  1356. }
  1357. LocalFree(pHeadersAdd);
  1358. }
  1359. if(pHeadersDL)
  1360. {
  1361. for(i=0;i<nDLs;i++)
  1362. {
  1363. if(pHeadersDL[i].bp.lpName)
  1364. LocalFree(pHeadersDL[i].bp.lpName);
  1365. if(pHeadersDL[i].bp.lpComment)
  1366. LocalFree(pHeadersDL[i].bp.lpComment);
  1367. }
  1368. LocalFree(pHeadersDL);
  1369. }
  1370. if (hFile) {
  1371. CloseHandle(hFile);
  1372. }
  1373. if (lpspv) {
  1374. WABFreeBuffer(lpspv);
  1375. lpspv = NULL;
  1376. }
  1377. if (lpMESSRecord) {
  1378. FreeMESSRecord(lpMESSRecord);
  1379. lpMESSRecord = NULL;
  1380. }
  1381. if (lpContainer) {
  1382. lpContainer->lpVtbl->Release(lpContainer);
  1383. lpContainer = NULL;
  1384. }
  1385. if (lpCreateEIDsWAB) {
  1386. WABFreeBuffer(lpCreateEIDsWAB);
  1387. lpCreateEIDsWAB = NULL;
  1388. }
  1389. return(hResult);
  1390. }