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.

5257 lines
167 KiB

  1. //
  2. // HotSync.c
  3. //
  4. // Contains code to synchronize addresses and groups with
  5. // HotMail servers
  6. //
  7. #define COBJMACROS
  8. #include <_apipch.h>
  9. #include <wab.h>
  10. #define COBJMACROS
  11. #include "HotSync.h"
  12. #include "iso8601.h"
  13. #include "uimisc.h"
  14. #include "ui_cflct.h"
  15. #include "ui_pwd.h"
  16. #include "useragnt.h"
  17. typedef enum {
  18. CIS_STRING = 0,
  19. CIS_BOOL,
  20. CIS_DWORD
  21. }CIS_TYPE;
  22. typedef struct CONTACTINFO_STRUCTURE
  23. {
  24. CIS_TYPE tType;
  25. DWORD dwOffset;
  26. }CONTACTINFO_STRUCTURE;
  27. enum {
  28. idcisHref = 0,
  29. idcisId,
  30. idcisType,
  31. idcisModified,
  32. idcisDisplayName,
  33. idcisGivenName,
  34. idcisSurname,
  35. idcisNickName,
  36. idcisEmail,
  37. idcisHomeStreet,
  38. idcisHomeCity,
  39. idcisHomeState,
  40. idcisHomePostalCode,
  41. idcisHomeCountry,
  42. idcisCompany,
  43. idcisWorkStreet,
  44. idcisWorkCity,
  45. idcisWorkState,
  46. idcisWorkPostalCode,
  47. idcisWorkCountry,
  48. idcisHomePhone,
  49. idcisHomeFax,
  50. idcisWorkPhone,
  51. idcisWorkFax,
  52. idcisMobilePhone,
  53. idcisOtherPhone,
  54. idcisBday,
  55. idcisPager
  56. };
  57. CONTACTINFO_STRUCTURE g_ContactInfoStructure[] =
  58. {
  59. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHref)},
  60. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszId)},
  61. {CIS_DWORD, offsetof(HTTPCONTACTINFO, tyContact)},
  62. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszModified)},
  63. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszDisplayName)},
  64. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszGivenName)},
  65. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszSurname)},
  66. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszNickname)},
  67. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszEmail)},
  68. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeStreet)},
  69. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeCity)},
  70. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeState)},
  71. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomePostalCode)},
  72. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeCountry)},
  73. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszCompany)},
  74. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkStreet)},
  75. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkCity)},
  76. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkState)},
  77. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkPostalCode)},
  78. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkCountry)},
  79. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomePhone)},
  80. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeFax)},
  81. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkPhone)},
  82. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkFax)},
  83. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszMobilePhone)},
  84. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszOtherPhone)},
  85. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszBday)},
  86. {CIS_STRING, offsetof(HTTPCONTACTINFO, pszPager)}
  87. };
  88. #define CIS_FIRST_DATA_FIELD 5
  89. #define CIS_GETSTRING(pci, i) (*((char **)(&((char *)pci)[g_ContactInfoStructure[i].dwOffset])))
  90. #define CIS_GETTYPE(i) (g_ContactInfoStructure[i].tType)
  91. IHTTPMailCallbackVtbl vtblIHTTPMAILCALLBACK = {
  92. VTABLE_FILL
  93. WABSync_QueryInterface,
  94. WABSync_AddRef,
  95. WABSync_Release,
  96. WABSync_OnTimeout,
  97. WABSync_OnLogonPrompt,
  98. WABSync_OnPrompt,
  99. WABSync_OnStatus,
  100. WABSync_OnError,
  101. WABSync_OnCommand,
  102. WABSync_OnResponse,
  103. WABSync_GetParentWindow
  104. };
  105. enum {
  106. ieid_PR_DISPLAY_NAME = 0,
  107. ieid_PR_OBJECT_TYPE,
  108. ieid_PR_ENTRYID,
  109. ieid_PR_LAST_MODIFICATION_TIME,
  110. ieid_PR_WAB_HOTMAIL_CONTACTIDS,
  111. ieid_PR_WAB_HOTMAIL_SERVERIDS,
  112. ieid_PR_WAB_HOTMAIL_MODTIMES,
  113. ieid_Max
  114. };
  115. static SizedSPropTagArray(ieid_Max, ptaEidSync)=
  116. {
  117. ieid_Max,
  118. {
  119. PR_DISPLAY_NAME,
  120. PR_OBJECT_TYPE,
  121. PR_ENTRYID,
  122. PR_LAST_MODIFICATION_TIME,
  123. PR_ENTRYID,
  124. PR_ENTRYID,
  125. PR_ENTRYID
  126. }
  127. };
  128. enum {
  129. ieidc_PR_DISPLAY_NAME = 0,
  130. ieidc_PR_OBJECT_TYPE,
  131. ieidc_PR_ENTRYID,
  132. ieidc_PR_LAST_MODIFICATION_TIME,
  133. ieidc_PR_GIVEN_NAME,
  134. ieidc_PR_SURNAME,
  135. ieidc_PR_NICKNAME,
  136. ieidc_PR_EMAIL_ADDRESS,
  137. ieidc_PR_HOME_ADDRESS_STREET,
  138. ieidc_PR_HOME_ADDRESS_CITY,
  139. ieidc_PR_HOME_ADDRESS_STATE_OR_PROVINCE,
  140. ieidc_PR_HOME_ADDRESS_POSTAL_CODE,
  141. ieidc_PR_HOME_ADDRESS_COUNTRY,
  142. ieidc_PR_COMPANY_NAME,
  143. ieidc_PR_BUSINESS_ADDRESS_STREET,
  144. ieidc_PR_BUSINESS_ADDRESS_CITY,
  145. ieidc_PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
  146. ieidc_PR_BUSINESS_ADDRESS_POSTAL_CODE,
  147. ieidc_PR_BUSINESS_ADDRESS_COUNTRY,
  148. ieidc_PR_HOME_TELEPHONE_NUMBER,
  149. ieidc_PR_HOME_FAX_NUMBER,
  150. ieidc_PR_BUSINESS_TELEPHONE_NUMBER,
  151. ieidc_PR_BUSINESS_FAX_NUMBER,
  152. ieidc_PR_MOBILE_TELEPHONE_NUMBER,
  153. ieidc_PR_OTHER_TELEPHONE_NUMBER,
  154. ieidc_PR_BIRTHDAY,
  155. ieidc_PR_PAGER,
  156. ieidc_PR_CONTACT_EMAIL_ADDRESSES,
  157. ieidc_PR_CONTACT_DEFAULT_ADDRESS_INDEX,
  158. #ifdef HM_GROUP_SYNCING
  159. ieidc_PR_WAB_DL_ENTRIES,
  160. ieidc_PR_WAB_DL_ONEOFFS,
  161. #endif
  162. ieidc_PR_WAB_HOTMAIL_CONTACTIDS,
  163. ieidc_PR_WAB_HOTMAIL_SERVERIDS,
  164. ieidc_PR_WAB_HOTMAIL_MODTIMES,
  165. ieidc_Max
  166. };
  167. static SizedSPropTagArray(ieidc_Max, ptaEidCSync)=
  168. {
  169. ieidc_Max,
  170. {
  171. PR_DISPLAY_NAME,
  172. PR_OBJECT_TYPE,
  173. PR_ENTRYID,
  174. PR_LAST_MODIFICATION_TIME,
  175. PR_GIVEN_NAME,
  176. PR_SURNAME,
  177. PR_NICKNAME,
  178. PR_EMAIL_ADDRESS,
  179. PR_HOME_ADDRESS_STREET,
  180. PR_HOME_ADDRESS_CITY,
  181. PR_HOME_ADDRESS_STATE_OR_PROVINCE,
  182. PR_HOME_ADDRESS_POSTAL_CODE,
  183. PR_HOME_ADDRESS_COUNTRY,
  184. PR_COMPANY_NAME,
  185. PR_BUSINESS_ADDRESS_STREET,
  186. PR_BUSINESS_ADDRESS_CITY,
  187. PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
  188. PR_BUSINESS_ADDRESS_POSTAL_CODE,
  189. PR_BUSINESS_ADDRESS_COUNTRY,
  190. PR_HOME_TELEPHONE_NUMBER,
  191. PR_HOME_FAX_NUMBER,
  192. PR_BUSINESS_TELEPHONE_NUMBER,
  193. PR_BUSINESS_FAX_NUMBER,
  194. PR_MOBILE_TELEPHONE_NUMBER,
  195. PR_OTHER_TELEPHONE_NUMBER,
  196. PR_BIRTHDAY,
  197. PR_PAGER_TELEPHONE_NUMBER,
  198. PR_CONTACT_EMAIL_ADDRESSES,
  199. PR_CONTACT_DEFAULT_ADDRESS_INDEX,
  200. #ifdef HM_GROUP_SYNCING
  201. PR_WAB_DL_ENTRIES,
  202. PR_ENTRYID,
  203. #endif
  204. PR_ENTRYID,
  205. PR_ENTRYID,
  206. PR_ENTRYID,
  207. }
  208. };
  209. // HM Nickname invalid characters
  210. const ULONG MAX_INVALID_ARRAY_INDEX = 123;
  211. static BOOL bInvalidCharArray[] =
  212. {
  213. TRUE, // 0
  214. TRUE,
  215. TRUE,
  216. TRUE,
  217. TRUE,
  218. TRUE,
  219. TRUE,
  220. TRUE,
  221. TRUE,
  222. TRUE, // 9
  223. TRUE,
  224. TRUE,
  225. TRUE,
  226. TRUE,
  227. TRUE,
  228. TRUE,
  229. TRUE,
  230. TRUE,
  231. TRUE,
  232. TRUE, // 19
  233. TRUE,
  234. TRUE,
  235. TRUE,
  236. TRUE,
  237. TRUE,
  238. TRUE,
  239. TRUE,
  240. TRUE,
  241. TRUE,
  242. TRUE, // 29
  243. TRUE,
  244. TRUE,
  245. TRUE, // 32 (x20) Space
  246. TRUE, // !
  247. TRUE, // "
  248. TRUE, // #
  249. TRUE, // $
  250. TRUE, // %
  251. TRUE, // &
  252. TRUE, // '
  253. TRUE, // (
  254. TRUE, // )
  255. TRUE, // 42 *
  256. TRUE, // +
  257. TRUE, // ,
  258. TRUE, // -
  259. TRUE, // .
  260. TRUE, // /
  261. FALSE, // 0
  262. FALSE, // 1
  263. FALSE, // 2
  264. FALSE, // 3
  265. FALSE, // 52 4
  266. FALSE, // 5
  267. FALSE, // 6
  268. FALSE, // 7
  269. FALSE, // 8
  270. FALSE, // 9
  271. TRUE, // :
  272. TRUE, // ;
  273. TRUE, // <
  274. TRUE, // =
  275. TRUE, // 62 >
  276. TRUE, // ?
  277. TRUE, // @
  278. FALSE, // A
  279. FALSE, // B
  280. FALSE, // C
  281. FALSE, // D
  282. FALSE, // E
  283. FALSE, // F
  284. FALSE, // G
  285. FALSE, // 72 H
  286. FALSE, // I
  287. FALSE, // J
  288. FALSE, // K
  289. FALSE, // L
  290. FALSE, // M
  291. FALSE, // N
  292. FALSE, // O
  293. FALSE, // P
  294. FALSE, // Q
  295. FALSE, // 82 R
  296. FALSE, // S
  297. FALSE, // T
  298. FALSE, // U
  299. FALSE, // V
  300. FALSE, // W
  301. FALSE, // X
  302. FALSE, // Y
  303. FALSE, // Z
  304. TRUE, // [
  305. TRUE, // 92 '\'
  306. TRUE, // ]
  307. TRUE, // ^
  308. FALSE, // _
  309. TRUE, // `
  310. FALSE, // a
  311. FALSE, // b
  312. FALSE, // c
  313. FALSE, // d
  314. FALSE, // e
  315. FALSE, // 102 f
  316. FALSE, // g
  317. FALSE, // h
  318. FALSE, // i
  319. FALSE, // j
  320. FALSE, // k
  321. FALSE, // l
  322. FALSE, // m
  323. FALSE, // n
  324. FALSE, // o
  325. FALSE, // 112 p
  326. FALSE, // q
  327. FALSE, // r
  328. FALSE, // s
  329. FALSE, // t
  330. FALSE, // u
  331. FALSE, // v
  332. FALSE, // w
  333. FALSE, // x
  334. FALSE, // y
  335. FALSE, // 122 z
  336. };
  337. extern HRESULT InitUserIdentityManager(LPIAB lpIAB, IUserIdentityManager ** lppUserIdentityManager);
  338. // Address Book Sync Window Class Name
  339. LPTSTR g_lpszSyncKey = TEXT("Software\\Microsoft\\WAB\\Synchronization\\");
  340. LPTSTR g_szSyncClass = TEXT("WABSyncView");
  341. extern VOID CenterDialog(HWND hwndDlg);
  342. #define WM_SYNC_NEXTSTATE (WM_USER + 4)
  343. #define WM_SYNC_NEXTOP (WM_USER + 5)
  344. #define SafeCoMemFree(_pv) \
  345. if (_pv) { \
  346. CoTaskMemFree(_pv); \
  347. _pv = NULL; \
  348. } \
  349. else
  350. #ifdef HM_GROUP_SYNCING
  351. HRESULT HrSynchronize(HWND hWnd, LPADRBOOK lpIAB, LPCTSTR pszAccountID, BOOL bSyncGroups)
  352. #else
  353. HRESULT HrSynchronize(HWND hWnd, LPADRBOOK lpIAB, LPCTSTR pszAccountID)
  354. #endif
  355. {
  356. HRESULT hr;
  357. LPWABSYNC pWabSync = NULL;
  358. // if (!bIsThereACurrentUser((LPIAB)lpIAB))
  359. // return E_FAIL;
  360. // [PaulHi] Raid 62149 Check to see if user is connected
  361. {
  362. DWORD dwConnectedState;
  363. TCHAR tszCaption[256];
  364. TCHAR tszMessage[256];
  365. if ( !InternetGetConnectedState(&dwConnectedState, 0) || (dwConnectedState & INTERNET_CONNECTION_OFFLINE) )
  366. {
  367. LoadString(hinstMapiX, idsSyncError, tszCaption, CharSizeOf(tszCaption));
  368. if (dwConnectedState & INTERNET_CONNECTION_OFFLINE)
  369. LoadString(hinstMapiX, idsOffline, tszMessage, CharSizeOf(tszMessage));
  370. else
  371. LoadString(hinstMapiX, idsNoInternetConnect, tszMessage, CharSizeOf(tszMessage));
  372. MessageBox(hWnd, tszMessage, tszCaption, MB_ICONEXCLAMATION | MB_OK);
  373. return E_FAIL;
  374. }
  375. }
  376. // Create the wab sync object
  377. hr = WABSync_Create(&pWabSync);
  378. if (FAILED(hr))
  379. goto exit;
  380. // initializing it kicks off the whole process
  381. #ifdef HM_GROUP_SYNCING
  382. // [PaulHi] 2/22/99 Hotmail syncing is now done in two passes. The first pass is
  383. // as before and synchronizes the normal email contacts. The second pass synchronizes
  384. // the group contacts. Group contacts contain references to email contacts so email
  385. // contacts must be completely synchronized before groups can be synchronized.
  386. hr = WABSync_Initialize(pWabSync, hWnd, lpIAB, pszAccountID, bSyncGroups);
  387. #else
  388. hr = WABSync_Initialize(pWabSync, hWnd, lpIAB, pszAccountID);
  389. #endif
  390. exit:
  391. WABSync_Release((IHTTPMailCallback*)pWabSync);
  392. return hr;
  393. }
  394. static LPSTR _StrDup(LPCSTR pszStr)
  395. {
  396. LPMALLOC lpMalloc;
  397. LPSTR pszResult = NULL;
  398. if (!pszStr)
  399. return NULL;
  400. CoGetMalloc(MEMCTX_TASK, &lpMalloc);
  401. if (lpMalloc)
  402. {
  403. DWORD cchSize = (lstrlenA(pszStr) + 1);
  404. pszResult = (LPSTR) lpMalloc->lpVtbl->Alloc(lpMalloc, cchSize * sizeof(pszResult[0]));
  405. if (pszResult)
  406. StrCpyNA(pszResult, pszStr, cchSize);
  407. lpMalloc->lpVtbl->Release(lpMalloc);
  408. }
  409. return pszResult;
  410. }
  411. void _FixHotmailDate(LPSTR pszDate)
  412. {
  413. if (!pszDate)
  414. return;
  415. while (*pszDate)
  416. {
  417. if (*pszDate == 'T')
  418. {
  419. *pszDate = 0;
  420. break;
  421. }
  422. if (*pszDate == '.')
  423. *pszDate = '-';
  424. pszDate++;
  425. }
  426. }
  427. BOOL LogTransactions(LPWABSYNC pWabSync)
  428. {
  429. BOOL fInit = FALSE, fLogging = FALSE;
  430. LPTSTR pszLogKey = TEXT("Software\\Microsoft\\Outlook Express\\5.0\\Mail");
  431. LPTSTR pszLogValue = TEXT("Log HTTPMail (0/1)");
  432. IUserIdentityManager * lpUserIdentityManager = NULL;
  433. IUserIdentity * lpUserIdentity = NULL;
  434. HRESULT hr;
  435. HKEY hkeyIdentity = NULL, hkeyLog = NULL;
  436. DWORD dwValue, dwType, dwSize;
  437. if(!bIsWABSessionProfileAware((LPIAB)(pWabSync->m_pAB)))
  438. goto exit;
  439. if(HR_FAILED(hr = InitUserIdentityManager((LPIAB)(pWabSync->m_pAB), &lpUserIdentityManager)))
  440. goto exit;
  441. fInit = TRUE;
  442. if(HR_FAILED(hr = lpUserIdentityManager->lpVtbl->GetIdentityByCookie(lpUserIdentityManager,
  443. (GUID *)&UID_GIBC_CURRENT_USER,
  444. &lpUserIdentity)))
  445. goto exit;
  446. if (HR_FAILED(hr = lpUserIdentity->lpVtbl->OpenIdentityRegKey(lpUserIdentity,
  447. KEY_READ, &hkeyIdentity)))
  448. goto exit;
  449. if (RegOpenKeyEx(hkeyIdentity, pszLogKey, 0, KEY_READ, &hkeyLog) != ERROR_SUCCESS)
  450. goto exit;
  451. dwSize = sizeof(DWORD);
  452. if (RegQueryValueEx(hkeyLog, pszLogValue, NULL, &dwType, (LPBYTE) &dwValue, &dwSize) != ERROR_SUCCESS)
  453. goto exit;
  454. fLogging = (dwValue == 1);
  455. exit:
  456. if(fInit)
  457. UninitUserIdentityManager((LPIAB)(pWabSync->m_pAB));
  458. if(lpUserIdentity)
  459. lpUserIdentity->lpVtbl->Release(lpUserIdentity);
  460. if (hkeyLog)
  461. RegCloseKey(hkeyLog);
  462. if (hkeyIdentity)
  463. RegCloseKey(hkeyIdentity);
  464. return fLogging;
  465. }
  466. DWORD CountHTTPMailAccounts(LPIAB lpIAB)
  467. {
  468. IImnAccountManager2 *lpAcctMgr;
  469. IImnEnumAccounts *pEnumAccts = NULL;
  470. DWORD dwCount = 0;
  471. HRESULT hr;
  472. if (FAILED(hr = InitAccountManager(lpIAB, &lpAcctMgr, NULL)) || NULL == lpAcctMgr)
  473. goto exit;
  474. if (FAILED(hr = lpAcctMgr->lpVtbl->Enumerate(lpAcctMgr, SRV_HTTPMAIL,&pEnumAccts)))
  475. goto exit;
  476. if (FAILED(hr = pEnumAccts->lpVtbl->GetCount(pEnumAccts, &dwCount)))
  477. dwCount = 0;
  478. exit:
  479. if( pEnumAccts)
  480. pEnumAccts->lpVtbl->Release(pEnumAccts);
  481. return dwCount;
  482. }
  483. HRESULT _FindHTTPMailAccount(HWND hwnd, IImnAccountManager2 *lpAcctMgr, LPSTR pszAcctName, ULONG ccb)
  484. {
  485. IImnEnumAccounts *pEnumAccts = NULL;
  486. DWORD dwCount = 0;
  487. IImnAccount *pAccount = NULL;
  488. HRESULT hr;
  489. Assert(lpAcctMgr);
  490. if (FAILED(hr = lpAcctMgr->lpVtbl->Enumerate(lpAcctMgr, SRV_HTTPMAIL,&pEnumAccts)))
  491. goto exit;
  492. if (FAILED(hr = pEnumAccts->lpVtbl->GetCount(pEnumAccts, &dwCount)) || dwCount == 0)
  493. goto exit;
  494. if (dwCount > 1)
  495. {
  496. if (!ChooseHotmailServer(hwnd, pEnumAccts, pszAcctName, ccb))
  497. {
  498. hr = E_UserCancel;
  499. goto exit;
  500. }
  501. }
  502. else
  503. {
  504. if (FAILED(hr = pEnumAccts->lpVtbl->GetNext(pEnumAccts, &pAccount)))
  505. goto exit;
  506. if (FAILED(hr = pAccount->lpVtbl->GetProp(pAccount, AP_ACCOUNT_ID, pszAcctName, &ccb)))
  507. goto exit;
  508. }
  509. hr = S_OK;
  510. exit:
  511. if( pAccount)
  512. pAccount->lpVtbl->Release(pAccount);
  513. if( pEnumAccts)
  514. pEnumAccts->lpVtbl->Release(pEnumAccts);
  515. return hr;
  516. }
  517. ///////////////////////////////////////////////////////////////////////////////
  518. // HrMakeContactId
  519. //
  520. // Helper function to convert ANSI strings and create UNICODE contact ID
  521. // string.
  522. ///////////////////////////////////////////////////////////////////////////////
  523. HRESULT hrMakeContactId(
  524. LPTSTR lptszContactId, // [out]
  525. int nCharNum, // [in]
  526. LPCTSTR lptcszProfileId, // [in]
  527. LPCSTR lpcszAccountId, // [in]
  528. LPCSTR lpcszLoginName) // [in]
  529. {
  530. HRESULT hr = S_OK;
  531. LPWSTR lpwszAccountId = NULL;
  532. LPWSTR lpwszLoginName = NULL;
  533. // Validate arguments
  534. if ( !lptszContactId ||
  535. !lptcszProfileId ||
  536. !lpcszAccountId ||
  537. !lpcszLoginName)
  538. {
  539. Assert(0);
  540. return ERROR_INVALID_PARAMETER;
  541. }
  542. // Check buffer size. Account for the two extra '-' characters.
  543. if ( nCharNum <= (lstrlen(lptcszProfileId) + lstrlenA(lpcszAccountId) + lstrlenA(lpcszLoginName) + 2) )
  544. {
  545. Assert(0);
  546. return ERROR_INSUFFICIENT_BUFFER;
  547. }
  548. lpwszAccountId = ConvertAtoW(lpcszAccountId);
  549. lpwszLoginName = ConvertAtoW(lpcszLoginName);
  550. if (!lpwszAccountId || !lpwszLoginName)
  551. {
  552. Assert(0);
  553. hr = E_FAIL;
  554. }
  555. else
  556. {
  557. wnsprintf(lptszContactId, nCharNum, TEXT("%s-%s-%s"), lptcszProfileId, lpwszAccountId, lpwszLoginName);
  558. }
  559. LocalFreeAndNull(&lpwszAccountId);
  560. LocalFreeAndNull(&lpwszLoginName);
  561. return hr;
  562. }
  563. #ifdef HM_GROUP_SYNCING
  564. ///////////////////////////////////////////////////////////////////////////////
  565. // hrAppendName
  566. //
  567. // Helper function to take a double byte name string, converts it to single
  568. // byte and appends it to the given name string, using ',' as the delimiter.
  569. // The name string pointer will be allocated and reallocated as needed. The
  570. // caller is responible for freeing the name string with CoTaskMemFree().
  571. //
  572. // Parameters
  573. // [IN/OUT] lpszNameString - name string pointer
  574. // [IN] ulCharCount - current name string size in char
  575. // [IN] double byte character string to append
  576. ///////////////////////////////////////////////////////////////////////////////
  577. LPCSTR lpszDelimiter = ",";
  578. ULONG ulAppendName(
  579. LPSTR * lppszNameString,
  580. ULONG ulCharCount,
  581. LPCTSTR lptszName)
  582. {
  583. ULONG ulLen = 0;
  584. ULONG ulNewLen = 0;
  585. ULONG ulNew = ulCharCount;
  586. LPSTR lpszTemp = NULL;
  587. Assert(lppszNameString);
  588. Assert(lptszName);
  589. // Check size of new string
  590. ulNewLen = (ULONG)lstrlen(lptszName) + 2; // Include delimiter character and termination
  591. if (*lppszNameString)
  592. ulLen = ulNewLen + (ULONG)lstrlenA(*lppszNameString);
  593. else
  594. ulLen = ulNewLen;
  595. if (ulLen > ulCharCount)
  596. {
  597. ulNew = (ulNewLen > MAX_PATH) ? (ulCharCount+ulNewLen+MAX_PATH) : (ulCharCount+MAX_PATH);
  598. lpszTemp = CoTaskMemAlloc(ulNew * sizeof(WCHAR));
  599. if (!lpszTemp)
  600. {
  601. Assert(0);
  602. goto error_out;
  603. }
  604. *lpszTemp = '\0';
  605. if (*lppszNameString)
  606. {
  607. StrCpyNA(lpszTemp, *lppszNameString, ulNew);
  608. CoTaskMemFree(*lppszNameString);
  609. }
  610. *lppszNameString = lpszTemp;
  611. ulCharCount = ulNew;
  612. }
  613. // Append new string name
  614. {
  615. LPSTR lptsz = ConvertWtoA(lptszName);
  616. if (**lppszNameString != '\0')
  617. StrCatBuffA(*lppszNameString, lpszDelimiter, ulCharCount);
  618. StrCatBuffA(*lppszNameString, lptsz, ulCharCount);
  619. LocalFreeAndNull(&lptsz);
  620. }
  621. return ulNew;
  622. error_out:
  623. // Error, return NULL string pointer
  624. if (*lppszNameString)
  625. {
  626. CoTaskMemFree(*lppszNameString);
  627. *lppszNameString = NULL;
  628. }
  629. return 0;
  630. }
  631. ///////////////////////////////////////////////////////////////////////////////
  632. // hrAppendGroupContact
  633. //
  634. // Helper function to a group's PR_WAB_DL_ENTRIES and/or PR_WAB_DL_ONEOFFS
  635. // names and append to the given name string. This name string is in the same
  636. // format as what is retrieved from a HotMail server, and is compared directly
  637. // with the corresponding HotMail group.
  638. //
  639. // a) PR_WAB_DL_ENTRIES are WAB entry ID contacts that map to HM contacts
  640. // distinquished by nickname.
  641. // b) PR_WAB_DL_ONEOFFS are WAB entry ID one-offs with user and email embedded
  642. // directly in the entry ID structure.
  643. //
  644. // Parameters
  645. // [IN] pWabSync
  646. // [IN] ulPropTag
  647. // [IN] lpProp - Pointer to property struct
  648. // [IN/OUT] lppszHMEmailName - HM string with new names appended
  649. // !!NOTE that this needs to be freed by caller using CoMemTaskFree()!!
  650. ///////////////////////////////////////////////////////////////////////////////
  651. HRESULT hrAppendGroupContact(
  652. LPWABSYNC pWabSync, // [IN]
  653. ULONG ulPropTag, // [IN]
  654. LPSPropValue lpProp, // [IN]
  655. LPSTR * lppszHMEmailName) // [IN/OUT]
  656. {
  657. HRESULT hr = S_OK;
  658. LPSPropValue lpaProps = NULL;
  659. ULONG ulcProps = 0;
  660. ULONG ul;
  661. ULONG ulCharSize = 0;
  662. Assert(pWabSync);
  663. Assert(lppszHMEmailName);
  664. Assert( (ulPropTag == PR_WAB_DL_ENTRIES) || (ulPropTag == PR_WAB_DL_ONEOFFS) );
  665. // Check each DL entry and check whether it is another WAB (mail user) contact
  666. // EID or a WAB One-Off email/name string EID.
  667. if (ulPropTag == PR_WAB_DL_ONEOFFS)
  668. {
  669. // Wab one-off is equivalent to a HM direct email name
  670. for (ul=0; ul<lpProp->Value.MVbin.cValues; ul++)
  671. {
  672. ULONG cbEntryID = lpProp->Value.MVbin.lpbin[ul].cb;
  673. LPENTRYID lpEntryID = (LPENTRYID)lpProp->Value.MVbin.lpbin[ul].lpb;
  674. BYTE bType;
  675. LPTSTR lptstrDisplayName, lptstrAddrType;
  676. LPTSTR lptstrAddress = NULL;
  677. bType = IsWABEntryID(cbEntryID, lpEntryID,
  678. &lptstrDisplayName,
  679. &lptstrAddrType,
  680. &lptstrAddress, NULL, NULL);
  681. if (lptstrAddress)
  682. {
  683. // Append the one-off email name
  684. ulCharSize = ulAppendName(lppszHMEmailName, ulCharSize, lptstrAddress);
  685. if (ulCharSize == 0)
  686. {
  687. hr = E_OUTOFMEMORY;
  688. goto out;
  689. }
  690. }
  691. else
  692. {
  693. Assert(0);
  694. }
  695. }
  696. }
  697. else if (ulPropTag == PR_WAB_DL_ENTRIES)
  698. {
  699. // WAB mail user contact is equivalent to a HM contact
  700. for (ul=0; ul<lpProp->Value.MVbin.cValues; ul++)
  701. {
  702. HRESULT hr;
  703. LPMAILUSER lpMailUser;
  704. ULONG ulObjectType;
  705. ULONG cbEntryID = lpProp->Value.MVbin.lpbin[ul].cb;
  706. LPENTRYID lpEntryID = (LPENTRYID)lpProp->Value.MVbin.lpbin[ul].lpb;
  707. hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, lpEntryID,
  708. NULL, 0, &ulObjectType, (LPUNKNOWN *)&lpMailUser);
  709. if (SUCCEEDED(hr))
  710. {
  711. LPSPropValue lpaProps;
  712. ULONG ulcProps;
  713. Assert(ulObjectType == MAPI_MAILUSER);
  714. // HM contacts are designated by the nickname field, so this is all
  715. // we need to append to the name string.
  716. hr = lpMailUser->lpVtbl->GetProps(lpMailUser, NULL, MAPI_UNICODE, &ulcProps, &lpaProps);
  717. if (SUCCEEDED(hr))
  718. {
  719. ULONG ulc;
  720. LPCTSTR lptszNickname = NULL;
  721. for (ulc=0; ulc<ulcProps; ulc++)
  722. {
  723. if (lpaProps[ulc].ulPropTag == PR_NICKNAME)
  724. break;
  725. }
  726. if (ulc == ulcProps)
  727. {
  728. // No nickname. This means that the preceeding contact sync has
  729. // failed or not completed in some way. Skip.
  730. Assert(0);
  731. continue;
  732. }
  733. else
  734. lptszNickname = (LPCTSTR)lpaProps[ulc].Value.lpszW;
  735. ulCharSize = ulAppendName(lppszHMEmailName, ulCharSize, lptszNickname);
  736. if (ulCharSize == 0)
  737. {
  738. hr = E_OUTOFMEMORY;
  739. goto out;
  740. }
  741. }
  742. }
  743. }
  744. }
  745. else
  746. {
  747. // Trace("Unknown property tag type");
  748. Assert(0);
  749. }
  750. out:
  751. return hr;
  752. }
  753. ///////////////////////////////////////////////////////////////////////////////
  754. // hrParseHMGroupEmail
  755. //
  756. // Helper function to parse a HM group email string into nickname names
  757. // (contacts) and email names (one-offs). The name arrays are simply pointers
  758. // into the passed in email name string and so are valid as long at that
  759. // input string is valid. Note that this function modifies the input string
  760. // lptszEmailName.
  761. //
  762. // Parameters
  763. // [IN] lptszEmailName - email string to parse
  764. // [OUT] patszContacts - array of parsed contact (nickname) names if requested
  765. // [OUT] pcContacts - number of contact names
  766. // [OUT] patszOneOffs - array of parsed one-off (email) names if requested
  767. // [OUT] pcOneOffs - number of one-off names
  768. ///////////////////////////////////////////////////////////////////////////////
  769. // It looks like HM allows four possible text delimiters: ' ', ',', ';', '+'
  770. const TCHAR tszSpace[] = TEXT(" ");
  771. const TCHAR tszComma[] = TEXT(",");
  772. const TCHAR tszSemi[] = TEXT(";");
  773. const TCHAR tszPlus[] = TEXT("+");
  774. const TCHAR tszAt[] = TEXT("@");
  775. HRESULT hrParseHMGroupEmail(
  776. LPTSTR lptszEmailName,
  777. LPTSTR ** patszContacts,
  778. ULONG * pcContacts,
  779. LPTSTR ** patszOneOffs,
  780. ULONG * pcOneOffs)
  781. {
  782. HRESULT hr = S_OK;
  783. ULONG cCount = 1;
  784. ULONG ul;
  785. LPTSTR lptszTemp = lptszEmailName;
  786. LPTSTR * atszContacts = NULL;
  787. LPTSTR * atszOneOffs = NULL;
  788. ULONG cContacts = 0;
  789. ULONG cOneOffs = 0;
  790. Assert( lptszEmailName && (pcContacts || pcOneOffs) );
  791. // Strip all leading and ending spaces
  792. TrimSpaces(lptszTemp);
  793. // Count
  794. while (*lptszTemp)
  795. {
  796. if ( ((*lptszTemp) == (*tszSpace)) ||
  797. ((*lptszTemp) == (*tszComma)) ||
  798. ((*lptszTemp) == (*tszSemi)) ||
  799. ((*lptszTemp) == (*tszPlus)) )
  800. {
  801. ++cCount;
  802. // Increment to next valid name
  803. ++lptszTemp;
  804. while ( ((*lptszTemp) == (*tszSpace)) ||
  805. ((*lptszTemp) == (*tszComma)) ||
  806. ((*lptszTemp) == (*tszSemi)) ||
  807. ((*lptszTemp) == (*tszPlus)) )
  808. {
  809. ++lptszTemp;
  810. }
  811. }
  812. else
  813. ++lptszTemp;
  814. }
  815. // Create Contacts and One-Offs name pointer arrays
  816. atszContacts = LocalAlloc(LMEM_ZEROINIT, (cCount * sizeof(LPTSTR)));
  817. if (!atszContacts)
  818. {
  819. hr = E_OUTOFMEMORY;
  820. goto out;
  821. }
  822. atszOneOffs = LocalAlloc(LMEM_ZEROINIT, (cCount * sizeof(LPTSTR)));
  823. if (!atszOneOffs)
  824. {
  825. hr = E_OUTOFMEMORY;
  826. goto out;
  827. }
  828. // Fill the name pointer arrays and counts
  829. {
  830. LPTSTR lptszName = lptszEmailName;
  831. BOOL fIsEmail = FALSE;
  832. lptszTemp = lptszName;
  833. while(*lptszTemp)
  834. {
  835. // Determine whether this name is a nickname or email. I am assuning
  836. // that all email names will have the '@' character.
  837. if ((*lptszTemp) == (*tszAt))
  838. fIsEmail = TRUE;
  839. if ( ((*lptszTemp) == (*tszSpace)) ||
  840. ((*lptszTemp) == (*tszComma)) ||
  841. ((*lptszTemp) == (*tszSemi)) ||
  842. ((*lptszTemp) == (*tszPlus)) )
  843. {
  844. *lptszTemp = '\0';
  845. ++lptszTemp;
  846. if (fIsEmail)
  847. {
  848. atszOneOffs[cOneOffs++] = lptszName;
  849. Assert(cOneOffs <= cCount);
  850. fIsEmail = FALSE;
  851. }
  852. else
  853. {
  854. atszContacts[cContacts++] = lptszName;
  855. Assert(cContacts <= cCount);
  856. }
  857. // Increment to next valid name
  858. while ( ((*lptszTemp) == (*tszSpace)) ||
  859. ((*lptszTemp) == (*tszComma)) ||
  860. ((*lptszTemp) == (*tszSemi)) ||
  861. ((*lptszTemp) == (*tszPlus)) )
  862. {
  863. ++lptszTemp;
  864. }
  865. lptszName = lptszTemp;
  866. }
  867. else
  868. ++lptszTemp;
  869. }
  870. // Pick up last item
  871. if (*lptszName)
  872. {
  873. if (fIsEmail)
  874. {
  875. atszOneOffs[cOneOffs++] = lptszName;
  876. Assert(cOneOffs <= cCount);
  877. }
  878. else
  879. {
  880. atszContacts[cContacts++] = lptszName;
  881. Assert(cContacts <= cCount);
  882. }
  883. }
  884. }
  885. // Pass back contact name array if requested
  886. if (cContacts && pcContacts)
  887. {
  888. *pcContacts = cContacts;
  889. }
  890. if (patszContacts)
  891. (*patszContacts) = atszContacts;
  892. // Pass back one-off name array if requested
  893. if (cOneOffs && pcOneOffs )
  894. {
  895. *pcOneOffs = cOneOffs;
  896. }
  897. if (patszOneOffs)
  898. (*patszOneOffs) = atszOneOffs;
  899. out:
  900. if ( FAILED(hr) || !patszContacts )
  901. LocalFreeAndNull((LPVOID *)&atszContacts);
  902. if ( FAILED(hr) || !patszOneOffs )
  903. LocalFreeAndNull((LPVOID *)&atszOneOffs);
  904. return hr;
  905. }
  906. ///////////////////////////////////////////////////////////////////////////////
  907. // hrCreateGroupMVBin
  908. //
  909. // Creates either a PR_WAB_DL_ENTRIES or PR_WAB_DL_ONEOFFS MVBin property and
  910. // adds it to the passed in property array.
  911. //
  912. // If the proptag is PR_WAB_DL_ENTRIES then the atszNames array is assumed to
  913. // contain valid WAB contact nicknames. The first contact's (mail user) EID
  914. // with that nickname is added to the MVBin property. It is assumed that
  915. // nicknames are unique (after contact syncing which is performed first) as is
  916. // required by Hotmail.
  917. //
  918. // If the proptag is PR_WAB_DL_ONEOFFS then the atszNames array is assumed to
  919. // contain valid email names. WAB one-off EIDs are created from these and
  920. // added to the MVBin property.
  921. //
  922. // Parameters
  923. // [IN] pWabSync
  924. // [IN] ulPropTag
  925. // [IN] atszNames - Array of wide char names
  926. // [IN] cCount - Number of items in above array
  927. // [IN/OUT] lpPropArray
  928. // [IN/OUT] pdwLoc - Current lpPropArray index
  929. ///////////////////////////////////////////////////////////////////////////////
  930. HRESULT hrCreateGroupMVBin(
  931. LPWABSYNC pWabSync,
  932. ULONG ulPropTag,
  933. LPTSTR * atszNames,
  934. ULONG cCount,
  935. LPSPropValue lpPropArray,
  936. DWORD * pdwLoc)
  937. {
  938. HRESULT hr = S_OK;
  939. ULONG ul;
  940. Assert(atszNames);
  941. Assert(lpPropArray);
  942. Assert(pdwLoc);
  943. // Set up this property as error. When the MVbin values are added via
  944. // AddPropToMVPBin() the tag type will change to valid PT_MV_BINARY type.
  945. lpPropArray[*pdwLoc].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulPropTag));
  946. lpPropArray[*pdwLoc].dwAlignPad = 0;
  947. lpPropArray[*pdwLoc].Value.MVbin.cValues = 0;
  948. lpPropArray[*pdwLoc].Value.MVbin.lpbin = NULL;
  949. if (ulPropTag == PR_WAB_DL_ENTRIES)
  950. {
  951. // Search for WAB mail users with these nicknames
  952. for (ul=0; ul<cCount; ul++)
  953. {
  954. SPropertyRestriction PropRes;
  955. SPropValue Prop = {0};
  956. LPSBinary rgsbEntryIDs = NULL;
  957. ULONG ulCount = 1;
  958. // Set up search restriction
  959. Prop.ulPropTag = PR_NICKNAME;
  960. Prop.Value.LPSZ = atszNames[ul];
  961. PropRes.lpProp = &Prop;
  962. PropRes.relop = RELOP_EQ;
  963. PropRes.ulPropTag = PR_NICKNAME;
  964. if (SUCCEEDED(FindRecords(((LPIAB)pWabSync->m_pAB)->lpPropertyStore->hPropertyStore,
  965. NULL, // pmbinFolder
  966. 0, // ulFlags
  967. TRUE, // Always TRUE
  968. &PropRes, // Propertyrestriction
  969. &ulCount, // IN: number of matches to find, OUT: number found
  970. &rgsbEntryIDs)))
  971. {
  972. // Add EID property
  973. if (ulCount > 0)
  974. {
  975. if ( FAILED(AddPropToMVPBin(
  976. lpPropArray,
  977. *pdwLoc,
  978. rgsbEntryIDs[0].lpb,
  979. rgsbEntryIDs[0].cb,
  980. FALSE)) ) // Don't add duplicates, not
  981. {
  982. Assert(0);
  983. }
  984. }
  985. FreeEntryIDs(((LPIAB)pWabSync->m_pAB)->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs);
  986. }
  987. else
  988. {
  989. // All contacts should be in WAB unless the preceeding mail user contact
  990. // sync failed.
  991. DebugTrace(TEXT("hrCreateGroupMVBin - Failed to find HM group contact\n"));
  992. }
  993. }
  994. }
  995. else if (ulPropTag == PR_WAB_DL_ONEOFFS)
  996. {
  997. for (ul=0; ul<cCount; ul++)
  998. {
  999. ULONG cbEID = 0;
  1000. LPENTRYID lpEID = NULL;
  1001. LPTSTR lptszName = NULL;
  1002. LPTSTR lptszSMTP = TEXT("");
  1003. LPTSTR lptszEmail = atszNames[ul];
  1004. LPTSTR lptszTemp = NULL;
  1005. int nLen = lstrlen(atszNames[ul]) + 1;
  1006. // A WAB DL OneOff must have a valid display name. Take the first
  1007. // part of the email name for this.
  1008. lptszName = LocalAlloc(LMEM_ZEROINIT, (nLen * sizeof(WCHAR)));
  1009. if (!lptszName)
  1010. {
  1011. hr = E_OUTOFMEMORY;
  1012. goto out;
  1013. }
  1014. StrCpyN(lptszName, lptszEmail, nLen);
  1015. lptszTemp = lptszName;
  1016. while ( *lptszTemp &&
  1017. (*lptszTemp) != (*tszAt) )
  1018. {
  1019. ++lptszTemp;
  1020. }
  1021. (*lptszTemp) = '\0';
  1022. // Creates UNICODE string embedded WAB one-off EID
  1023. if ( SUCCEEDED(CreateWABEntryID(WAB_ONEOFF,
  1024. (LPVOID)lptszName,
  1025. (LPVOID)lptszSMTP,
  1026. (LPVOID)lptszEmail,
  1027. 0, 0, NULL,
  1028. &cbEID,
  1029. &lpEID)) )
  1030. {
  1031. if ( FAILED(AddPropToMVPBin(
  1032. lpPropArray,
  1033. *pdwLoc,
  1034. lpEID,
  1035. cbEID,
  1036. FALSE)) ) // Don't add duplicates, not
  1037. {
  1038. Assert(0);
  1039. }
  1040. }
  1041. LocalFreeAndNull(&lptszName);
  1042. }
  1043. }
  1044. else
  1045. {
  1046. Assert(0);
  1047. }
  1048. out:
  1049. ++(*pdwLoc);
  1050. return hr;
  1051. }
  1052. #endif // HM_GROUP_SYNCING
  1053. ///////////////////////////////////////////////////////////////////////////////
  1054. // hrStripInvalidChars
  1055. //
  1056. // Helper function to remove disallowed characters. HM only allows
  1057. // alphanumeric and '-' and '_' characters in a nickname. All illegal chars
  1058. // are removed from the string.
  1059. //
  1060. ///////////////////////////////////////////////////////////////////////////////
  1061. HRESULT hrStripInvalidChars(LPSTR lpszName)
  1062. {
  1063. HRESULT hr = S_OK;
  1064. LPSTR lpszAddTo = NULL;
  1065. Assert(lpszName);
  1066. lpszAddTo = lpszName;
  1067. while (*lpszName)
  1068. {
  1069. // @review Currently the look up table only contains 122 characters. Make
  1070. // it full 256? How will HM change when it adds intenational suppport?
  1071. if ( ((UCHAR)(*lpszName) < MAX_INVALID_ARRAY_INDEX) && !bInvalidCharArray[*lpszName] )
  1072. {
  1073. *lpszAddTo = *lpszName;
  1074. ++lpszAddTo;
  1075. }
  1076. ++lpszName;
  1077. }
  1078. *lpszAddTo = '\0';
  1079. return hr;
  1080. }
  1081. // ****************************************************************************************************
  1082. // C H O T S Y N C C L A S S
  1083. //
  1084. // Class to handle the synchronizing of WAB and Hotmail contacts
  1085. //
  1086. HRESULT WABSync_Create(LPWABSYNC *ppWabSync)
  1087. {
  1088. Assert(ppWabSync);
  1089. *ppWabSync = LocalAlloc(LMEM_ZEROINIT, sizeof(WABSYNC));
  1090. // fix up the prop tag array structure to take into account the variable values
  1091. ptaEidSync.aulPropTag[ieid_PR_WAB_HOTMAIL_CONTACTIDS] = PR_WAB_HOTMAIL_CONTACTIDS;
  1092. ptaEidSync.aulPropTag[ieid_PR_WAB_HOTMAIL_SERVERIDS] = PR_WAB_HOTMAIL_SERVERIDS;
  1093. ptaEidSync.aulPropTag[ieid_PR_WAB_HOTMAIL_MODTIMES] = PR_WAB_HOTMAIL_MODTIMES;
  1094. // fix up the other prop tag array structure to take into account the variable values
  1095. ptaEidCSync.aulPropTag[ieidc_PR_WAB_HOTMAIL_CONTACTIDS] = PR_WAB_HOTMAIL_CONTACTIDS;
  1096. ptaEidCSync.aulPropTag[ieidc_PR_WAB_HOTMAIL_SERVERIDS] = PR_WAB_HOTMAIL_SERVERIDS;
  1097. ptaEidCSync.aulPropTag[ieidc_PR_WAB_HOTMAIL_MODTIMES] = PR_WAB_HOTMAIL_MODTIMES;
  1098. #ifdef HM_GROUP_SYNCING
  1099. ptaEidCSync.aulPropTag[ieidc_PR_WAB_DL_ONEOFFS] = PR_WAB_DL_ONEOFFS;
  1100. #endif
  1101. if (*ppWabSync)
  1102. {
  1103. (*ppWabSync)->vtbl = &vtblIHTTPMAILCALLBACK;
  1104. (*ppWabSync)->m_cRef = 1;
  1105. (*ppWabSync)->m_state = SYNC_STATE_INITIALIZING;
  1106. (*ppWabSync)->m_ixpStatus = IXP_DISCONNECTED;
  1107. ZeroMemory(&(*ppWabSync)->m_rInetServerInfo, sizeof(INETSERVER));
  1108. }
  1109. else
  1110. return E_OUTOFMEMORY;
  1111. return S_OK;
  1112. }
  1113. void WABSync_Delete(LPWABSYNC pWabSync)
  1114. {
  1115. Assert(pWabSync);
  1116. ZeroMemory(&(pWabSync->m_rInetServerInfo), sizeof(INETSERVER)); // Done for security
  1117. if (pWabSync->m_pOps)
  1118. {
  1119. WABSync_FreeOps(pWabSync);
  1120. Vector_Delete(pWabSync->m_pOps);
  1121. pWabSync->m_pOps = NULL;
  1122. }
  1123. if (pWabSync->m_pWabItems)
  1124. {
  1125. WABSync_FreeItems(pWabSync);
  1126. Vector_Delete(pWabSync->m_pWabItems);
  1127. }
  1128. if (pWabSync->m_pszAccountId)
  1129. CoTaskMemFree(pWabSync->m_pszAccountId);
  1130. if (pWabSync->m_pAB)
  1131. pWabSync->m_pAB->lpVtbl->Release(pWabSync->m_pAB);
  1132. if (pWabSync->m_pTransport)
  1133. IHTTPMailTransport_Release(pWabSync->m_pTransport);
  1134. if (pWabSync->m_pszRootUrl)
  1135. CoTaskMemFree(pWabSync->m_pszRootUrl);
  1136. #ifdef HM_GROUP_SYNCING
  1137. // [PaulHi] If we are ending a mail contact sync, kick off a second pass
  1138. // to synchronize the group contacts.
  1139. // @review - We may want to skip group syncing if an error occurs during the
  1140. // first pass contact syncing.
  1141. if (!pWabSync->m_fSyncGroups && pWabSync->m_hParentWnd)
  1142. PostMessage(pWabSync->m_hParentWnd, WM_USER_SYNCGROUPS, 0, 0L);
  1143. #endif
  1144. LocalFree(pWabSync);
  1145. }
  1146. //----------------------------------------------------------------------
  1147. // IUnknown Members
  1148. //----------------------------------------------------------------------
  1149. HRESULT WABSync_QueryInterface (IHTTPMailCallback __RPC_FAR *lpunkobj,
  1150. REFIID riid,
  1151. LPVOID FAR * lppUnk)
  1152. {
  1153. SCODE sc;
  1154. LPWABSYNC lpWabSync = (LPWABSYNC)lpunkobj;
  1155. if (IsEqualGUID(riid, &IID_IUnknown) ||
  1156. IsEqualGUID(riid, &IID_IHTTPMailCallback) ||
  1157. IsEqualGUID(riid, &IID_ITransportCallback))
  1158. {
  1159. sc = S_OK;
  1160. }
  1161. else
  1162. {
  1163. *lppUnk = NULL; // OLE requires zeroing [out] parameters
  1164. sc = E_NOINTERFACE;
  1165. goto error;
  1166. }
  1167. /* We found the requested interface so increment the reference count.
  1168. */
  1169. lpWabSync ->m_cRef++;
  1170. *lppUnk = lpunkobj;
  1171. return hrSuccess;
  1172. error:
  1173. return ResultFromScode(sc);
  1174. }
  1175. ULONG WABSync_AddRef(IHTTPMailCallback __RPC_FAR *This)
  1176. {
  1177. LPWABSYNC pWabSync = (LPWABSYNC)This;
  1178. return InterlockedIncrement(&pWabSync->m_cRef);
  1179. }
  1180. ULONG WABSync_Release(IHTTPMailCallback __RPC_FAR *This)
  1181. {
  1182. LPWABSYNC pWabSync = (LPWABSYNC)This;
  1183. LONG cRef = InterlockedDecrement(&pWabSync->m_cRef);
  1184. Assert(cRef >= 0);
  1185. if (0 == cRef)
  1186. WABSync_Delete(pWabSync);
  1187. return (ULONG)cRef;
  1188. }
  1189. //----------------------------------------------------------------------
  1190. // IHTTPMailCallback Members
  1191. //----------------------------------------------------------------------
  1192. STDMETHODIMP WABSync_OnTimeout (IHTTPMailCallback __RPC_FAR *This, DWORD *pdwTimeout, IInternetTransport *pTransport)
  1193. {
  1194. // LPWABSYNC pWabSync = (LPWABSYNC)This;
  1195. return E_NOTIMPL;
  1196. }
  1197. STDMETHODIMP WABSync_OnLogonPrompt (IHTTPMailCallback __RPC_FAR *This, LPINETSERVER pInetServer, IInternetTransport *pTransport)
  1198. {
  1199. LPWABSYNC pWabSync = (LPWABSYNC)This;
  1200. if (PromptUserForPassword(pInetServer, pWabSync->m_hWnd))
  1201. {
  1202. return S_OK;
  1203. }
  1204. return E_FAIL;
  1205. }
  1206. STDMETHODIMP_(INT) WABSync_OnPrompt (IHTTPMailCallback __RPC_FAR *This, HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
  1207. {
  1208. // LPWABSYNC pWabSync = (LPWABSYNC)This;
  1209. return E_NOTIMPL;
  1210. }
  1211. STDMETHODIMP WABSync_OnStatus (IHTTPMailCallback __RPC_FAR *This, IXPSTATUS ixpstatus, IInternetTransport *pTransport)
  1212. {
  1213. // LPWABSYNC pWabSync = (LPWABSYNC)This;
  1214. return E_NOTIMPL;
  1215. }
  1216. STDMETHODIMP WABSync_OnError (IHTTPMailCallback __RPC_FAR *This, IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
  1217. {
  1218. // LPWABSYNC pWabSync = (LPWABSYNC)This;
  1219. return E_NOTIMPL;
  1220. }
  1221. STDMETHODIMP WABSync_OnCommand (IHTTPMailCallback __RPC_FAR *This, CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport)
  1222. {
  1223. // LPWABSYNC pWabSync = (LPWABSYNC)This;
  1224. return E_NOTIMPL;
  1225. }
  1226. STDMETHODIMP WABSync_GetParentWindow (IHTTPMailCallback __RPC_FAR *This, HWND *pHwndParent)
  1227. {
  1228. LPWABSYNC pWabSync = (LPWABSYNC)This;
  1229. *pHwndParent = pWabSync->m_hWnd;
  1230. return S_OK;
  1231. }
  1232. STDMETHODIMP WABSync_OnResponse (IHTTPMailCallback __RPC_FAR *This, LPHTTPMAILRESPONSE pResponse)
  1233. {
  1234. LPWABSYNC pWabSync = (LPWABSYNC)This;
  1235. HRESULT hr = S_OK;
  1236. Assert(pWabSync);
  1237. Assert(pResponse);
  1238. if (FAILED(pResponse->rIxpResult.hrResult))
  1239. {
  1240. switch (pResponse->rIxpResult.hrResult)
  1241. {
  1242. case IXP_E_HTTP_INSUFFICIENT_STORAGE:
  1243. case IXP_E_HTTP_ROOT_PROP_NOT_FOUND:
  1244. case IXP_E_HTTP_NOT_IMPLEMENTED:
  1245. WABSync_Abort(pWabSync, pResponse->rIxpResult.hrResult);
  1246. break;
  1247. }
  1248. }
  1249. if (pWabSync->m_fAborted)
  1250. return E_FAIL;
  1251. if (SYNC_STATE_SERVER_CONTACT_DISCOVERY == pWabSync->m_state)
  1252. {
  1253. if (pResponse->command == HTTPMAIL_GETPROP)
  1254. hr = WABSync_HandleContactsRootResponse(pWabSync, pResponse);
  1255. else
  1256. hr = WABSync_HandleIDListResponse(pWabSync, pResponse);
  1257. }
  1258. else if ((SYNC_STATE_PROCESS_OPS == pWabSync->m_state || SYNC_STATE_PROCESS_MERGED_CONFLICTS == pWabSync->m_state)
  1259. && pWabSync->m_pOps)
  1260. {
  1261. LPHOTSYNCOP pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
  1262. Assert(pOp);
  1263. if (pOp)
  1264. hr = Syncop_HandleResponse(pOp, pResponse);
  1265. else
  1266. hr = E_FAIL;
  1267. if (FAILED(hr))
  1268. WABSync_AbortOp(pWabSync, hr);
  1269. }
  1270. else
  1271. hr = E_FAIL;
  1272. return hr;
  1273. }
  1274. #ifdef HM_GROUP_SYNCING
  1275. STDMETHODIMP WABSync_Initialize(LPWABSYNC pWabSync, HWND hWnd, IAddrBook *pAB, LPCTSTR pszAccountID, BOOL bSyncGroups)
  1276. #else
  1277. STDMETHODIMP WABSync_Initialize(LPWABSYNC pWabSync, HWND hWnd, IAddrBook *pAB, LPCTSTR pszAccountID)
  1278. #endif
  1279. {
  1280. IImnAccountManager2 *lpAcctMgr = NULL;
  1281. IImnAccount *pAccount = NULL;
  1282. HRESULT hr;
  1283. char szAcctName[CCHMAX_ACCOUNT_NAME+1];
  1284. DWORD ccb = CCHMAX_ACCOUNT_NAME;
  1285. LPSTR pszUserAgent = NULL;
  1286. #ifdef HM_GROUP_SYNCING
  1287. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1288. #endif
  1289. Assert(pWabSync);
  1290. Assert(pAB);
  1291. pWabSync->m_hParentWnd = hWnd;
  1292. pWabSync->m_pTransport = NULL;
  1293. pWabSync->m_fSkipped = FALSE;
  1294. #ifdef HM_GROUP_SYNCING
  1295. pWabSync->m_fSyncGroups = bSyncGroups;
  1296. #endif
  1297. pWabSync->m_hWnd = CreateDialogParam (hinstMapiX, MAKEINTRESOURCE (iddSyncProgress),
  1298. pWabSync->m_hParentWnd, SyncProgressDlgProc, (LPARAM)pWabSync);
  1299. if (!pWabSync->m_hWnd)
  1300. {
  1301. hr = E_FAIL;
  1302. goto exit;
  1303. }
  1304. ShowWindow(pWabSync->m_hWnd, SW_SHOW);
  1305. if (pWabSync->m_hParentWnd)
  1306. EnableWindow (pWabSync->m_hParentWnd, FALSE);
  1307. WABSync_BeginSynchronize(pWabSync);
  1308. InitWABUserAgent(TRUE);
  1309. if (FAILED(hr = InitAccountManager(NULL, &lpAcctMgr, NULL)))
  1310. goto exit;
  1311. if (pszAccountID == NULL)
  1312. {
  1313. if (FAILED(hr = _FindHTTPMailAccount(pWabSync->m_hWnd, lpAcctMgr, szAcctName, CCHMAX_ACCOUNT_NAME)))
  1314. goto exit;
  1315. #ifdef HM_GROUP_SYNCING
  1316. // [PaulHi] We don't want the user to have to choose the HM account twice (once for contact and
  1317. // then for group syncing). So save the account ID here.
  1318. LocalFreeAndNull(&(lpPTGData->lptszHMAccountId));
  1319. lpPTGData->lptszHMAccountId = ConvertAtoW(szAcctName);
  1320. #endif
  1321. }
  1322. else
  1323. {
  1324. LPSTR lpAcctA = ConvertWtoA((LPWSTR)pszAccountID);
  1325. StrCpyNA(szAcctName, lpAcctA, ARRAYSIZE(szAcctName));
  1326. LocalFreeAndNull(&lpAcctA);
  1327. }
  1328. // Get the account
  1329. hr = lpAcctMgr->lpVtbl->FindAccount(lpAcctMgr, AP_ACCOUNT_ID, szAcctName, &pAccount);
  1330. if (FAILED(hr))
  1331. {
  1332. hr = lpAcctMgr->lpVtbl->FindAccount(lpAcctMgr, AP_ACCOUNT_NAME, szAcctName, &pAccount);
  1333. if (FAILED(hr))
  1334. goto exit;
  1335. }
  1336. if (SUCCEEDED(hr = pAccount->lpVtbl->GetProp(pAccount, AP_ACCOUNT_ID, szAcctName, &ccb)))
  1337. pWabSync->m_pszAccountId = _StrDup(szAcctName);
  1338. pWabSync->m_pAB = pAB;
  1339. pWabSync->m_pAB->lpVtbl->AddRef(pWabSync->m_pAB);
  1340. // Create the Transport
  1341. hr = CoCreateInstance( &CLSID_IHTTPMailTransport,
  1342. NULL,
  1343. CLSCTX_INPROC_SERVER,
  1344. &IID_IHTTPMailTransport,
  1345. (LPVOID *)&(pWabSync->m_pTransport));
  1346. if (FAILED(hr) || !pWabSync->m_pTransport)
  1347. goto exit;
  1348. pszUserAgent = GetWABUserAgentString();
  1349. if (!pszUserAgent)
  1350. goto exit;
  1351. // Initialize the transport
  1352. hr = IHTTPMailTransport_InitNew(pWabSync->m_pTransport, pszUserAgent, (LogTransactions(pWabSync) ? "C:\\WabSync.log" : NULL),(IHTTPMailCallback*)pWabSync);
  1353. if (FAILED(hr))
  1354. goto exit;
  1355. // Create the SERVERINFO
  1356. hr = IHTTPMailTransport_InetServerFromAccount(pWabSync->m_pTransport, pAccount, &pWabSync->m_rInetServerInfo);
  1357. if (FAILED(hr))
  1358. goto exit;
  1359. StrCpyNA(pWabSync->m_szLoginName, pWabSync->m_rInetServerInfo.szUserName, ARRAYSIZE(pWabSync->m_szLoginName));
  1360. // Check if I can connect
  1361. hr = IHTTPMailTransport_Connect(pWabSync->m_pTransport,&pWabSync->m_rInetServerInfo,TRUE,TRUE);
  1362. if (FAILED(hr))
  1363. goto exit;
  1364. hr = WABSync_LoadLastModInfo(pWabSync);
  1365. if (FAILED(hr))
  1366. goto exit;
  1367. hr = WABSync_BuildWabContactList(pWabSync);
  1368. if (FAILED(hr))
  1369. goto exit;
  1370. WABSync_NextState(pWabSync);
  1371. exit:
  1372. if (pszUserAgent)
  1373. LocalFree(pszUserAgent);
  1374. if (FAILED(hr))
  1375. {
  1376. if (pWabSync->m_pTransport)
  1377. IHTTPMailTransport_Release(pWabSync->m_pTransport);
  1378. pWabSync->m_pTransport = NULL;
  1379. WABSync_Abort(pWabSync, hr);
  1380. if (pWabSync->m_pAB)
  1381. {
  1382. pWabSync->m_pAB->lpVtbl->Release(pWabSync->m_pAB);
  1383. pWabSync->m_pAB = NULL;
  1384. }
  1385. }
  1386. // don't release the lpAcctMgr since the WAB maintains a global reference.
  1387. if (pAccount)
  1388. pAccount->lpVtbl->Release(pAccount);
  1389. return hr;
  1390. }
  1391. //
  1392. // CHotSync::Abort
  1393. //
  1394. // Blow away all of the pending items in the queue.
  1395. //
  1396. STDMETHODIMP WABSync_Abort(LPWABSYNC pWabSync, HRESULT hr)
  1397. {
  1398. LPHOTSYNCOP pOp;
  1399. TCHAR szMsg[512], szCaption[255], szRes[512];
  1400. Assert(pWabSync);
  1401. pWabSync->m_fAborted = TRUE;
  1402. if (pWabSync->m_pOps)
  1403. {
  1404. DWORD dwIndex, cOps = Vector_GetLength(pWabSync->m_pOps);
  1405. for (dwIndex = 0; dwIndex < cOps; ++dwIndex)
  1406. {
  1407. pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
  1408. if (pOp)
  1409. {
  1410. Syncop_Abort(pOp);
  1411. Syncop_Delete(pOp);
  1412. }
  1413. Vector_RemoveItem(pWabSync->m_pOps, 0);
  1414. }
  1415. }
  1416. if (FAILED(hr) && hr != E_UserCancel)
  1417. {
  1418. switch (hr)
  1419. {
  1420. case IXP_E_HTTP_INSUFFICIENT_STORAGE:
  1421. LoadString(hinstMapiX, idsOutOfServerSpace, szMsg, CharSizeOf(szMsg));
  1422. break;
  1423. case IXP_E_HTTP_ROOT_PROP_NOT_FOUND:
  1424. case IXP_E_HTTP_NOT_IMPLEMENTED:
  1425. LoadString(hinstMapiX, idsSyncNotHandled, szMsg, CharSizeOf(szMsg));
  1426. break;
  1427. default:
  1428. LoadString(hinstMapiX, idsSyncAborted, szRes, CharSizeOf(szRes));
  1429. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, hr);
  1430. break;
  1431. }
  1432. LoadString(hinstMapiX, idsSyncError, szCaption, CharSizeOf(szCaption));
  1433. MessageBox(pWabSync->m_hWnd, szMsg, szCaption, MB_ICONEXCLAMATION | MB_OK);
  1434. }
  1435. WABSync_FinishSynchronize(pWabSync, hr);
  1436. return S_OK;
  1437. }
  1438. //
  1439. // CHotSync::AbortOp
  1440. //
  1441. // Abort the current operation (for some reason)
  1442. //
  1443. STDMETHODIMP WABSync_AbortOp(LPWABSYNC pWabSync, HRESULT hr)
  1444. {
  1445. LPHOTSYNCOP pOp;
  1446. Assert(pWabSync);
  1447. pWabSync->m_cAborts++;
  1448. // do something with the knowledge of this abort (log to whatever)
  1449. if (!WABSync_NextOp(pWabSync, TRUE))
  1450. WABSync_NextState(pWabSync);
  1451. return S_OK;
  1452. }
  1453. int __cdecl CompareOpTypes(const void* lpvA, const void* lpvB)
  1454. {
  1455. LPHOTSYNCOP pSyncOpA;
  1456. LPHOTSYNCOP pSyncOpB;
  1457. pSyncOpA = *((LPHOTSYNCOP*)lpvA);
  1458. pSyncOpB = *((LPHOTSYNCOP*)lpvB);
  1459. return (pSyncOpA->m_bOpType - pSyncOpB->m_bOpType);
  1460. }
  1461. STDMETHODIMP WABSync_RequestContactsRootProperty(LPWABSYNC pWabSync)
  1462. {
  1463. HRESULT hr;
  1464. Assert(pWabSync);
  1465. Assert(pWabSync->m_pTransport);
  1466. hr = pWabSync->m_pTransport->lpVtbl->GetProperty(pWabSync->m_pTransport, HTTPMAIL_PROP_CONTACTS, &pWabSync->m_pszRootUrl);
  1467. if(hr == E_PENDING)
  1468. hr = S_OK;
  1469. else if (SUCCEEDED(hr) && pWabSync->m_pszRootUrl)
  1470. WABSync_RequestServerIDList(pWabSync);
  1471. else
  1472. WABSync_Abort(pWabSync, hr); //something went terribly wrong
  1473. return S_OK;
  1474. }
  1475. STDMETHODIMP WABSync_HandleContactsRootResponse(LPWABSYNC pWabSync, LPHTTPMAILRESPONSE pResponse)
  1476. {
  1477. Assert(pWabSync);
  1478. pWabSync->m_pszRootUrl = NULL;
  1479. if (SUCCEEDED(pResponse->rIxpResult.hrResult))
  1480. {
  1481. if (pResponse->rGetPropInfo.type == HTTPMAIL_PROP_CONTACTS)
  1482. {
  1483. pWabSync->m_pszRootUrl = pResponse->rGetPropInfo.pszProp;
  1484. pResponse->rGetPropInfo.pszProp = NULL;
  1485. }
  1486. }
  1487. if (pWabSync->m_pszRootUrl)
  1488. WABSync_RequestServerIDList(pWabSync);
  1489. else
  1490. WABSync_Abort(pWabSync, pResponse->rIxpResult.hrResult);
  1491. return S_OK;
  1492. }
  1493. STDMETHODIMP WABSync_RequestServerIDList(LPWABSYNC pWabSync)
  1494. {
  1495. HRESULT hr;
  1496. Assert(pWabSync);
  1497. Assert(pWabSync->m_pTransport);
  1498. Assert(pWabSync->m_pszRootUrl && *pWabSync->m_pszRootUrl);
  1499. WABSync_Progress(pWabSync, idsSyncGathering, -1);
  1500. hr = pWabSync->m_pTransport->lpVtbl->ListContactInfos(pWabSync->m_pTransport, pWabSync->m_pszRootUrl, 0);
  1501. if FAILED(hr)
  1502. WABSync_Abort(pWabSync, hr);
  1503. return hr;
  1504. }
  1505. STDMETHODIMP WABSync_FindContactByServerId(LPWABSYNC pWabSync, LPSTR pszServerId, LPWABCONTACTINFO *ppContact, DWORD *pdwIndex)
  1506. {
  1507. DWORD cItems, dwIndex;
  1508. LPWABCONTACTINFO pContact;
  1509. Assert(pWabSync);
  1510. Assert(pWabSync->m_pWabItems);
  1511. cItems = Vector_GetLength(pWabSync->m_pWabItems);
  1512. for (dwIndex = 0; dwIndex < cItems; dwIndex++)
  1513. {
  1514. pContact = (LPWABCONTACTINFO)Vector_GetItem(pWabSync->m_pWabItems, dwIndex);
  1515. if (pContact && pContact->pszHotmailId && lstrcmpA(pContact->pszHotmailId, pszServerId) == 0)
  1516. {
  1517. *ppContact = pContact;
  1518. *pdwIndex = dwIndex;
  1519. return S_OK;
  1520. }
  1521. }
  1522. return E_FAIL;
  1523. }
  1524. STDMETHODIMP WABSync_HandleIDListResponse(LPWABSYNC pWabSync, LPHTTPMAILRESPONSE pResponse)
  1525. {
  1526. HRESULT hr;
  1527. LPHOTSYNCOP pNewOp;
  1528. if (SUCCEEDED(pResponse->rIxpResult.hrResult))
  1529. {
  1530. ULONG cItems = pResponse->rContactInfoList.cContactInfo;
  1531. LPHTTPCONTACTINFO prgId = pResponse->rContactInfoList.prgContactInfo;
  1532. DWORD dwItem;
  1533. for (dwItem = 0; dwItem < cItems; dwItem++)
  1534. {
  1535. #ifdef HM_GROUP_SYNCING
  1536. // [PaulHi] We synchronize contacts and groups separately
  1537. if ( (!pWabSync->m_fSyncGroups && (prgId[dwItem].tyContact == HTTPMAIL_CT_CONTACT)) ||
  1538. (pWabSync->m_fSyncGroups && (prgId[dwItem].tyContact == HTTPMAIL_CT_GROUP)) )
  1539. #else
  1540. if (HTTPMAIL_CT_GROUP == prgId[dwItem].tyContact)
  1541. {
  1542. // ignore groups for now
  1543. continue;
  1544. }
  1545. else
  1546. #endif
  1547. {
  1548. LPWABCONTACTINFO pContact;
  1549. DWORD dwIndex;
  1550. FILETIME ftModTime = {0,0};
  1551. pNewOp = NULL;
  1552. // [PaulHi] 12/17/98 Raid #61548
  1553. // The Exchange server will pass in contacts with no file mod time,
  1554. // which really hoses the sync process. We could just skip these
  1555. // contacts but to keep things simple we abort the sync process here.
  1556. // Note that HotMail servers work correctly.
  1557. //
  1558. // @todo [PaulHi]
  1559. // After IE5 ship of WAB, fix this by creating a conflict op code and
  1560. // let user straighten out any differences. Also time stamp so future
  1561. // syncs will work.
  1562. hr = iso8601ToFileTime(prgId[dwItem].pszModified, &ftModTime, TRUE, TRUE);
  1563. if (FAILED(hr))
  1564. {
  1565. WABSync_Abort(pWabSync, hr);
  1566. return hr;
  1567. }
  1568. if (SUCCEEDED(WABSync_FindContactByServerId(pWabSync, prgId[dwItem].pszId, &pContact, &dwIndex)))
  1569. {
  1570. if (pContact->fDelete)
  1571. {
  1572. // it has been deleted from the wab. Now delete it from the server.
  1573. pContact->pszHotmailHref = prgId[dwItem].pszHref;
  1574. prgId[dwItem].pszHref = NULL;
  1575. pContact->pszModHotmail = prgId[dwItem].pszModified;
  1576. prgId[dwItem].pszModified = NULL;
  1577. pNewOp = Syncop_CreateServerDelete(pContact);
  1578. }
  1579. else
  1580. {
  1581. LONG lLocalCompare = CompareFileTime(&pWabSync->m_ftLastSync, &pContact->ftModWab);
  1582. LONG lServerCompare = pContact->pszModHotmail && prgId[dwItem].pszModified ? lstrcmpA(pContact->pszModHotmail, prgId[dwItem].pszModified) : -1;
  1583. SafeCoMemFree(pContact->pszHotmailHref);
  1584. pContact->pszHotmailHref = prgId[dwItem].pszHref;
  1585. prgId[dwItem].pszHref = NULL;
  1586. SafeCoMemFree(pContact->pszHotmailId);
  1587. pContact->pszHotmailId = prgId[dwItem].pszId;
  1588. prgId[dwItem].pszId = NULL;
  1589. SafeCoMemFree(pContact->pszModHotmail);
  1590. pContact->pszModHotmail = prgId[dwItem].pszModified;
  1591. prgId[dwItem].pszModified = NULL;
  1592. if (lLocalCompare >= 0)
  1593. {
  1594. // hasn't changed locally since last sync
  1595. if (lServerCompare)
  1596. {
  1597. // has changed on server, just update here
  1598. pNewOp = Syncop_CreateClientChange(pContact);
  1599. Assert(pNewOp);
  1600. Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
  1601. }
  1602. else
  1603. {
  1604. // hasn't changed anywhere. do nothing.
  1605. WABContact_Delete(pContact);
  1606. pContact = NULL;
  1607. }
  1608. }
  1609. else
  1610. {
  1611. // has changed locally.
  1612. if (lServerCompare)
  1613. {
  1614. // has changed on server, CONFLICT
  1615. pNewOp = Syncop_CreateConflict(pContact);
  1616. Assert(pNewOp);
  1617. Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
  1618. }
  1619. else
  1620. {
  1621. // Local change only, upload changes
  1622. pNewOp = Syncop_CreateServerChange(pContact);
  1623. Assert(pNewOp);
  1624. Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
  1625. }
  1626. }
  1627. }
  1628. //remove the contact from the list of local contacts
  1629. Vector_RemoveItem(pWabSync->m_pWabItems, dwIndex);
  1630. }
  1631. else
  1632. {
  1633. // its not in the WAB, we need to add it there.
  1634. pContact = LocalAlloc(LMEM_ZEROINIT, sizeof(WABCONTACTINFO));
  1635. Assert(pContact);
  1636. if (pContact)
  1637. {
  1638. pContact->pszHotmailHref = prgId[dwItem].pszHref;
  1639. prgId[dwItem].pszHref = NULL;
  1640. pContact->pszHotmailId = prgId[dwItem].pszId;
  1641. prgId[dwItem].pszId = NULL;
  1642. pContact->pszModHotmail = prgId[dwItem].pszModified;
  1643. prgId[dwItem].pszModified = NULL;
  1644. pNewOp = Syncop_CreateClientAdd(pContact);
  1645. Assert(pNewOp);
  1646. Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
  1647. }
  1648. }
  1649. if (pNewOp)
  1650. {
  1651. Syncop_Init(pNewOp, (IHTTPMailCallback *)pWabSync, pWabSync->m_pTransport);
  1652. hr = Vector_AddItem(pWabSync->m_pOps, pNewOp);
  1653. }
  1654. else
  1655. {
  1656. if (pContact)
  1657. WABContact_Delete(pContact);
  1658. }
  1659. }
  1660. }
  1661. if (pResponse->fDone)
  1662. {
  1663. //everything left in the contact list needs to either
  1664. //be added to the server or deleted locally.
  1665. LONG cItems, dwIndex;
  1666. LPWABCONTACTINFO pContact;
  1667. Assert(pWabSync->m_pWabItems);
  1668. cItems = Vector_GetLength(pWabSync->m_pWabItems);
  1669. if (cItems > 0)
  1670. {
  1671. for (dwIndex = cItems - 1; dwIndex >= 0; dwIndex--)
  1672. {
  1673. pNewOp = NULL;
  1674. pContact = (LPWABCONTACTINFO)Vector_GetItem(pWabSync->m_pWabItems, dwIndex);
  1675. if (pContact && pContact->pszHotmailId)
  1676. {
  1677. if (pContact->fDelete)
  1678. {
  1679. TCHAR tszServerId[MAX_PATH];
  1680. TCHAR tszKey[MAX_PATH];
  1681. HKEY hkey;
  1682. // now that the delete has completed, delete the tombstone from the registry.
  1683. hr = hrMakeContactId(
  1684. tszServerId,
  1685. MAX_PATH,
  1686. ((LPIAB)(pWabSync->m_pAB))->szProfileID,
  1687. pWabSync->m_pszAccountId,
  1688. pWabSync->m_szLoginName);
  1689. if (FAILED(hr))
  1690. return hr;
  1691. wnsprintf(tszKey, ARRAYSIZE(tszKey), TEXT("%s%s"), g_lpszSyncKey, tszServerId);
  1692. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tszKey, 0, KEY_SET_VALUE, &hkey))
  1693. {
  1694. LPTSTR lpKey =
  1695. ConvertAtoW(pContact->pszHotmailId);
  1696. RegDeleteValue(hkey, lpKey);
  1697. LocalFreeAndNull(&lpKey);
  1698. RegCloseKey(hkey);
  1699. }
  1700. }
  1701. else
  1702. {
  1703. //needs to be deleted locally
  1704. pNewOp = Syncop_CreateClientDelete(pContact);
  1705. }
  1706. }
  1707. else if (pContact)
  1708. {
  1709. //needs to be added remotely
  1710. pNewOp = Syncop_CreateServerAdd(pContact);
  1711. }
  1712. if (pNewOp)
  1713. {
  1714. //remove the contact from the list of local contacts
  1715. Vector_RemoveItem(pWabSync->m_pWabItems, dwIndex);
  1716. Syncop_Init(pNewOp, (IHTTPMailCallback *)pWabSync, pWabSync->m_pTransport);
  1717. hr = Vector_AddItem(pWabSync->m_pOps, pNewOp);
  1718. }
  1719. }
  1720. }
  1721. WABSync_MergeAddsToConflicts(pWabSync);
  1722. pWabSync->m_cTotalOps = Vector_GetLength(pWabSync->m_pOps);
  1723. Vector_Sort(pWabSync->m_pOps, CompareOpTypes);
  1724. //Now go on to handling the operations
  1725. WABSync_NextState(pWabSync);
  1726. }
  1727. }
  1728. else
  1729. WABSync_Abort(pWabSync, pResponse->rIxpResult.hrResult);
  1730. return S_OK;
  1731. }
  1732. STDMETHODIMP WABSync_OperationCompleted(LPWABSYNC pWabSync, LPHOTSYNCOP pOp)
  1733. {
  1734. Assert(pWabSync->m_pOps);
  1735. Assert(pOp == Vector_GetItem(pWabSync->m_pOps, 0)); //completing op should be first op in the list
  1736. Syncop_Delete(pOp);
  1737. Vector_RemoveItem(pWabSync->m_pOps, 0);
  1738. // get the next operation and start it running.
  1739. // if there are no more operations, go to the next state
  1740. pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
  1741. if (pOp)
  1742. Syncop_Begin(pOp);
  1743. else
  1744. WABSync_NextState(pWabSync);
  1745. return S_OK;
  1746. }
  1747. STDMETHODIMP WABSync_BeginSynchronize(LPWABSYNC pWabSync)
  1748. {
  1749. //Keep a reference to ourself while the UI is shown
  1750. WABSync_AddRef((IHTTPMailCallback *)pWabSync);
  1751. // begin ui
  1752. return S_OK;
  1753. }
  1754. STDMETHODIMP WABSync_FinishSynchronize(LPWABSYNC pWabSync, HRESULT hr)
  1755. {
  1756. // if there were any failures or the user didn't resolve all of the
  1757. // conflicts, then don't update the mod info so we have to do it again.
  1758. #ifdef HM_GROUP_SYNCING
  1759. // [PaulHi] Don't store the current mod time until the synchronization
  1760. // process is completely through, meaning that we are ending the second
  1761. // group contact syncing pass
  1762. if (SUCCEEDED(hr) && !pWabSync->m_fSkipped && pWabSync->m_fSyncGroups)
  1763. #else
  1764. if (SUCCEEDED(hr) && !pWabSync->m_fSkipped)
  1765. #endif
  1766. WABSync_SaveCurrentModInfo(pWabSync);
  1767. else if (!pWabSync->m_fAborted && FAILED(hr))
  1768. {
  1769. TCHAR szMsg[512], szCaption[255];
  1770. LoadString(hinstMapiX, idsSyncFailed, szMsg, CharSizeOf(szMsg));
  1771. LoadString(hinstMapiX, idsSyncError, szCaption, CharSizeOf(szCaption));
  1772. MessageBox(pWabSync->m_hWnd, szMsg, szCaption, MB_ICONEXCLAMATION | MB_OK);
  1773. }
  1774. if (pWabSync->m_pTransport)
  1775. {
  1776. IHTTPMailTransport_Release(pWabSync->m_pTransport);
  1777. pWabSync->m_pTransport = NULL;
  1778. }
  1779. if (pWabSync->m_hWnd)
  1780. {
  1781. if (pWabSync->m_hParentWnd)
  1782. EnableWindow (pWabSync->m_hParentWnd, TRUE);
  1783. DestroyWindow(pWabSync->m_hWnd);
  1784. pWabSync->m_hWnd = NULL;
  1785. }
  1786. InitWABUserAgent(FALSE);
  1787. WABSync_Release((IHTTPMailCallback *)pWabSync);
  1788. return S_OK;
  1789. }
  1790. void WABSync_CheckForLocalDeletions(LPWABSYNC pWabSync)
  1791. {
  1792. TCHAR tszKey[MAX_PATH], tszId[MAX_PATH];
  1793. TCHAR tszServerId[MAX_PATH];
  1794. DWORD dwType = 0;
  1795. DWORD dwValue = 0;
  1796. HKEY hkey = NULL;
  1797. DWORD dwSize;
  1798. HRESULT hr = E_FAIL;
  1799. DWORD cRecords, i, cb, lResult;
  1800. Assert(pWabSync);
  1801. Assert(*pWabSync->m_szLoginName);
  1802. // [PaulHi] Assemble the contact ID string
  1803. if ( FAILED(hrMakeContactId(
  1804. tszServerId,
  1805. MAX_PATH,
  1806. ((LPIAB)(pWabSync->m_pAB))->szProfileID,
  1807. pWabSync->m_pszAccountId,
  1808. pWabSync->m_szLoginName)) )
  1809. {
  1810. return;
  1811. }
  1812. wnsprintf(tszKey, ARRAYSIZE(tszKey), TEXT("%s%s"), g_lpszSyncKey, tszServerId);
  1813. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tszKey, 0, KEY_READ, &hkey))
  1814. {
  1815. if (ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, 0, NULL, NULL, NULL, &cRecords, NULL, NULL, NULL, NULL) &&
  1816. cRecords > 0)
  1817. {
  1818. // Start Enumerating the keys
  1819. for (i = 0; i < cRecords; i++)
  1820. {
  1821. // Enumerate Friendly Names
  1822. cb = CharSizeOf(tszId);
  1823. lResult = RegEnumValue(hkey, i, tszId, &cb, 0, NULL, NULL, NULL);
  1824. if (ERROR_SUCCESS == lResult && *tszId)
  1825. {
  1826. WABCONTACTINFO *lpWCI;
  1827. lpWCI = LocalAlloc(LMEM_ZEROINIT, sizeof(WABCONTACTINFO));
  1828. if (!lpWCI)
  1829. {
  1830. hr = E_OUTOFMEMORY;
  1831. DebugPrintError(( TEXT("WABCONTACTINFO Alloc Failed\n")));
  1832. goto out;
  1833. }
  1834. lpWCI->fDelete = TRUE;
  1835. {
  1836. LPSTR lpID =
  1837. ConvertWtoA(tszId);
  1838. lpWCI->pszHotmailId = _StrDup(lpID);
  1839. LocalFreeAndNull(&lpID);
  1840. }
  1841. if (FAILED(Vector_AddItem(pWabSync->m_pWabItems, lpWCI)))
  1842. goto out;
  1843. }
  1844. }
  1845. }
  1846. out:
  1847. RegCloseKey(hkey);
  1848. }
  1849. }
  1850. STDMETHODIMP WABSync_BuildWabContactList(LPWABSYNC pWabSync)
  1851. {
  1852. HRESULT hr = S_OK;
  1853. ULONG ulObjType;
  1854. LPENTRYID pEntryID = NULL;
  1855. ULONG cbEntryID = 0;
  1856. LPABCONT lpContainer = NULL;
  1857. ULONG ulObjectType;
  1858. LPMAPITABLE lpABTable = NULL;
  1859. LPSRowSet lpRowAB = NULL;
  1860. int cNumRows = 0;
  1861. int nRows=0;
  1862. Assert(pWabSync->m_pAB);
  1863. Vector_Create(&pWabSync->m_pOps);
  1864. if (pWabSync->m_pOps == NULL)
  1865. {
  1866. WABSync_Abort(pWabSync, E_OUTOFMEMORY);
  1867. return E_OUTOFMEMORY;
  1868. }
  1869. Vector_Create(&pWabSync->m_pWabItems);
  1870. if (pWabSync->m_pWabItems == NULL)
  1871. {
  1872. WABSync_Abort(pWabSync, E_OUTOFMEMORY);
  1873. return E_OUTOFMEMORY;
  1874. }
  1875. WABSync_CheckForLocalDeletions(pWabSync);
  1876. if (HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->GetPAB(pWabSync->m_pAB, &cbEntryID, &pEntryID)))
  1877. {
  1878. DebugPrintError(( TEXT("GetPAB Failed\n")));
  1879. goto out;
  1880. }
  1881. hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, // size of EntryID to open
  1882. pEntryID, // EntryID to open
  1883. NULL, // interface
  1884. 0, // flags
  1885. &ulObjType,
  1886. (LPUNKNOWN *)&lpContainer);
  1887. MAPIFreeBuffer(pEntryID);
  1888. pEntryID = NULL;
  1889. if (HR_FAILED(hr))
  1890. {
  1891. DebugPrintError(( TEXT("OpenEntry Failed\n")));
  1892. goto out;
  1893. }
  1894. if (HR_FAILED(hr = lpContainer->lpVtbl->GetContentsTable(lpContainer, MAPI_UNICODE | WAB_PROFILE_CONTENTS, &lpABTable)))
  1895. {
  1896. DebugPrintError(( TEXT("GetContentsTable Failed\n")));
  1897. goto out;
  1898. }
  1899. hr = lpABTable->lpVtbl->SetColumns(lpABTable, (LPSPropTagArray)&ptaEidSync, 0 );
  1900. if(HR_FAILED(hr))
  1901. goto out;
  1902. // Reset to the beginning of the table
  1903. //
  1904. hr = lpABTable->lpVtbl->SeekRow(lpABTable, BOOKMARK_BEGINNING, 0, NULL );
  1905. if(HR_FAILED(hr))
  1906. goto out;
  1907. // Read all the rows of the table one by one
  1908. //
  1909. do {
  1910. hr = lpABTable->lpVtbl->QueryRows(lpABTable, 1, 0, &lpRowAB);
  1911. if(HR_FAILED(hr))
  1912. break;
  1913. if(lpRowAB)
  1914. {
  1915. cNumRows = lpRowAB->cRows;
  1916. if (cNumRows)
  1917. {
  1918. LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieid_PR_DISPLAY_NAME].Value.LPSZ;
  1919. LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieid_PR_ENTRYID].Value.bin.lpb;
  1920. ULONG cbEID = lpRowAB->aRow[0].lpProps[ieid_PR_ENTRYID].Value.bin.cb;
  1921. //
  1922. // There are 2 kinds of objects - the MAPI_MAILUSER contact object
  1923. // and the MAPI_DISTLIST contact object
  1924. //
  1925. #ifdef HM_GROUP_SYNCING
  1926. if( (!pWabSync->m_fSyncGroups && (lpRowAB->aRow[0].lpProps[ieid_PR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)) ||
  1927. (pWabSync->m_fSyncGroups && (lpRowAB->aRow[0].lpProps[ieid_PR_OBJECT_TYPE].Value.l == MAPI_DISTLIST)) )
  1928. #else
  1929. // Only consider MAILUSER objects
  1930. if (lpRowAB->aRow[0].lpProps[ieid_PR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
  1931. #endif
  1932. {
  1933. WABCONTACTINFO *lpWCI;
  1934. HTTPCONTACTINFO hci;
  1935. lpWCI = LocalAlloc(LMEM_ZEROINIT, sizeof(WABCONTACTINFO));
  1936. if (!lpWCI)
  1937. {
  1938. hr = E_OUTOFMEMORY;
  1939. DebugPrintError(( TEXT("WABCONTACTINFO Alloc Failed\n")));
  1940. goto out;
  1941. }
  1942. lpWCI->lpEID = LocalAlloc(LMEM_ZEROINIT, cbEID);
  1943. if (!lpWCI->lpEID)
  1944. {
  1945. hr = E_OUTOFMEMORY;
  1946. DebugPrintError(( TEXT("WABCONTACTINFO.ENTRYID Alloc Failed\n")));
  1947. goto out;
  1948. }
  1949. lpWCI->cbEID = cbEID;
  1950. CopyMemory(lpWCI->lpEID, lpEID, cbEID);
  1951. lpWCI->ftModWab = lpRowAB->aRow[0].lpProps[ieid_PR_LAST_MODIFICATION_TIME].Value.ft;
  1952. lpWCI->pszHotmailId = NULL;
  1953. lpWCI->pszModHotmail = NULL;
  1954. if (SUCCEEDED(ContactInfo_LoadFromWAB(pWabSync, &hci, lpWCI, lpEID, cbEID)))
  1955. {
  1956. lpWCI->pszHotmailId = _StrDup(hci.pszId);
  1957. lpWCI->pszModHotmail = _StrDup(hci.pszModified);
  1958. ContactInfo_Free(&hci);
  1959. }
  1960. // search the multi value list of longs for the proper server id. If found,
  1961. // then get the appropriate hotmail id and mod id.
  1962. if (FAILED(Vector_AddItem(pWabSync->m_pWabItems, lpWCI)))
  1963. goto out;
  1964. }
  1965. }
  1966. FreeProws(lpRowAB );
  1967. }
  1968. }while ( SUCCEEDED(hr) && cNumRows && lpRowAB) ;
  1969. out:
  1970. if (HR_FAILED(hr))
  1971. {
  1972. if (pWabSync->m_pWabItems)
  1973. WABSync_FreeItems(pWabSync);
  1974. if (lpContainer)
  1975. lpContainer->lpVtbl->Release(lpContainer);
  1976. if (lpABTable)
  1977. lpABTable->lpVtbl->Release(lpABTable);
  1978. }
  1979. return hr;
  1980. }
  1981. HRESULT WABSync_LoadLastModInfo(LPWABSYNC pWabSync)
  1982. {
  1983. TCHAR szKey[MAX_PATH];
  1984. DWORD dwType = 0;
  1985. DWORD dwValue = 0;
  1986. HKEY hKey = NULL;
  1987. DWORD dwSize;
  1988. HRESULT hr = E_FAIL;
  1989. FILETIME ftValue;
  1990. Assert(pWabSync);
  1991. Assert(*pWabSync->m_szLoginName);
  1992. StrCpyN(szKey, g_lpszSyncKey, ARRAYSIZE(szKey));
  1993. #ifndef UNICODE
  1994. StrCatBuff(szKey, pWabSync->m_szLoginName, ARRAYSIZE(szKey));
  1995. #else
  1996. {
  1997. LPTSTR lpName = ConvertAtoW(pWabSync->m_szLoginName);
  1998. StrCatBuff(szKey, lpName, ARRAYSIZE(szKey));
  1999. LocalFreeAndNull(&lpName);
  2000. }
  2001. #endif
  2002. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_READ, &hKey))
  2003. {
  2004. dwSize = sizeof(DWORD);
  2005. hr = RegQueryValueEx( hKey, TEXT("Server ID"), NULL, &dwType, (LPBYTE) &dwValue, &dwSize);
  2006. if (dwValue && ERROR_SUCCESS == hr)
  2007. {
  2008. pWabSync->m_dwServerID = dwValue;
  2009. }
  2010. else
  2011. goto fail;
  2012. dwSize = sizeof(FILETIME);
  2013. if (ERROR_SUCCESS == (hr = RegQueryValueEx( hKey, TEXT("Server Last Sync"), NULL, &dwType, (LPBYTE) &ftValue, &dwSize)))
  2014. {
  2015. pWabSync->m_ftLastSync = ftValue;
  2016. }
  2017. else
  2018. goto fail;
  2019. }
  2020. else
  2021. {
  2022. // the key for this user account isn't there.
  2023. // create a new one and return default values.
  2024. // a random number would be nice here, instead we will
  2025. // use the low DWORD of a date time....
  2026. GetSystemTimeAsFileTime(&ftValue);
  2027. pWabSync->m_dwServerID = ftValue.dwLowDateTime;
  2028. // NULL filetime since we haven't synced yet, everything is after the last sync
  2029. ZeroMemory(&pWabSync->m_ftLastSync, sizeof(FILETIME));
  2030. hr = WABSync_SaveCurrentModInfo(pWabSync);
  2031. }
  2032. fail:
  2033. if (hKey)
  2034. RegCloseKey(hKey);
  2035. return hr;
  2036. }
  2037. HRESULT WABSync_SaveCurrentModInfo(LPWABSYNC pWabSync)
  2038. {
  2039. TCHAR szKey[MAX_PATH];
  2040. HKEY hKey = NULL;
  2041. HRESULT hr = E_FAIL;
  2042. Assert(pWabSync);
  2043. Assert(*pWabSync->m_szLoginName);
  2044. StrCpyN(szKey, g_lpszSyncKey, ARRAYSIZE(szKey));
  2045. {
  2046. LPTSTR lpName = ConvertAtoW(pWabSync->m_szLoginName);
  2047. StrCatBuff(szKey, lpName, ARRAYSIZE(szKey));
  2048. LocalFreeAndNull(&lpName);
  2049. }
  2050. if(ERROR_SUCCESS == ( hr = RegCreateKey(HKEY_CURRENT_USER, szKey, &hKey)))
  2051. {
  2052. GetSystemTimeAsFileTime(&pWabSync->m_ftLastSync);
  2053. hr = RegSetValueEx( hKey, TEXT("Server ID"), 0, REG_DWORD, (BYTE *)&pWabSync->m_dwServerID, sizeof(DWORD));
  2054. hr = RegSetValueEx( hKey, TEXT("Server Last Sync"), 0, REG_BINARY, (BYTE *)&pWabSync->m_ftLastSync, sizeof(FILETIME));
  2055. RegCloseKey(hKey);
  2056. }
  2057. return hr;
  2058. }
  2059. void WABSync_Progress(LPWABSYNC pWabSync, DWORD dwResId, DWORD dwCount)
  2060. {
  2061. TCHAR szRes[MAX_PATH], szMsg[MAX_PATH];
  2062. HWND hwndText;
  2063. LoadString(hinstMapiX, dwResId, szRes, CharSizeOf(szRes));
  2064. if (dwCount != -1)
  2065. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, dwCount);
  2066. else
  2067. StrCpyN(szMsg, szRes, ARRAYSIZE(szMsg));
  2068. hwndText = GetDlgItem(pWabSync->m_hWnd, IDC_SYNC_MSG);
  2069. if (hwndText)
  2070. {
  2071. SetWindowText(hwndText, szMsg);
  2072. }
  2073. SendDlgItemMessage(pWabSync->m_hWnd, IDC_SYNC_PROGBAR, PBM_SETRANGE, 0, MAKELPARAM(0, pWabSync->m_cTotalOps));
  2074. SendDlgItemMessage(pWabSync->m_hWnd, IDC_SYNC_PROGBAR, PBM_SETPOS, pWabSync->m_cTotalOps - dwCount, 0);
  2075. }
  2076. void WABSync_NextState(LPWABSYNC pWabSync)
  2077. {
  2078. PostMessage(pWabSync->m_hWnd, WM_SYNC_NEXTSTATE, 0, (LPARAM)pWabSync);
  2079. }
  2080. void _WABSync_NextState(LPWABSYNC pWabSync)
  2081. {
  2082. HRESULT hr;
  2083. Assert(pWabSync);
  2084. pWabSync->m_state++;
  2085. switch(pWabSync->m_state)
  2086. {
  2087. case SYNC_STATE_SERVER_CONTACT_DISCOVERY:
  2088. WABSync_Progress(pWabSync, idsSyncConnecting, -1);
  2089. hr = WABSync_RequestContactsRootProperty(pWabSync);
  2090. break;
  2091. case SYNC_STATE_PROCESS_OPS:
  2092. WABSync_Progress(pWabSync, idsSyncSynchronizing, Vector_GetLength(pWabSync->m_pOps));
  2093. if (pWabSync->m_pOps && Vector_GetLength(pWabSync->m_pOps) > 0)
  2094. {
  2095. if (WABSync_NextOp(pWabSync, FALSE))
  2096. return;
  2097. }
  2098. // fall through if there are no ops
  2099. pWabSync->m_state++;
  2100. case SYNC_STATE_PROCESS_CONFLICTS:
  2101. WABSync_Progress(pWabSync, idsSyncConflicts, Vector_GetLength(pWabSync->m_pOps));
  2102. if (pWabSync->m_pOps && Vector_GetLength(pWabSync->m_pOps) > 0)
  2103. {
  2104. if(SUCCEEDED(WABSync_DoConflicts(pWabSync)))
  2105. return;
  2106. }
  2107. // fall through if there are no ops
  2108. pWabSync->m_state++;
  2109. if (pWabSync->m_fAborted)
  2110. return;
  2111. case SYNC_STATE_PROCESS_MERGED_CONFLICTS:
  2112. WABSync_Progress(pWabSync, idsSyncFinishing, Vector_GetLength(pWabSync->m_pOps));
  2113. if (pWabSync->m_pOps && Vector_GetLength(pWabSync->m_pOps) > 0)
  2114. {
  2115. if (WABSync_NextOp(pWabSync, FALSE))
  2116. return;
  2117. }
  2118. // fall through if there are no ops
  2119. pWabSync->m_state++;
  2120. case SYNC_STATE_DONE:
  2121. WABSync_FinishSynchronize(pWabSync, (pWabSync->m_cAborts == 0 ? S_OK : E_FAIL));
  2122. break;
  2123. }
  2124. }
  2125. BOOL _WABSync_NextOp(LPWABSYNC pWabSync, BOOL fPopFirst)
  2126. {
  2127. HRESULT hr = E_FAIL;
  2128. LPHOTSYNCOP pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
  2129. Assert(pWabSync->m_state == SYNC_STATE_PROCESS_OPS || pWabSync->m_state == SYNC_STATE_PROCESS_MERGED_CONFLICTS);
  2130. Assert(pOp);
  2131. if (pOp && fPopFirst)
  2132. {
  2133. LPVECTOR pVector;
  2134. pVector = pWabSync->m_pOps;
  2135. Assert(pVector);
  2136. Vector_Remove(pVector, pOp);
  2137. Syncop_Delete(pOp);
  2138. pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
  2139. }
  2140. if (pWabSync->m_state == SYNC_STATE_PROCESS_OPS)
  2141. WABSync_Progress(pWabSync, idsSyncSynchronizing, Vector_GetLength(pWabSync->m_pOps));
  2142. else if (pWabSync->m_state == SYNC_STATE_PROCESS_MERGED_CONFLICTS)
  2143. WABSync_Progress(pWabSync, idsSyncFinishing, Vector_GetLength(pWabSync->m_pOps));
  2144. if (pOp)
  2145. hr = Syncop_Begin(pOp);
  2146. return (SUCCEEDED(hr));
  2147. }
  2148. BOOL WABSync_NextOp(LPWABSYNC pWabSync, BOOL fPopFirst)
  2149. {
  2150. HRESULT hr = E_FAIL;
  2151. LPHOTSYNCOP pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
  2152. if (!pOp)
  2153. return FALSE;
  2154. PostMessage(pWabSync->m_hWnd, WM_SYNC_NEXTOP, fPopFirst, (LPARAM)pWabSync);
  2155. return TRUE;
  2156. }
  2157. void WABSync_FreeOps(LPWABSYNC pWabSync)
  2158. {
  2159. LPHOTSYNCOP pOp;
  2160. if (pWabSync->m_pOps)
  2161. {
  2162. LONG dwIndex, cItems = Vector_GetLength(pWabSync->m_pOps);
  2163. for (dwIndex = cItems - 1; dwIndex >= 0; --dwIndex)
  2164. {
  2165. pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, dwIndex);
  2166. if (pOp)
  2167. {
  2168. Vector_RemoveItem(pWabSync->m_pOps, dwIndex);
  2169. Syncop_Abort(pOp);
  2170. Syncop_Delete(pOp);
  2171. }
  2172. if (dwIndex == 0)
  2173. break;
  2174. }
  2175. }
  2176. }
  2177. void WABSync_FreeItems(LPWABSYNC pWabSync)
  2178. {
  2179. LPWABCONTACTINFO lprWCI;
  2180. if (pWabSync->m_pWabItems)
  2181. {
  2182. LONG dwIndex, cItems = Vector_GetLength(pWabSync->m_pWabItems);
  2183. for (dwIndex = cItems - 1; dwIndex >= 0; --dwIndex)
  2184. {
  2185. lprWCI = (LPWABCONTACTINFO)Vector_GetItem(pWabSync->m_pWabItems, dwIndex);
  2186. if (lprWCI)
  2187. {
  2188. if (lprWCI->lpEID)
  2189. LocalFree(lprWCI->lpEID);
  2190. LocalFree(lprWCI);
  2191. }
  2192. Vector_RemoveItem(pWabSync->m_pWabItems, dwIndex);
  2193. if (dwIndex == 0)
  2194. break;
  2195. }
  2196. }
  2197. }
  2198. HRESULT WABSync_DoConflicts(LPWABSYNC pWabSync)
  2199. {
  2200. LONG dwIndex, cConflicts = 0, cItems = Vector_GetLength(pWabSync->m_pOps);
  2201. LPHOTSYNCOP pOp;
  2202. LPHTTPCONFLICTINFO pConflicts = NULL;
  2203. if (cItems == 0)
  2204. {
  2205. WABSync_NextState(pWabSync);
  2206. return S_OK;
  2207. }
  2208. pConflicts = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONFLICTINFO) * cItems);
  2209. if (!pConflicts)
  2210. return E_OUTOFMEMORY;
  2211. for (dwIndex = 0; dwIndex < cItems; dwIndex++)
  2212. {
  2213. pOp = Vector_GetItem(pWabSync->m_pOps, dwIndex);
  2214. Assert(pOp->m_bOpType == SYNCOP_CONFLICT);
  2215. if (!pOp || pOp->m_bOpType != SYNCOP_CONFLICT)
  2216. continue;
  2217. Assert(pOp->m_pServerContact);
  2218. Assert(pOp->m_pClientContact);
  2219. pConflicts[dwIndex].pciServer = pOp->m_pServerContact;
  2220. pConflicts[dwIndex].pciClient = pOp->m_pClientContact;
  2221. cConflicts++;
  2222. }
  2223. if (ResolveConflicts(pWabSync->m_hParentWnd, pConflicts, cConflicts))
  2224. {
  2225. HRESULT hr = S_OK;
  2226. for (dwIndex = 0; dwIndex < cConflicts; dwIndex++)
  2227. {
  2228. BOOL fChanged = FALSE;
  2229. DWORD dw;
  2230. pOp = Vector_GetItem(pWabSync->m_pOps, dwIndex);
  2231. Assert(pOp->m_bOpType == SYNCOP_CONFLICT);
  2232. Assert(pOp->m_pServerContact);
  2233. Assert(pOp->m_pClientContact);
  2234. for (dw = 0; dw < CONFLICT_DECISION_COUNT; dw++)
  2235. {
  2236. if (pConflicts[dwIndex].rgcd[dw] != 0)
  2237. {
  2238. fChanged = TRUE;
  2239. break;
  2240. }
  2241. }
  2242. if (fChanged)
  2243. {
  2244. hr = ContactInfo_BlendResults(pOp->m_pServerContact, pOp->m_pClientContact, (CONFLICT_DECISION *)&(pConflicts[dwIndex].rgcd));
  2245. pOp->m_bState = OP_STATE_MERGED;
  2246. }
  2247. else
  2248. {
  2249. // toss out the conflict since they didn't want to change anything
  2250. pOp->m_bState = OP_STATE_DONE;
  2251. }
  2252. // if any of it was skipped, we need to remember this and not update the timestamps.
  2253. if (pConflicts[dwIndex].fContainsSkip)
  2254. {
  2255. pOp->m_fPartialSkip = TRUE;
  2256. pWabSync->m_fSkipped = TRUE;
  2257. }
  2258. }
  2259. //reset progress to new total ops
  2260. pWabSync->m_cTotalOps = Vector_GetLength(pWabSync->m_pOps);
  2261. // HACK to get back into processing ops
  2262. WABSync_NextState(pWabSync);
  2263. return hr;
  2264. }
  2265. else
  2266. WABSync_Abort(pWabSync, E_UserCancel);
  2267. if (pConflicts)
  2268. LocalFree(pConflicts);
  2269. return E_FAIL;
  2270. }
  2271. void WABSync_MergeAddsToConflicts(LPWABSYNC pWabSync)
  2272. {
  2273. DWORD dwOpCount;
  2274. DWORD dwCliAddIndex, dwSvrAddIndex;
  2275. LPHOTSYNCOP pCliOp, pOp, pNewOp;
  2276. BOOL fMerged = FALSE;
  2277. HRESULT hr;
  2278. dwOpCount = Vector_GetLength(pWabSync->m_pOps);
  2279. // search for Client Adds. If found, look for a server add for the
  2280. // same contact.
  2281. for (dwCliAddIndex = 0; dwCliAddIndex < dwOpCount; dwCliAddIndex++)
  2282. {
  2283. fMerged = FALSE;
  2284. pCliOp = Vector_GetItem(pWabSync->m_pOps, dwCliAddIndex);
  2285. if (pCliOp && pCliOp->m_bOpType == SYNCOP_CLIENT_ADD)
  2286. {
  2287. for (dwSvrAddIndex = 0; dwSvrAddIndex < dwOpCount; dwSvrAddIndex++)
  2288. {
  2289. pOp = Vector_GetItem(pWabSync->m_pOps, dwSvrAddIndex);
  2290. if (pOp && pOp->m_bOpType == SYNCOP_SERVER_ADD)
  2291. {
  2292. if (pOp->m_pClientContact && pOp->m_pClientContact->pszEmail &&
  2293. pCliOp->m_pServerContact && pCliOp->m_pServerContact->pszEmail)
  2294. {
  2295. if (lstrcmpiA(pCliOp->m_pServerContact->pszEmail, pOp->m_pClientContact->pszEmail) == 0)
  2296. {
  2297. pNewOp = Syncop_CreateConflict(pCliOp->m_pContactInfo);
  2298. Assert(pNewOp);
  2299. if (pNewOp)
  2300. {
  2301. pNewOp->m_pContactInfo->lpEID = pOp->m_pContactInfo->lpEID;
  2302. pNewOp->m_pContactInfo->cbEID = pOp->m_pContactInfo->cbEID;
  2303. pNewOp->m_pContactInfo->pszaContactIds = pOp->m_pContactInfo->pszaContactIds;
  2304. pNewOp->m_pContactInfo->pszaServerIds = pOp->m_pContactInfo->pszaServerIds;
  2305. pNewOp->m_pContactInfo->pszaModtimes = pOp->m_pContactInfo->pszaModtimes;
  2306. pNewOp->m_pContactInfo->pszaEmails = pOp->m_pContactInfo->pszaEmails;
  2307. pOp->m_pContactInfo->pszaContactIds = NULL;
  2308. pOp->m_pContactInfo->pszaServerIds = NULL;
  2309. pOp->m_pContactInfo->pszaModtimes = NULL;
  2310. pOp->m_pContactInfo->pszaEmails = NULL;
  2311. pOp->m_pContactInfo->lpEID = NULL;
  2312. pOp->m_pContactInfo->cbEID = 0;
  2313. pCliOp->m_pContactInfo = NULL;
  2314. pNewOp->m_pServerContact = pCliOp->m_pServerContact;
  2315. pCliOp->m_pServerContact = NULL;
  2316. Syncop_Init(pNewOp, (IHTTPMailCallback *)pWabSync, pWabSync->m_pTransport);
  2317. hr = Vector_AddItem(pWabSync->m_pOps, pNewOp);
  2318. if (dwSvrAddIndex < dwCliAddIndex)
  2319. --dwCliAddIndex;
  2320. Vector_Remove(pWabSync->m_pOps, pOp);
  2321. Vector_Remove(pWabSync->m_pOps, pCliOp);
  2322. dwOpCount = Vector_GetLength(pWabSync->m_pOps);
  2323. fMerged = TRUE;
  2324. }
  2325. break;
  2326. }
  2327. }
  2328. }
  2329. }
  2330. }
  2331. if (fMerged)
  2332. -- dwCliAddIndex;
  2333. }
  2334. }
  2335. // ****************************************************************************************************
  2336. // V E C T O R "C L A S S"
  2337. //
  2338. // Basic vector class (resizable / sortable array of LPVOIDs).
  2339. //
  2340. HRESULT Vector_Create(LPVECTOR *ppVector)
  2341. {
  2342. Assert(ppVector);
  2343. *ppVector = LocalAlloc(LMEM_ZEROINIT, sizeof(VECTOR));
  2344. if (*ppVector)
  2345. {
  2346. (*ppVector)->m_dwGrowBy = 4;
  2347. return S_OK;
  2348. }
  2349. else
  2350. return E_OUTOFMEMORY;
  2351. }
  2352. /*
  2353. Vector_Delete
  2354. Clean up any memory that was allocated in the Vector object
  2355. */
  2356. void Vector_Delete(LPVECTOR pVector)
  2357. {
  2358. Assert(pVector);
  2359. if (pVector->m_pItems)
  2360. LocalFree(pVector->m_pItems);
  2361. if (pVector)
  2362. LocalFree(pVector);
  2363. }
  2364. /*
  2365. Vector_GetLength
  2366. Get the number of items in the vector.
  2367. */
  2368. DWORD Vector_GetLength(LPVECTOR pVector)
  2369. {
  2370. Assert(pVector);
  2371. return pVector->m_cItems;
  2372. }
  2373. /*
  2374. Vector_AddItem
  2375. Add a item to the end of the item list.
  2376. */
  2377. HRESULT Vector_AddItem(LPVECTOR pVector, LPVOID lpvItem)
  2378. {
  2379. DWORD dwNewIndex;
  2380. DWORD dw;
  2381. Assert(pVector);
  2382. // make more room for pointers, if necessary
  2383. if (pVector->m_cSpaces == pVector->m_cItems)
  2384. {
  2385. LPVOID pNewItems;
  2386. DWORD dwOldSize = pVector->m_cSpaces * sizeof(char *);
  2387. pVector->m_cSpaces += pVector->m_dwGrowBy;
  2388. pNewItems = LocalAlloc(LMEM_ZEROINIT, sizeof(char *) * pVector->m_cSpaces);
  2389. if (!pNewItems)
  2390. {
  2391. pVector->m_cSpaces -= pVector->m_dwGrowBy;
  2392. return E_OUTOFMEMORY;
  2393. }
  2394. else
  2395. {
  2396. if (pVector->m_pItems)
  2397. {
  2398. CopyMemory(pNewItems, pVector->m_pItems, dwOldSize);
  2399. LocalFree(pVector->m_pItems);
  2400. }
  2401. pVector->m_pItems = (LPVOID *)pNewItems;
  2402. pVector->m_dwGrowBy = pVector->m_dwGrowBy << 1; // double the size for the next time we grow it.
  2403. }
  2404. }
  2405. //now put the item in the next location
  2406. dwNewIndex = pVector->m_cItems++;
  2407. pVector->m_pItems[dwNewIndex] = lpvItem;
  2408. return S_OK;
  2409. }
  2410. /*
  2411. Vector_Remove
  2412. Remove a given item from the vector
  2413. */
  2414. void Vector_Remove(LPVECTOR pVector, LPVOID lpvItem)
  2415. {
  2416. DWORD dw;
  2417. for (dw = 0; dw < pVector->m_cItems; dw++)
  2418. {
  2419. if (pVector->m_pItems[dw] == lpvItem)
  2420. {
  2421. Vector_RemoveItem(pVector, dw);
  2422. return;
  2423. }
  2424. }
  2425. }
  2426. /*
  2427. Vector_RemoveItem
  2428. Remove a item at zero based index iIndex
  2429. */
  2430. void Vector_RemoveItem(LPVECTOR pVector, DWORD dwIndex)
  2431. {
  2432. int iCopySize;
  2433. DWORD dw;
  2434. Assert(pVector);
  2435. Assert(dwIndex < pVector->m_cItems);
  2436. // move the other pItems down
  2437. for (dw = dwIndex+1; dw < pVector->m_cItems; dw ++)
  2438. pVector->m_pItems[dw - 1] = pVector->m_pItems[dw];
  2439. // null out the last item in the list and decrement the counter.
  2440. pVector->m_pItems[--pVector->m_cItems] = NULL;
  2441. }
  2442. /*
  2443. CVector::GetItem
  2444. Return the pointer to the item at zero based index iIndex.
  2445. Return the item at the given index. Note that the char pointer
  2446. is still owned by the item list and should not be deleted.
  2447. */
  2448. LPVOID Vector_GetItem(LPVECTOR pVector, DWORD dwIndex)
  2449. {
  2450. Assert(pVector);
  2451. Assert(dwIndex < pVector->m_cItems || dwIndex == 0);
  2452. if (dwIndex < pVector->m_cItems )
  2453. return pVector->m_pItems[dwIndex];
  2454. else
  2455. return NULL;
  2456. }
  2457. void Vector_Sort(LPVECTOR pVector, FnCompareFunc lpfnCompare)
  2458. {
  2459. qsort(pVector->m_pItems, pVector->m_cItems, sizeof(LPVOID), lpfnCompare);
  2460. }
  2461. LPHOTSYNCOP Syncop_CreateServerAdd(LPWABCONTACTINFO pContactInfo)
  2462. {
  2463. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2464. if (pOp)
  2465. {
  2466. pOp->m_bOpType = SYNCOP_SERVER_ADD;
  2467. pOp->m_pfnHandleResponse = Syncop_ServerAddResponse;
  2468. pOp->m_pfnBegin = Syncop_ServerAddBegin;
  2469. pOp->m_pContactInfo = pContactInfo;
  2470. }
  2471. return pOp;
  2472. }
  2473. LPHOTSYNCOP Syncop_CreateServerDelete(LPWABCONTACTINFO pContactInfo)
  2474. {
  2475. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2476. if (pOp)
  2477. {
  2478. pOp->m_bOpType = SYNCOP_SERVER_DELETE;
  2479. pOp->m_pfnHandleResponse = Syncop_ServerDeleteResponse;
  2480. pOp->m_pfnBegin = Syncop_ServerDeleteBegin;
  2481. pOp->m_pContactInfo = pContactInfo;
  2482. }
  2483. return pOp;
  2484. }
  2485. LPHOTSYNCOP Syncop_CreateServerChange(LPWABCONTACTINFO pContactInfo)
  2486. {
  2487. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2488. if (pOp)
  2489. {
  2490. pOp->m_bOpType = SYNCOP_SERVER_CHANGE;
  2491. pOp->m_pfnHandleResponse = Syncop_ServerChangeResponse;
  2492. pOp->m_pfnBegin = Syncop_ServerChangeBegin;
  2493. pOp->m_pContactInfo = pContactInfo;
  2494. }
  2495. return pOp;
  2496. }
  2497. LPHOTSYNCOP Syncop_CreateClientAdd(LPWABCONTACTINFO pContactInfo)
  2498. {
  2499. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2500. Assert(pContactInfo);
  2501. Assert(pOp);
  2502. if (pOp)
  2503. {
  2504. pOp->m_bOpType = SYNCOP_CLIENT_ADD;
  2505. pOp->m_pfnHandleResponse = Syncop_ClientAddResponse;
  2506. pOp->m_pfnBegin = Syncop_ClientAddBegin;
  2507. pOp->m_pContactInfo = pContactInfo;
  2508. }
  2509. return pOp;
  2510. }
  2511. LPHOTSYNCOP Syncop_CreateClientDelete(LPWABCONTACTINFO pContactInfo)
  2512. {
  2513. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2514. if (pOp)
  2515. {
  2516. pOp->m_bOpType = SYNCOP_CLIENT_DELETE;
  2517. pOp->m_pfnHandleResponse = Syncop_ClientDeleteResponse;
  2518. pOp->m_pfnBegin = Syncop_ClientDeleteBegin;
  2519. pOp->m_pContactInfo = pContactInfo;
  2520. }
  2521. return pOp;
  2522. }
  2523. LPHOTSYNCOP Syncop_CreateClientChange(LPWABCONTACTINFO pContactInfo)
  2524. {
  2525. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2526. if (pOp)
  2527. {
  2528. pOp->m_bOpType = SYNCOP_CLIENT_CHANGE;
  2529. pOp->m_pfnHandleResponse = Syncop_ClientChangeResponse;
  2530. pOp->m_pfnBegin = Syncop_ClientChangeBegin;
  2531. pOp->m_pContactInfo = pContactInfo;
  2532. }
  2533. return pOp;
  2534. }
  2535. LPHOTSYNCOP Syncop_CreateConflict(LPWABCONTACTINFO pContactInfo)
  2536. {
  2537. LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
  2538. if (pOp)
  2539. {
  2540. pOp->m_bOpType = SYNCOP_CONFLICT;
  2541. pOp->m_pfnHandleResponse = Syncop_ConflictResponse;
  2542. pOp->m_pfnBegin = Syncop_ConflictBegin;
  2543. pOp->m_pContactInfo = pContactInfo;
  2544. }
  2545. return pOp;
  2546. }
  2547. HRESULT Syncop_Init(LPHOTSYNCOP pSyncOp, IHTTPMailCallback *pHotSync, IHTTPMailTransport *pTransport)
  2548. {
  2549. HRESULT hr = S_OK;
  2550. Assert(pSyncOp);
  2551. Assert(pSyncOp->m_pHotSync == NULL);
  2552. Assert(pSyncOp->m_pTransport == NULL);
  2553. pSyncOp->m_pClientContact = NULL;
  2554. pSyncOp->m_pHotSync = pHotSync;
  2555. pSyncOp->m_pTransport = pTransport;
  2556. pSyncOp->m_bState = OP_STATE_INITIALIZING;
  2557. pSyncOp->m_fPartialSkip = FALSE;
  2558. pSyncOp->m_dwRetries = 0;
  2559. if (pSyncOp->m_pTransport)
  2560. IHTTPMailTransport_AddRef(pSyncOp->m_pTransport);
  2561. if (pSyncOp->m_pHotSync)
  2562. IHTTPMailCallback_AddRef(pSyncOp->m_pHotSync);
  2563. if (pSyncOp->m_bOpType == SYNCOP_SERVER_ADD ||
  2564. pSyncOp->m_bOpType == SYNCOP_SERVER_CHANGE ||
  2565. pSyncOp->m_bOpType == SYNCOP_CLIENT_CHANGE ||
  2566. pSyncOp->m_bOpType == SYNCOP_CONFLICT )
  2567. {
  2568. pSyncOp->m_pClientContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
  2569. if (pSyncOp->m_pClientContact)
  2570. hr = ContactInfo_LoadFromWAB(((LPWABSYNC)pSyncOp->m_pHotSync),
  2571. pSyncOp->m_pClientContact,
  2572. pSyncOp->m_pContactInfo,
  2573. pSyncOp->m_pContactInfo->lpEID,
  2574. pSyncOp->m_pContactInfo->cbEID);
  2575. }
  2576. return hr;
  2577. }
  2578. HRESULT Syncop_Delete(LPHOTSYNCOP pSyncOp)
  2579. {
  2580. Assert(pSyncOp);
  2581. if (pSyncOp->m_pTransport)
  2582. IHTTPMailTransport_Release(pSyncOp->m_pTransport);
  2583. if (pSyncOp->m_pHotSync)
  2584. IHTTPMailCallback_Release(pSyncOp->m_pHotSync);
  2585. if (pSyncOp->m_pServerContact)
  2586. {
  2587. ContactInfo_Free(pSyncOp->m_pServerContact);
  2588. LocalFree(pSyncOp->m_pServerContact);
  2589. }
  2590. if (pSyncOp->m_pClientContact)
  2591. {
  2592. ContactInfo_Free(pSyncOp->m_pClientContact);
  2593. LocalFree(pSyncOp->m_pClientContact);
  2594. }
  2595. if (pSyncOp->m_pContactInfo)
  2596. {
  2597. WABContact_Delete(pSyncOp->m_pContactInfo);
  2598. }
  2599. LocalFree(pSyncOp);
  2600. return S_OK;
  2601. }
  2602. HRESULT Syncop_HandleResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2603. {
  2604. Assert(pSyncOp);
  2605. Assert(pSyncOp->m_pfnHandleResponse);
  2606. Assert(pSyncOp->m_bOpType != SYNCOP_SERVER_INVALID);
  2607. return (pSyncOp->m_pfnHandleResponse)(pSyncOp, pResponse);
  2608. }
  2609. HRESULT Syncop_Begin(LPHOTSYNCOP pSyncOp)
  2610. {
  2611. Assert(pSyncOp);
  2612. Assert(pSyncOp->m_pfnBegin);
  2613. Assert(pSyncOp->m_bOpType != SYNCOP_SERVER_INVALID);
  2614. return (pSyncOp->m_pfnBegin)(pSyncOp);
  2615. }
  2616. HRESULT Syncop_Abort(LPHOTSYNCOP pSyncOp)
  2617. {
  2618. Assert(pSyncOp);
  2619. return E_NOTIMPL;
  2620. }
  2621. HRESULT Syncop_ServerAddResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2622. {
  2623. HRESULT hr = S_OK;
  2624. LPWABSYNC pWabSync = (LPWABSYNC)(pSyncOp->m_pHotSync);
  2625. Assert(pSyncOp);
  2626. Assert(pWabSync);
  2627. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rPostContactInfo.pszHref)
  2628. {
  2629. pSyncOp->m_pClientContact->pszId = pResponse->rPostContactInfo.pszId;
  2630. pResponse->rPostContactInfo.pszId = NULL;
  2631. pSyncOp->m_pClientContact->pszModified = pResponse->rPostContactInfo.pszModified;
  2632. pResponse->rPostContactInfo.pszModified = NULL;
  2633. hr = ContactInfo_SaveToWAB(pWabSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo,
  2634. pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
  2635. if (!WABSync_NextOp(pWabSync, TRUE))
  2636. WABSync_NextState(pWabSync);
  2637. }
  2638. else
  2639. {
  2640. if (IXP_E_HTTP_CONFLICT == pResponse->rIxpResult.hrResult)
  2641. {
  2642. // if we get a conflict, it is probably because the nickname we
  2643. // generated is not unique. Lets try to generate a new one, but
  2644. // don't try this more than twice.
  2645. if (pSyncOp->m_dwRetries <= 2)
  2646. {
  2647. pSyncOp->m_dwRetries ++;
  2648. if (SUCCEEDED(hr = ContactInfo_GenerateNickname(pSyncOp->m_pClientContact)))
  2649. hr = pSyncOp->m_pTransport->lpVtbl->PostContact(pSyncOp->m_pTransport, ((LPWABSYNC)pSyncOp->m_pHotSync)->m_pszRootUrl, pSyncOp->m_pClientContact, 0);
  2650. }
  2651. else
  2652. { // [PaulHi] 12/3/98 After trying three different nicknames, abort this
  2653. // synchronization operation.
  2654. hr = pResponse->rIxpResult.hrResult;
  2655. }
  2656. }
  2657. else
  2658. {
  2659. if (pResponse->rPostContactInfo.pszHref)
  2660. {
  2661. // TODO : delete the server version here?
  2662. // we have the reference, just not the timestamp or id. Guess the id, and
  2663. // throw in a crappy timestamp so that it will get fixed up next time
  2664. char *pszId = NULL, *psz;
  2665. psz = pResponse->rPostContactInfo.pszHref;
  2666. while (*psz)
  2667. {
  2668. if ('/' == *psz)
  2669. {
  2670. if (psz[1] == 0)
  2671. *psz = 0;
  2672. else
  2673. pszId = ++psz;
  2674. }
  2675. else
  2676. psz++;
  2677. }
  2678. if (pszId)
  2679. {
  2680. pSyncOp->m_pClientContact->pszId = _StrDup(pszId);
  2681. pResponse->rPostContactInfo.pszId = NULL;
  2682. pResponse->rPostContactInfo.pszModified = _StrDup( "1993-01-01T00:00");
  2683. hr = ContactInfo_SaveToWAB(pWabSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo,
  2684. pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
  2685. if (!WABSync_NextOp(pWabSync, TRUE))
  2686. WABSync_NextState(pWabSync);
  2687. return S_OK;
  2688. }
  2689. }
  2690. hr = pResponse->rIxpResult.hrResult;
  2691. }
  2692. }
  2693. return hr;
  2694. }
  2695. HRESULT Syncop_ServerAddBegin(LPHOTSYNCOP pSyncOp)
  2696. {
  2697. HRESULT hr;
  2698. Assert(pSyncOp);
  2699. if (!pSyncOp->m_pClientContact)
  2700. {
  2701. hr = E_OUTOFMEMORY;
  2702. goto exit;
  2703. }
  2704. if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
  2705. {
  2706. pSyncOp->m_bState = OP_STATE_SERVER_GET;
  2707. if (pSyncOp->m_pClientContact->pszNickname || SUCCEEDED(hr = ContactInfo_GenerateNickname(pSyncOp->m_pClientContact)))
  2708. hr = pSyncOp->m_pTransport->lpVtbl->PostContact(pSyncOp->m_pTransport, ((LPWABSYNC)pSyncOp->m_pHotSync)->m_pszRootUrl, pSyncOp->m_pClientContact, 0);
  2709. }
  2710. exit:
  2711. if (FAILED(hr))
  2712. {
  2713. if (pSyncOp->m_pClientContact)
  2714. {
  2715. ContactInfo_Free(pSyncOp->m_pClientContact);
  2716. LocalFree(pSyncOp->m_pClientContact);
  2717. pSyncOp->m_pClientContact = NULL;
  2718. }
  2719. }
  2720. return hr;
  2721. }
  2722. HRESULT Syncop_ServerDeleteResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2723. {
  2724. HRESULT hr = pResponse->rIxpResult.hrResult;
  2725. LPWABSYNC pWabSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2726. Assert(pSyncOp);
  2727. if (SUCCEEDED(pResponse->rIxpResult.hrResult))
  2728. {
  2729. TCHAR tszServerId[MAX_PATH];
  2730. TCHAR tszKey[MAX_PATH];
  2731. HKEY hkey = NULL;
  2732. // now that the delete has completed, delete the tombstone from the registry.
  2733. if ( FAILED(hrMakeContactId(
  2734. tszServerId,
  2735. MAX_PATH,
  2736. ((LPIAB)(pWabSync->m_pAB))->szProfileID,
  2737. pWabSync->m_pszAccountId,
  2738. pWabSync->m_szLoginName)) )
  2739. {
  2740. return hr;
  2741. }
  2742. wnsprintf(tszKey, ARRAYSIZE(tszKey), TEXT("%s%s"), g_lpszSyncKey, tszServerId);
  2743. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tszKey, 0, KEY_SET_VALUE, &hkey))
  2744. {
  2745. LPTSTR lpKey =
  2746. ConvertAtoW(pSyncOp->m_pContactInfo->pszHotmailId);
  2747. RegDeleteValue(hkey, lpKey);
  2748. LocalFreeAndNull(&lpKey);
  2749. RegCloseKey(hkey);
  2750. }
  2751. if (!WABSync_NextOp(pWabSync, TRUE))
  2752. WABSync_NextState(pWabSync);
  2753. }
  2754. return hr;
  2755. }
  2756. HRESULT Syncop_ServerDeleteBegin(LPHOTSYNCOP pSyncOp)
  2757. {
  2758. HRESULT hr;
  2759. Assert(pSyncOp);
  2760. Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
  2761. hr = pSyncOp->m_pTransport->lpVtbl->CommandDELETE(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
  2762. return hr;
  2763. }
  2764. HRESULT Syncop_ServerChangeResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2765. {
  2766. HRESULT hr = pResponse->rIxpResult.hrResult;
  2767. LPWABSYNC pWabSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2768. Assert(pSyncOp);
  2769. if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
  2770. {
  2771. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
  2772. {
  2773. // assume the whole struct
  2774. Assert(pResponse->rContactInfoList.prgContactInfo);
  2775. Assert(pResponse->rContactInfoList.cContactInfo == 1);
  2776. if (!pSyncOp->m_pServerContact)
  2777. pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
  2778. *pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
  2779. ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
  2780. pSyncOp->m_bState = OP_STATE_LOADED;
  2781. if (!ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
  2782. {
  2783. pSyncOp->m_bState = OP_STATE_SERVER_PUT;
  2784. hr = ContactInfo_PreparePatch(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact);
  2785. hr = pSyncOp->m_pTransport->lpVtbl->PatchContact(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, pSyncOp->m_pClientContact, 0);
  2786. }
  2787. else
  2788. if (!WABSync_NextOp(pWabSync, TRUE))
  2789. WABSync_NextState(pWabSync);
  2790. }
  2791. }
  2792. else if (OP_STATE_SERVER_PUT == pSyncOp->m_bState)
  2793. {
  2794. // if it succeeded, save the new values mod stamp, etc to the wab
  2795. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
  2796. {
  2797. SafeCoMemFree(pSyncOp->m_pClientContact->pszId);
  2798. pSyncOp->m_pClientContact->pszId = pResponse->rPostContactInfo.pszId;
  2799. pResponse->rPostContactInfo.pszId = NULL;
  2800. SafeCoMemFree(pSyncOp->m_pClientContact->pszModified);
  2801. pSyncOp->m_pClientContact->pszModified = pResponse->rPostContactInfo.pszModified;
  2802. pResponse->rPostContactInfo.pszModified = NULL;
  2803. hr = ContactInfo_SaveToWAB(pWabSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
  2804. if (!WABSync_NextOp(pWabSync, TRUE))
  2805. WABSync_NextState(pWabSync);
  2806. }
  2807. }
  2808. return hr;
  2809. }
  2810. HRESULT Syncop_ServerChangeBegin(LPHOTSYNCOP pSyncOp)
  2811. {
  2812. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2813. HRESULT hr = S_OK;
  2814. Assert(pSyncOp);
  2815. Assert(pSyncOp->m_pTransport);
  2816. Assert(pSyncOp->m_pContactInfo);
  2817. Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
  2818. if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
  2819. {
  2820. if (pSyncOp->m_pServerContact)
  2821. {
  2822. pSyncOp->m_bState = OP_STATE_LOADED;
  2823. if (!ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
  2824. {
  2825. pSyncOp->m_bState = OP_STATE_SERVER_PUT;
  2826. hr = ContactInfo_PreparePatch(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact);
  2827. hr = pSyncOp->m_pTransport->lpVtbl->PatchContact(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, pSyncOp->m_pClientContact, 0);
  2828. }
  2829. else
  2830. if (!WABSync_NextOp(pHotSync, TRUE))
  2831. WABSync_NextState(pHotSync);
  2832. }
  2833. else
  2834. {
  2835. pSyncOp->m_bState = OP_STATE_SERVER_GET;
  2836. hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
  2837. }
  2838. }
  2839. return hr;
  2840. }
  2841. HRESULT Syncop_ClientAddResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2842. {
  2843. HRESULT hr = S_OK;
  2844. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2845. Assert(pSyncOp);
  2846. if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
  2847. {
  2848. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
  2849. {
  2850. // assume the whole struct
  2851. Assert(pResponse->rContactInfoList.prgContactInfo);
  2852. Assert(pResponse->rContactInfoList.cContactInfo == 1);
  2853. if (!pSyncOp->m_pServerContact)
  2854. pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
  2855. *pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
  2856. ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
  2857. pSyncOp->m_bState = OP_STATE_LOADED;
  2858. ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, NULL, NULL, 0, FALSE);
  2859. if (!WABSync_NextOp(pHotSync, TRUE))
  2860. WABSync_NextState(pHotSync);
  2861. }
  2862. else
  2863. hr = pResponse->rIxpResult.hrResult;
  2864. }
  2865. return hr;
  2866. }
  2867. HRESULT Syncop_ClientAddBegin(LPHOTSYNCOP pSyncOp)
  2868. {
  2869. HRESULT hr = S_OK;
  2870. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2871. Assert(pSyncOp);
  2872. Assert(pSyncOp->m_pTransport);
  2873. Assert(pSyncOp->m_pContactInfo);
  2874. Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
  2875. if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
  2876. {
  2877. if (pSyncOp->m_pServerContact)
  2878. {
  2879. pSyncOp->m_bState = OP_STATE_LOADED;
  2880. ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, NULL, NULL, 0, FALSE);
  2881. if (!WABSync_NextOp(pHotSync, TRUE))
  2882. WABSync_NextState(pHotSync);
  2883. }
  2884. else
  2885. {
  2886. pSyncOp->m_bState = OP_STATE_SERVER_GET;
  2887. hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
  2888. }
  2889. }
  2890. return hr;
  2891. }
  2892. HRESULT Syncop_ClientDeleteResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2893. {
  2894. Assert(pSyncOp);
  2895. return E_NOTIMPL;
  2896. }
  2897. HRESULT Syncop_ClientDeleteBegin(LPHOTSYNCOP pSyncOp)
  2898. {
  2899. LPABCONT lpWABCont = NULL;
  2900. LPWABSYNC pWabSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2901. HRESULT hr = S_OK;
  2902. ULONG cbWABEID = 0;
  2903. LPENTRYID lpWABEID = NULL;
  2904. ULONG ulObjType;
  2905. SBinaryArray SBA = {0};
  2906. Assert(pSyncOp);
  2907. if(HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->GetPAB(pWabSync->m_pAB, &cbWABEID, &lpWABEID)))
  2908. goto exit;
  2909. if(HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB,
  2910. cbWABEID, // size of EntryID to open
  2911. lpWABEID, // EntryID to open
  2912. NULL, // interface
  2913. 0, // flags
  2914. &ulObjType,
  2915. (LPUNKNOWN *)&lpWABCont)))
  2916. goto exit;
  2917. if(!(SBA.lpbin = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary))))
  2918. goto exit;
  2919. SetSBinary(&(SBA.lpbin[0]), pSyncOp->m_pContactInfo->cbEID, (LPBYTE)pSyncOp->m_pContactInfo->lpEID);
  2920. SBA.cValues = 1;
  2921. if(HR_FAILED(hr = lpWABCont->lpVtbl->DeleteEntries( lpWABCont, (LPENTRYLIST) &SBA, 0)))
  2922. {
  2923. hr = S_OK;
  2924. goto exit;
  2925. }
  2926. exit:
  2927. if(SBA.lpbin && SBA.cValues)
  2928. {
  2929. LocalFreeAndNull((LPVOID *) (&(SBA.lpbin[0].lpb)));
  2930. LocalFreeAndNull(&SBA.lpbin);
  2931. }
  2932. if(lpWABCont)
  2933. UlRelease(lpWABCont);
  2934. if(lpWABEID)
  2935. FreeBufferAndNull(&lpWABEID);
  2936. if (!WABSync_NextOp(pWabSync, TRUE))
  2937. WABSync_NextState(pWabSync);
  2938. return hr;
  2939. }
  2940. HRESULT Syncop_ClientChangeResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2941. {
  2942. HRESULT hr = S_OK;
  2943. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2944. Assert(pSyncOp);
  2945. if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
  2946. {
  2947. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
  2948. {
  2949. // assume the whole struct
  2950. Assert(pResponse->rContactInfoList.prgContactInfo);
  2951. Assert(pResponse->rContactInfoList.cContactInfo == 1);
  2952. if (!pSyncOp->m_pServerContact)
  2953. pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
  2954. *pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
  2955. ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
  2956. pSyncOp->m_bState = OP_STATE_LOADED;
  2957. ContactInfo_EmptyNullItems(pSyncOp->m_pServerContact);
  2958. ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
  2959. if (!WABSync_NextOp(pHotSync, TRUE))
  2960. WABSync_NextState(pHotSync);
  2961. }
  2962. else
  2963. hr = pResponse->rIxpResult.hrResult;
  2964. }
  2965. return hr;
  2966. }
  2967. HRESULT Syncop_ClientChangeBegin(LPHOTSYNCOP pSyncOp)
  2968. {
  2969. HRESULT hr = S_OK;
  2970. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2971. Assert(pSyncOp);
  2972. Assert(pSyncOp->m_pTransport);
  2973. Assert(pSyncOp->m_pContactInfo);
  2974. Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
  2975. if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
  2976. {
  2977. if (pSyncOp->m_pServerContact)
  2978. {
  2979. pSyncOp->m_bState = OP_STATE_LOADED;
  2980. ContactInfo_EmptyNullItems(pSyncOp->m_pServerContact);
  2981. ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
  2982. if (!WABSync_NextOp(pHotSync, TRUE))
  2983. WABSync_NextState(pHotSync);
  2984. }
  2985. else
  2986. {
  2987. pSyncOp->m_bState = OP_STATE_SERVER_GET;
  2988. hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
  2989. }
  2990. }
  2991. return hr;
  2992. }
  2993. HRESULT Syncop_ConflictResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
  2994. {
  2995. HRESULT hr = S_OK;
  2996. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  2997. Assert(pSyncOp);
  2998. if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
  2999. {
  3000. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
  3001. {
  3002. // assume the whole struct
  3003. Assert(pResponse->rContactInfoList.prgContactInfo);
  3004. Assert(pResponse->rContactInfoList.cContactInfo == 1);
  3005. if (!pSyncOp->m_pServerContact)
  3006. pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
  3007. *pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
  3008. ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
  3009. pSyncOp->m_bState = OP_STATE_LOADED;
  3010. // if the records match as far as we're concerned, we are done.
  3011. if (ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
  3012. {
  3013. // update the timestamp so it isn't a conflict next time.
  3014. ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
  3015. if (!WABSync_NextOp(pHotSync, TRUE))
  3016. WABSync_NextState(pHotSync);
  3017. }
  3018. else
  3019. {
  3020. // move this item to the end, once all conflicts are loaded, then we
  3021. // will do the dialog
  3022. Vector_Remove(pHotSync->m_pOps, pSyncOp);
  3023. Vector_AddItem(pHotSync->m_pOps, pSyncOp);
  3024. if (!WABSync_NextOp(pHotSync, FALSE))
  3025. WABSync_NextState(pHotSync);
  3026. }
  3027. }
  3028. else
  3029. hr = pResponse->rIxpResult.hrResult;
  3030. }
  3031. else if (OP_STATE_SERVER_PUT == pSyncOp->m_bState)
  3032. {
  3033. // if it succeeded, save the new values mod stamp, etc to the wab
  3034. if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
  3035. {
  3036. SafeCoMemFree(pSyncOp->m_pClientContact->pszId);
  3037. pSyncOp->m_pClientContact->pszId = pResponse->rPostContactInfo.pszId;
  3038. pResponse->rPostContactInfo.pszId = NULL;
  3039. SafeCoMemFree(pSyncOp->m_pClientContact->pszModified);
  3040. pSyncOp->m_pClientContact->pszModified = pResponse->rPostContactInfo.pszModified;
  3041. pResponse->rPostContactInfo.pszModified = NULL;
  3042. if (!pSyncOp->m_fPartialSkip)
  3043. hr = ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
  3044. if (!WABSync_NextOp(pHotSync, TRUE))
  3045. WABSync_NextState(pHotSync);
  3046. }
  3047. }
  3048. return hr;
  3049. }
  3050. HRESULT Syncop_ConflictBegin(LPHOTSYNCOP pSyncOp)
  3051. {
  3052. HRESULT hr = S_OK;
  3053. LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
  3054. Assert(pSyncOp);
  3055. Assert(pSyncOp->m_pTransport);
  3056. Assert(pSyncOp->m_pContactInfo);
  3057. Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
  3058. if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
  3059. {
  3060. if (pSyncOp->m_pServerContact)
  3061. {
  3062. pSyncOp->m_bState = OP_STATE_LOADED;
  3063. // if the records match as far as we're concerned, we are done.
  3064. if (ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
  3065. {
  3066. // update the timestamp so it isn't a conflict next time.
  3067. ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
  3068. if (!WABSync_NextOp(pHotSync, TRUE))
  3069. WABSync_NextState(pHotSync);
  3070. }
  3071. else
  3072. {
  3073. // move this item to the end, once all conflicts are loaded, then we
  3074. // will do the dialog
  3075. Vector_Remove(pHotSync->m_pOps, pSyncOp);
  3076. Vector_AddItem(pHotSync->m_pOps, pSyncOp);
  3077. if (!WABSync_NextOp(pHotSync, FALSE))
  3078. WABSync_NextState(pHotSync);
  3079. }
  3080. }
  3081. else
  3082. {
  3083. pSyncOp->m_bState = OP_STATE_SERVER_GET;
  3084. hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
  3085. }
  3086. }
  3087. else if (OP_STATE_LOADED == pSyncOp->m_bState)
  3088. WABSync_NextState(pHotSync);
  3089. else if (OP_STATE_MERGED == pSyncOp->m_bState)
  3090. {
  3091. hr = ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
  3092. if (FAILED(hr))
  3093. return hr;
  3094. pSyncOp->m_bState = OP_STATE_SERVER_PUT;
  3095. hr = pSyncOp->m_pTransport->lpVtbl->PatchContact(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, pSyncOp->m_pServerContact, 0);
  3096. }
  3097. else if (OP_STATE_DONE == pSyncOp->m_bState)
  3098. {
  3099. if (!WABSync_NextOp(pHotSync, TRUE))
  3100. WABSync_NextState(pHotSync);
  3101. }
  3102. return hr;
  3103. }
  3104. void Syncop_SetServerContactInfo(LPHOTSYNCOP pSyncOp, LPWABCONTACTINFO pWabContactInfo, LPHTTPCONTACTINFO pContactInfo)
  3105. {
  3106. if (!pSyncOp)
  3107. return;
  3108. if (!pSyncOp->m_pServerContact)
  3109. pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
  3110. if (!pSyncOp->m_pServerContact)
  3111. return;
  3112. *pSyncOp->m_pServerContact = *pContactInfo;
  3113. ContactInfo_Clear(pContactInfo);
  3114. pSyncOp->m_pServerContact->pszId = _StrDup(pWabContactInfo->pszHotmailId);
  3115. pSyncOp->m_pServerContact->pszModified = _StrDup(pWabContactInfo->pszModHotmail);
  3116. }
  3117. void WABContact_Delete(LPWABCONTACTINFO pContact)
  3118. {
  3119. Assert(pContact);
  3120. if (pContact->pszHotmailHref)
  3121. CoTaskMemFree(pContact->pszHotmailHref);
  3122. if (pContact->pszModHotmail)
  3123. CoTaskMemFree(pContact->pszModHotmail);
  3124. if (pContact->pszHotmailId)
  3125. CoTaskMemFree(pContact->pszHotmailId);
  3126. if (pContact->pszaContactIds)
  3127. FreeMultiValueString(pContact->pszaContactIds);
  3128. if (pContact->pszaServerIds)
  3129. FreeMultiValueString(pContact->pszaServerIds);
  3130. if (pContact->pszaModtimes)
  3131. FreeMultiValueString(pContact->pszaModtimes);
  3132. if (pContact->pszaEmails)
  3133. FreeMultiValueString(pContact->pszaEmails);
  3134. if (pContact->lpEID)
  3135. LocalFree(pContact->lpEID);
  3136. LocalFree(pContact);
  3137. }
  3138. void ContactInfo_Clear(LPHTTPCONTACTINFO pContactInfo)
  3139. {
  3140. ZeroMemory(pContactInfo, sizeof(HTTPCONTACTINFO));
  3141. }
  3142. void ContactInfo_Free(LPHTTPCONTACTINFO pContactInfo)
  3143. {
  3144. DWORD i, dwSize = ARRAYSIZE(g_ContactInfoStructure);
  3145. if (!pContactInfo)
  3146. return;
  3147. for (i = 0; i < dwSize; i++)
  3148. {
  3149. if (CIS_STRING == CIS_GETTYPE(i))
  3150. SafeCoMemFree(CIS_GETSTRING(pContactInfo, i));
  3151. }
  3152. }
  3153. ULONG rgPropMap[] = {
  3154. PR_ENTRYID, //href
  3155. PR_ENTRYID, //id
  3156. PR_ENTRYID, //type
  3157. PR_ENTRYID, //modified
  3158. PR_DISPLAY_NAME,
  3159. PR_GIVEN_NAME,
  3160. PR_SURNAME,
  3161. PR_NICKNAME,
  3162. PR_EMAIL_ADDRESS,
  3163. PR_HOME_ADDRESS_STREET,
  3164. PR_HOME_ADDRESS_CITY,
  3165. PR_HOME_ADDRESS_STATE_OR_PROVINCE,
  3166. PR_HOME_ADDRESS_POSTAL_CODE,
  3167. PR_HOME_ADDRESS_COUNTRY,
  3168. PR_COMPANY_NAME,
  3169. PR_BUSINESS_ADDRESS_STREET,
  3170. PR_BUSINESS_ADDRESS_CITY,
  3171. PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
  3172. PR_BUSINESS_ADDRESS_POSTAL_CODE,
  3173. PR_BUSINESS_ADDRESS_COUNTRY,
  3174. PR_HOME_TELEPHONE_NUMBER,
  3175. PR_HOME_FAX_NUMBER,
  3176. PR_BUSINESS_TELEPHONE_NUMBER,
  3177. PR_BUSINESS_FAX_NUMBER,
  3178. PR_MOBILE_TELEPHONE_NUMBER,
  3179. PR_OTHER_TELEPHONE_NUMBER,
  3180. PR_BIRTHDAY,
  3181. PR_PAGER_TELEPHONE_NUMBER
  3182. };
  3183. DWORD ContactInfo_CountProperties(LPHTTPCONTACTINFO pContactInfo)
  3184. {
  3185. DWORD cProps = 0;
  3186. DWORD dwIndex, dwSize = ARRAYSIZE(g_ContactInfoStructure);
  3187. // skip href
  3188. for (dwIndex = 1; dwIndex < dwSize; dwIndex ++)
  3189. {
  3190. #ifdef HM_GROUP_SYNCING
  3191. // [PaulHi] Skip email name here if we are group syncing
  3192. if ( (pContactInfo->tyContact == HTTPMAIL_CT_GROUP) && (dwIndex == idcisEmail) )
  3193. continue;
  3194. #endif
  3195. if (CIS_STRING == CIS_GETTYPE(dwIndex) && CIS_GETSTRING(pContactInfo, dwIndex) && *(CIS_GETSTRING(pContactInfo, dwIndex)))
  3196. cProps++;
  3197. }
  3198. #ifdef HM_GROUP_SYNCING
  3199. // [PaulHi] Group syncing
  3200. if (pContactInfo->tyContact == HTTPMAIL_CT_GROUP)
  3201. {
  3202. LPTSTR lptszEmailName = ConvertAtoW( CIS_GETSTRING(pContactInfo, idcisEmail) );
  3203. if (lptszEmailName)
  3204. {
  3205. ULONG cContacts = 0;
  3206. ULONG cOneOffs = 0;
  3207. if ( SUCCEEDED(hrParseHMGroupEmail(lptszEmailName, NULL, &cContacts, NULL, &cOneOffs)) )
  3208. {
  3209. // One property for each set of mail user contacts or one-offs
  3210. cProps += (cContacts != 0) ? 1 : 0;
  3211. cProps += (cOneOffs != 0) ? 1 : 0;
  3212. }
  3213. LocalFreeAndNull(&lptszEmailName);
  3214. }
  3215. // A valid WAB DL must have a display name. HM groups only have nicknames so we
  3216. // need to reserve a PR_DISPLAY_NAME property.
  3217. // [PaulHi] Note, only do this if there is a valid Nickname field. The ContactInfo_SaveToWAB()
  3218. // function, which calls this function, is always in response to a server add or change.
  3219. // The pContactInfo fields reflect whatever was changed on the server. If there is a
  3220. // valid Nickname field then be sure we translate this to the WAB property DisplayName field.
  3221. // The WAB group display name corresponds to a HM group nickname.
  3222. if (pContactInfo->pszNickname)
  3223. ++cProps; // This gets translated to a DisplayName in ContactInfo_TranslateProps()
  3224. }
  3225. else
  3226. {
  3227. #endif
  3228. if (pContactInfo->pszEmail && *(pContactInfo->pszEmail))
  3229. cProps++; //need to make room for the PR_ADDRTYPE too
  3230. #ifdef HM_GROUP_SYNCING
  3231. }
  3232. #endif
  3233. return cProps;
  3234. }
  3235. HRESULT ContactInfo_SetProp(ULONG ulPropTag, LPTSTR pszValue, LPSPropValue lpPropArray, DWORD *pdwLoc)
  3236. {
  3237. ULONG ulLen;
  3238. SCODE sc;
  3239. UNALIGNED LPTSTR *lppszValues;
  3240. HRESULT hr;
  3241. LPSTR lp = NULL;
  3242. Assert(pszValue);
  3243. switch (PROP_TYPE(ulPropTag))
  3244. {
  3245. // BUGBUG currently only works for PT_TSTRING or PT_MV_TSTRING properties
  3246. case PT_TSTRING:
  3247. // Get the value for this attribute
  3248. if (ulLen = lstrlen(pszValue))
  3249. {
  3250. lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
  3251. lpPropArray[*pdwLoc].dwAlignPad = 0;
  3252. // Allocate more space for the data
  3253. ulLen = (ulLen + 1) * sizeof(TCHAR);
  3254. sc = MAPIAllocateMore(ulLen, lpPropArray, (LPVOID *)&(lpPropArray[*pdwLoc].Value.LPSZ));
  3255. if (sc)
  3256. goto error;
  3257. StrCpyN(lpPropArray[*pdwLoc].Value.LPSZ, pszValue, ulLen);
  3258. // If this is PR_EMAIL_ADDRESS, create a PR_ADDRTYPE entry as well
  3259. if (PR_EMAIL_ADDRESS == ulPropTag)
  3260. {
  3261. // Remember where the email value was, so we can add it to
  3262. // PR_CONTACT_EMAIL_ADDRESSES later
  3263. // ulPrimaryEmailIndex = *pdwLoc;
  3264. (*pdwLoc)++;
  3265. lpPropArray[*pdwLoc].ulPropTag = PR_ADDRTYPE;
  3266. lpPropArray[*pdwLoc].dwAlignPad = 0;
  3267. lpPropArray[*pdwLoc].Value.LPSZ = (LPTSTR)szSMTP;
  3268. }
  3269. (*pdwLoc)++;
  3270. }
  3271. break;
  3272. case PT_MV_TSTRING:
  3273. lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
  3274. lpPropArray[*pdwLoc].dwAlignPad = 0;
  3275. lpPropArray[*pdwLoc].Value.MVSZ.cValues = 1;
  3276. sc = MAPIAllocateMore((2)*sizeof(LPTSTR), lpPropArray,
  3277. (LPVOID *)&(lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ));
  3278. if (sc)
  3279. goto error;
  3280. lppszValues = lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ;
  3281. ulLen = sizeof(TCHAR)*(lstrlen(pszValue) + 1);
  3282. // Allocate more space for the email address and copy it.
  3283. sc = MAPIAllocateMore(ulLen, lpPropArray, (LPVOID *)&(lppszValues[0]));
  3284. if (sc)
  3285. goto error;
  3286. StrCpyN(lppszValues[0], pszValue, ulLen);
  3287. lppszValues[1] = NULL;
  3288. (*pdwLoc)++;
  3289. break;
  3290. case PT_SYSTIME:
  3291. lp = ConvertWtoA(pszValue);
  3292. hr = iso8601ToFileTime(lp, (FILETIME *) (&lpPropArray[*pdwLoc].Value.ft), TRUE, TRUE);
  3293. if (SUCCEEDED(hr))
  3294. {
  3295. lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
  3296. lpPropArray[*pdwLoc].dwAlignPad = 0;
  3297. (*pdwLoc)++;
  3298. }
  3299. LocalFreeAndNull(&lp);
  3300. break;
  3301. default:
  3302. return E_INVALIDARG;
  3303. }
  3304. return S_OK;
  3305. error:
  3306. return ResultFromScode(sc);
  3307. }
  3308. HRESULT ContactInfo_SetMVSZProp(ULONG ulPropTag, SLPSTRArray *pszaValue, LPSPropValue lpPropArray, DWORD *pdwLoc)
  3309. {
  3310. ULONG ulLen;
  3311. ULONG cbValue;
  3312. SCODE sc;
  3313. UNALIGNED LPTSTR *lppszValues;
  3314. HRESULT hr;
  3315. DWORD i;
  3316. LPTSTR lpVal = NULL;
  3317. Assert(pszaValue);
  3318. switch (PROP_TYPE(ulPropTag))
  3319. {
  3320. case PT_MV_TSTRING:
  3321. lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
  3322. lpPropArray[*pdwLoc].dwAlignPad = 0;
  3323. lpPropArray[*pdwLoc].Value.MVSZ.cValues = pszaValue->cValues;
  3324. sc = MAPIAllocateMore((pszaValue->cValues+1)*sizeof(LPTSTR), lpPropArray,
  3325. (LPVOID *)&(lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ));
  3326. if (sc)
  3327. goto error;
  3328. lppszValues = lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ;
  3329. for (i = 0; i < pszaValue->cValues; i ++)
  3330. {
  3331. ScAnsiToWCMore((LPALLOCATEMORE )(&MAPIAllocateMore), (LPVOID) lpPropArray, (LPSTR) (pszaValue->lppszA[i]), (LPWSTR *) (&(lppszValues[i])));
  3332. }
  3333. lppszValues[pszaValue->cValues] = NULL;
  3334. (*pdwLoc)++;
  3335. break;
  3336. default:
  3337. return E_INVALIDARG;
  3338. }
  3339. return S_OK;
  3340. error:
  3341. return ResultFromScode(sc);
  3342. }
  3343. HRESULT ContactInfo_TranslateProps(LPWABSYNC pWabSync, LPHTTPCONTACTINFO pContactInfo, LPWABCONTACTINFO pWabContactInfo, LPSPropValue lpaProps)
  3344. {
  3345. HRESULT hr = S_OK;
  3346. DWORD dwIndex, dwSize = ARRAYSIZE(rgPropMap);
  3347. DWORD dwPropIndex = 0, dwLoc = 0;
  3348. TCHAR szFullProfile[MAX_PATH];
  3349. DWORD dwStartIndex = 1;
  3350. // [PaulHi] Assemble the contact ID string
  3351. hr = hrMakeContactId(
  3352. szFullProfile,
  3353. MAX_PATH,
  3354. ((LPIAB)(pWabSync->m_pAB))->szProfileID,
  3355. pWabSync->m_pszAccountId,
  3356. pWabSync->m_szLoginName);
  3357. if (FAILED(hr))
  3358. return hr;
  3359. // fix up the other prop tag array structure to take into account the variable values
  3360. rgPropMap[1] = PR_WAB_HOTMAIL_SERVERIDS;
  3361. rgPropMap[3] = PR_WAB_HOTMAIL_MODTIMES;
  3362. if (pWabContactInfo && pWabContactInfo->pszaContactIds)
  3363. {
  3364. DWORD i;
  3365. BOOL fFound = FALSE;
  3366. // [PaulHi] 1/21/99 We are assuming that pszaModtimes and pszaServerIds
  3367. // pointers are valid too. Check this.
  3368. Assert(pWabContactInfo->pszaModtimes);
  3369. Assert(pWabContactInfo->pszaServerIds);
  3370. for (i = 0; i < pWabContactInfo->pszaContactIds->cValues; i++)
  3371. {
  3372. LPTSTR lpVal =
  3373. ConvertAtoW(pWabContactInfo->pszaContactIds->lppszA[i]);
  3374. if (lstrcmp(szFullProfile, lpVal) == 0)
  3375. {
  3376. LocalFreeAndNull(&lpVal);
  3377. fFound = TRUE;
  3378. break;
  3379. }
  3380. LocalFreeAndNull(&lpVal);
  3381. }
  3382. if (fFound)
  3383. {
  3384. SCODE sc;
  3385. ULONG cchSize = lstrlenA(CIS_GETSTRING(pContactInfo, idcisModified))+1;
  3386. // Allocate new memory for the string, sure the old memory we still be allocated but
  3387. // it will still be freed via the magic of MAPIAllocate* once the whole array gets freed.
  3388. sc = MAPIAllocateMore(sizeof(CHAR) * cchSize, pWabContactInfo->pszaModtimes,
  3389. (LPVOID *)&pWabContactInfo->pszaModtimes->lppszA[i]);
  3390. if (!sc)
  3391. {
  3392. // update the mod time
  3393. StrCpyNA(pWabContactInfo->pszaModtimes->lppszA[i], CIS_GETSTRING(pContactInfo, idcisModified), cchSize);
  3394. }
  3395. }
  3396. else
  3397. {
  3398. if (CIS_GETSTRING(pContactInfo, idcisId) && CIS_GETSTRING(pContactInfo, idcisModified))
  3399. {
  3400. // add this one to the list at the end
  3401. LPSTR lpValA =
  3402. ConvertWtoA(szFullProfile);
  3403. AppendToMultiValueString(pWabContactInfo->pszaContactIds, lpValA);
  3404. LocalFreeAndNull(&lpValA);
  3405. AppendToMultiValueString(pWabContactInfo->pszaServerIds, CIS_GETSTRING(pContactInfo, idcisId));
  3406. AppendToMultiValueString(pWabContactInfo->pszaModtimes, CIS_GETSTRING(pContactInfo, idcisModified));
  3407. }
  3408. }
  3409. ContactInfo_SetMVSZProp(PR_WAB_HOTMAIL_CONTACTIDS, pWabContactInfo->pszaContactIds, lpaProps, &dwLoc);
  3410. ContactInfo_SetMVSZProp(PR_WAB_HOTMAIL_SERVERIDS, pWabContactInfo->pszaServerIds, lpaProps, &dwLoc);
  3411. ContactInfo_SetMVSZProp(PR_WAB_HOTMAIL_MODTIMES, pWabContactInfo->pszaModtimes, lpaProps, &dwLoc);
  3412. dwStartIndex = 4;
  3413. }
  3414. else
  3415. hr = ContactInfo_SetProp(PR_WAB_HOTMAIL_CONTACTIDS, szFullProfile, lpaProps, &dwLoc);
  3416. #ifdef HM_GROUP_SYNCING
  3417. if (!pWabSync->m_fSyncGroups)
  3418. {
  3419. // [PaulHi] Normal contact email addresses
  3420. #endif
  3421. // Set the other e-mail address fields
  3422. if (pWabContactInfo && pWabContactInfo->pszaEmails && CIS_GETSTRING(pContactInfo, idcisEmail))
  3423. {
  3424. DWORD dw, cStrs;
  3425. BOOL fFound = FALSE;
  3426. cStrs = pWabContactInfo->pszaEmails->cValues;
  3427. for (dw = 0; dw < cStrs; dw ++)
  3428. {
  3429. if (lstrcmpiA(pWabContactInfo->pszaEmails->lppszA[dw], CIS_GETSTRING(pContactInfo, idcisEmail)) == 0)
  3430. {
  3431. pWabContactInfo->dwEmailIndex = dw;
  3432. fFound = TRUE;
  3433. break;
  3434. }
  3435. }
  3436. if (!fFound)
  3437. {
  3438. SetMultiValueStringValue(pWabContactInfo->pszaEmails, CIS_GETSTRING(pContactInfo, idcisEmail), pWabContactInfo->dwEmailIndex);
  3439. }
  3440. ContactInfo_SetMVSZProp(PR_CONTACT_EMAIL_ADDRESSES, pWabContactInfo->pszaEmails, lpaProps, &dwLoc);
  3441. //set the index
  3442. lpaProps[dwLoc].ulPropTag = PR_CONTACT_DEFAULT_ADDRESS_INDEX;
  3443. lpaProps[dwLoc].dwAlignPad = 0;
  3444. lpaProps[dwLoc].Value.ul = pWabContactInfo->dwEmailIndex;
  3445. dwLoc ++;
  3446. }
  3447. #ifdef HM_GROUP_SYNCING
  3448. }
  3449. else
  3450. {
  3451. // [PaulHi] Implement group syncing. If we are synchronizing groups then the HM contact
  3452. // email string is a series of contact nicknames and one-off email names. Parse this
  3453. // string and add each group contact.
  3454. LPTSTR lptszEmailName = ConvertAtoW( CIS_GETSTRING(pContactInfo, idcisEmail) );
  3455. if (lptszEmailName)
  3456. {
  3457. LPTSTR * atszContacts = NULL;
  3458. LPTSTR * atszOneOffs = NULL;
  3459. ULONG cContacts = 0;
  3460. ULONG cOneOffs = 0;
  3461. ULONG ul;
  3462. // The atszContacts and atszOneOffs arrays are just pointers into the lptszEmailName
  3463. // buffer. So these arrays are only valid as long as lptszEmailName is valid.
  3464. hr = hrParseHMGroupEmail(lptszEmailName, &atszContacts, &cContacts, &atszOneOffs, &cOneOffs);
  3465. if (FAILED(hr))
  3466. {
  3467. LocalFreeAndNull(&lptszEmailName);
  3468. goto out;
  3469. }
  3470. // Add multi-value property tags as appropriate
  3471. if (cContacts)
  3472. hrCreateGroupMVBin(pWabSync, PR_WAB_DL_ENTRIES, atszContacts, cContacts, lpaProps, &dwLoc);
  3473. if (cOneOffs)
  3474. hrCreateGroupMVBin(pWabSync, PR_WAB_DL_ONEOFFS, atszOneOffs, cOneOffs, lpaProps, &dwLoc);
  3475. // cleanup
  3476. LocalFreeAndNull((LPVOID *)&atszContacts);
  3477. LocalFreeAndNull((LPVOID *)&atszOneOffs);
  3478. LocalFreeAndNull(&lptszEmailName);
  3479. }
  3480. }
  3481. #endif
  3482. // skip the first ones since we just did them
  3483. for (dwIndex = dwStartIndex; dwIndex < dwSize; dwIndex ++)
  3484. {
  3485. if (CIS_STRING == CIS_GETTYPE(dwIndex) && CIS_GETSTRING(pContactInfo, dwIndex))
  3486. {
  3487. LPTSTR lptsz = ConvertAtoW(CIS_GETSTRING(pContactInfo, dwIndex));
  3488. #ifdef HM_GROUP_SYNCING
  3489. // [PaulHi] Special group syncing logic
  3490. if (pContactInfo->tyContact == HTTPMAIL_CT_GROUP)
  3491. {
  3492. // Don't add email name for groups
  3493. if (dwIndex == idcisEmail)
  3494. continue;
  3495. // Copy the nickname to the display name property. All WAB DL items
  3496. // MUST have a PR_DISPLAY_NAME property. Since HM groups only contain
  3497. // a nickname use the nickname as the display name.
  3498. if (dwIndex == idcisNickName)
  3499. {
  3500. hr = ContactInfo_SetProp(PR_DISPLAY_NAME, lptsz, lpaProps, &dwLoc);
  3501. if (FAILED(hr))
  3502. {
  3503. LocalFreeAndNull(&lptsz);
  3504. break;
  3505. }
  3506. }
  3507. }
  3508. #endif
  3509. hr = ContactInfo_SetProp(rgPropMap[dwIndex], lptsz, lpaProps, &dwLoc);
  3510. LocalFreeAndNull(&lptsz);
  3511. if (FAILED(hr))
  3512. break;
  3513. }
  3514. }
  3515. #ifdef HM_GROUP_SYNCING
  3516. out:
  3517. #endif
  3518. return hr;
  3519. }
  3520. static LONG _FindPropTag(ULONG ulPropTag)
  3521. {
  3522. LONG lIndex, lSize = ARRAYSIZE(rgPropMap);
  3523. // skip href
  3524. for (lIndex = 1; lIndex < lSize; lIndex ++)
  3525. {
  3526. if (rgPropMap[lIndex] == ulPropTag)
  3527. return lIndex;
  3528. }
  3529. return -1;
  3530. }
  3531. HRESULT ContactInfo_DetermineDeleteProps(LPHTTPCONTACTINFO pContactInfo, LPSPropTagArray prgRemoveProps)
  3532. {
  3533. LPSTR *pProps = (LPSTR *)pContactInfo;
  3534. LONG lSize = ARRAYSIZE(rgPropMap);
  3535. LONG dwIndex;
  3536. prgRemoveProps->cValues = 0;
  3537. for (dwIndex = CIS_FIRST_DATA_FIELD; dwIndex < lSize; dwIndex ++)
  3538. {
  3539. if (CIS_STRING == CIS_GETTYPE(dwIndex) && CIS_GETSTRING(pContactInfo, dwIndex) && *(CIS_GETSTRING(pContactInfo, dwIndex)) == 0)
  3540. {
  3541. prgRemoveProps->aulPropTag[prgRemoveProps->cValues++] = rgPropMap[dwIndex];
  3542. }
  3543. }
  3544. return S_OK;
  3545. }
  3546. HRESULT ContactInfo_PopulateProps(
  3547. LPWABSYNC pWabSync,
  3548. LPHTTPCONTACTINFO pContactInfo,
  3549. LPWABCONTACTINFO pWabContactInfo,
  3550. LPSPropValue lpaProps,
  3551. ULONG ulcProps,
  3552. ULONG ulObjectType)
  3553. {
  3554. HRESULT hr = S_OK;
  3555. LONG lSize = ARRAYSIZE(rgPropMap);
  3556. DWORD dwPropIndex = 0, dwLoc = 0;
  3557. ULONG i, ulPropTag;
  3558. LONG lIndex;
  3559. char szBuffer[255];
  3560. ULONG ulIndServerIDs = -1, ulIndContactIDs = -1, ulIndModtimes = -1, ulIndEmails = -1;
  3561. LPSTR lpszA = NULL;
  3562. // fix up the other prop tag array structure to take into account the variable values
  3563. // @todo [PaulHi] Instead of using explict numbers create an enum for the array
  3564. // indices so we can remain consistent.
  3565. rgPropMap[1] = PR_WAB_HOTMAIL_SERVERIDS;
  3566. rgPropMap[3] = PR_WAB_HOTMAIL_MODTIMES;
  3567. ZeroMemory(pContactInfo, sizeof(HTTPCONTACTINFO));
  3568. #ifdef HM_GROUP_SYNCING
  3569. // [PaulHi] Set the contact type flag (mail user or group contact)
  3570. if (ulObjectType == MAPI_DISTLIST)
  3571. {
  3572. // group contact
  3573. pContactInfo->tyContact = HTTPMAIL_CT_GROUP;
  3574. pWabContactInfo->ulContactType = HTTPMAIL_CT_GROUP;
  3575. }
  3576. else
  3577. {
  3578. // mail user contact
  3579. pContactInfo->tyContact = HTTPMAIL_CT_CONTACT;
  3580. pWabContactInfo->ulContactType = HTTPMAIL_CT_CONTACT;
  3581. }
  3582. #endif
  3583. for (i = 0; i < ulcProps; i++)
  3584. {
  3585. ulPropTag = lpaProps[i].ulPropTag;
  3586. lIndex = _FindPropTag(ulPropTag);
  3587. #ifdef HM_GROUP_SYNCING
  3588. if (lIndex >= 0 && lIndex != 2) // The index==2 array position is tyContact, which we set above.
  3589. #else
  3590. if (lIndex >= 0)
  3591. #endif
  3592. {
  3593. Assert(lIndex < lSize);
  3594. SafeCoMemFree(CIS_GETSTRING(pContactInfo, lIndex));
  3595. switch (PROP_TYPE(ulPropTag))
  3596. {
  3597. case PT_TSTRING:
  3598. Assert(CIS_STRING == CIS_GETTYPE(lIndex));
  3599. if (CIS_GETSTRING(pContactInfo, lIndex))
  3600. SafeCoMemFree(CIS_GETSTRING(pContactInfo, lIndex));
  3601. lpszA =
  3602. ConvertWtoA(lpaProps[i].Value.LPSZ);
  3603. CIS_GETSTRING(pContactInfo, lIndex) = _StrDup(lpszA);
  3604. LocalFreeAndNull(&lpszA);
  3605. if (!CIS_GETSTRING(pContactInfo, lIndex))
  3606. {
  3607. hr = E_OUTOFMEMORY;
  3608. goto exit;
  3609. }
  3610. break;
  3611. case PT_SYSTIME:
  3612. Assert(CIS_STRING == CIS_GETTYPE(lIndex));
  3613. if (SUCCEEDED(FileTimeToiso8601((FILETIME *) (&lpaProps[i].Value.ft), szBuffer)))
  3614. {
  3615. CIS_GETSTRING(pContactInfo, lIndex) = _StrDup(szBuffer);
  3616. if (!CIS_GETSTRING(pContactInfo, lIndex))
  3617. {
  3618. hr = E_OUTOFMEMORY;
  3619. goto exit;
  3620. }
  3621. }
  3622. else
  3623. {
  3624. hr = E_INVALIDARG;
  3625. goto exit;
  3626. }
  3627. if (PR_BIRTHDAY == ulPropTag && CIS_GETSTRING(pContactInfo, lIndex))
  3628. {
  3629. // fix it up to be a hotmail formatted date
  3630. _FixHotmailDate(CIS_GETSTRING(pContactInfo, lIndex));
  3631. }
  3632. break;
  3633. case PT_MV_TSTRING:
  3634. if (ulPropTag == PR_WAB_HOTMAIL_SERVERIDS)
  3635. ulIndServerIDs = i;
  3636. else if (ulPropTag == PR_WAB_HOTMAIL_MODTIMES)
  3637. ulIndModtimes = i;
  3638. break;
  3639. }
  3640. }
  3641. else
  3642. {
  3643. if (ulPropTag == PR_WAB_HOTMAIL_CONTACTIDS)
  3644. ulIndContactIDs = i;
  3645. else if (ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
  3646. ulIndEmails = i;
  3647. else if (ulPropTag == PR_CONTACT_DEFAULT_ADDRESS_INDEX)
  3648. pWabContactInfo->dwEmailIndex = lpaProps[i].Value.ul;
  3649. #ifdef HM_GROUP_SYNCING
  3650. else if ( (ulObjectType == MAPI_DISTLIST) &&
  3651. (ulPropTag == PR_WAB_DL_ENTRIES) || (ulPropTag == PR_WAB_DL_ONEOFFS) )
  3652. {
  3653. LPSTR lpszNewEmailName = CIS_GETSTRING(pContactInfo, idcisEmail);
  3654. hr = hrAppendGroupContact(pWabSync,
  3655. ulPropTag,
  3656. &lpaProps[i],
  3657. &lpszNewEmailName);
  3658. CIS_GETSTRING(pContactInfo, idcisEmail) = lpszNewEmailName;
  3659. if (FAILED(hr))
  3660. goto exit;
  3661. }
  3662. #endif
  3663. }
  3664. }
  3665. #ifdef HM_GROUP_SYNCING
  3666. // [PaulHi] Group syncing. HM group contact information consists only of an email and nickname.
  3667. // The WAB group display name becomes the HM group nickname.
  3668. if (ulObjectType == MAPI_DISTLIST)
  3669. {
  3670. LPSTR lpszDisplayName = CIS_GETSTRING(pContactInfo, idcisDisplayName);
  3671. LPSTR lpszNickName = CIS_GETSTRING(pContactInfo, idcisNickName);
  3672. if (lpszDisplayName)
  3673. {
  3674. if (lpszNickName)
  3675. CoTaskMemFree(lpszNickName);
  3676. CIS_GETSTRING(pContactInfo, idcisDisplayName) = NULL;
  3677. // [PaulHi]
  3678. // A HM group nickname cannot contain certain characters. So we remove all
  3679. // invalid characters in the name string. This change will be reflected
  3680. // in the WAB group name too (yuck).
  3681. hrStripInvalidChars(lpszDisplayName);
  3682. CIS_GETSTRING(pContactInfo,idcisNickName) = lpszDisplayName;
  3683. }
  3684. }
  3685. else
  3686. #endif
  3687. {
  3688. // Likewise email contact nicknames cannot contain certain characters or
  3689. // the post to HM server will fail.
  3690. LPSTR lpszNickName = CIS_GETSTRING(pContactInfo, idcisNickName);
  3691. if (lpszNickName)
  3692. hrStripInvalidChars(lpszNickName);
  3693. }
  3694. if (ulIndEmails != -1)
  3695. {
  3696. if (pWabContactInfo->pszaEmails)
  3697. FreeMultiValueString(pWabContactInfo->pszaEmails);
  3698. hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndEmails].Value.MVSZ), &pWabContactInfo->pszaEmails);
  3699. }
  3700. // If we have the indexes to all of the multivalues that we care about,
  3701. // try to get the appropriate values for the current identity.
  3702. if (ulIndContactIDs != -1 && ulIndModtimes != -1 && ulIndServerIDs != -1)
  3703. {
  3704. ULONG ulMVIndex = -1;
  3705. UNALIGNED LPTSTR *lppszValues;
  3706. TCHAR szFullProfile[MAX_PATH];
  3707. // [PaulHi] Assemble the contact ID string
  3708. hr = hrMakeContactId(
  3709. szFullProfile,
  3710. MAX_PATH,
  3711. ((LPIAB)(pWabSync->m_pAB))->szProfileID,
  3712. pWabSync->m_pszAccountId,
  3713. pWabSync->m_szLoginName);
  3714. if (FAILED(hr))
  3715. goto exit;
  3716. // sanity check, all three multi values must contain the same number
  3717. // of values. If not they are out of sync and not to be trusted.
  3718. if (lpaProps[ulIndContactIDs].Value.MVSZ.cValues != lpaProps[ulIndModtimes].Value.MVSZ.cValues ||
  3719. lpaProps[ulIndModtimes].Value.MVSZ.cValues != lpaProps[ulIndServerIDs].Value.MVSZ.cValues)
  3720. {
  3721. Assert(FALSE);
  3722. goto exit;
  3723. }
  3724. if (pWabContactInfo->pszaContactIds)
  3725. FreeMultiValueString(pWabContactInfo->pszaContactIds);
  3726. hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndContactIDs].Value.MVSZ), &pWabContactInfo->pszaContactIds);
  3727. if (pWabContactInfo->pszaServerIds)
  3728. FreeMultiValueString(pWabContactInfo->pszaServerIds);
  3729. hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndServerIDs].Value.MVSZ), &pWabContactInfo->pszaServerIds);
  3730. if (pWabContactInfo->pszaModtimes)
  3731. FreeMultiValueString(pWabContactInfo->pszaModtimes);
  3732. hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndModtimes].Value.MVSZ), &pWabContactInfo->pszaModtimes);
  3733. if (PROP_TYPE(lpaProps[ulIndContactIDs].ulPropTag) == PT_MV_TSTRING)
  3734. {
  3735. lppszValues = lpaProps[ulIndContactIDs].Value.MVSZ.LPPSZ;
  3736. // find the index for this identity
  3737. for (i = 0; i < lpaProps[ulIndContactIDs].Value.MVSZ.cValues; i++)
  3738. {
  3739. if (lstrcmp(szFullProfile, lppszValues[i]) == 0)
  3740. {
  3741. ulMVIndex = i;
  3742. break;
  3743. }
  3744. }
  3745. if (ulMVIndex != -1)
  3746. {
  3747. ULONG ulLen;
  3748. LPSTR lpVal = NULL;
  3749. lpVal = ConvertWtoA(lpaProps[ulIndServerIDs].Value.MVSZ.LPPSZ[ulMVIndex]);
  3750. //Copy the values for this identity to the structure
  3751. pContactInfo->pszId = _StrDup(lpVal);
  3752. LocalFreeAndNull(&lpVal);
  3753. if (!pContactInfo->pszId)
  3754. {
  3755. hr = E_OUTOFMEMORY;
  3756. goto exit;
  3757. }
  3758. lpVal = ConvertWtoA(lpaProps[ulIndModtimes].Value.MVSZ.LPPSZ[ulMVIndex]);
  3759. pContactInfo->pszModified = _StrDup(lpVal);
  3760. LocalFreeAndNull(&lpVal);
  3761. if (!pContactInfo->pszModified)
  3762. {
  3763. hr = E_OUTOFMEMORY;
  3764. goto exit;
  3765. }
  3766. }
  3767. }
  3768. }
  3769. exit:
  3770. if (FAILED(hr))
  3771. {
  3772. ContactInfo_Free(pContactInfo);
  3773. }
  3774. return hr;
  3775. }
  3776. HRESULT ContactInfo_SaveToWAB(LPWABSYNC pWabSync,
  3777. LPHTTPCONTACTINFO pContactInfo,
  3778. LPWABCONTACTINFO pWabContactInfo,
  3779. LPENTRYID lpEntryID,
  3780. ULONG cbEntryID,
  3781. BOOL fDeleteProps)
  3782. {
  3783. LPENTRYID pEntryID = NULL;
  3784. ULONG cbLocEntryID = 0;
  3785. HRESULT hr;
  3786. LPMAILUSER lpMailUser = NULL;
  3787. LPSPropValue lpaProps = NULL;
  3788. ULONG ulcProps = 0;
  3789. ULONG ulObjectType;
  3790. SCODE sc;
  3791. SBinary sBinary;
  3792. ULONG uli;
  3793. Assert(pWabSync);
  3794. Assert(pContactInfo);
  3795. Assert(pWabSync->m_pAB);
  3796. if (HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->GetPAB(pWabSync->m_pAB, &sBinary.cb, (LPENTRYID*)&sBinary.lpb)))
  3797. {
  3798. DebugPrintError(( TEXT("GetPAB Failed\n")));
  3799. goto out;
  3800. }
  3801. Assert(sBinary.lpb);
  3802. if (lpEntryID)
  3803. {
  3804. if (HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, // size of EntryID to open
  3805. lpEntryID, // EntryID to open
  3806. NULL, // interface
  3807. MAPI_MODIFY, // flags
  3808. &ulObjectType,
  3809. (LPUNKNOWN *) &lpMailUser)))
  3810. {
  3811. DebugPrintError(( TEXT("OpenEntry Failed\n")));
  3812. goto out;
  3813. }
  3814. }
  3815. else
  3816. {
  3817. #ifdef HM_GROUP_SYNCING
  3818. ULONG ulObjectType = (pWabSync->m_fSyncGroups) ? MAPI_DISTLIST : MAPI_MAILUSER;
  3819. #else
  3820. ULONG ulObjectType = MAPI_MAILUSER;
  3821. #endif
  3822. fDeleteProps = FALSE;
  3823. if (HR_FAILED(hr = HrCreateNewObject(pWabSync->m_pAB,
  3824. &sBinary,
  3825. ulObjectType,
  3826. CREATE_CHECK_DUP_STRICT,
  3827. (LPMAPIPROP *) &lpMailUser)))
  3828. {
  3829. DebugPrintError(( TEXT("HRCreateNewObject Failed\n")));
  3830. goto out;
  3831. }
  3832. }
  3833. Assert(lpMailUser);
  3834. //Add one for the contact's identity id
  3835. ulcProps = ContactInfo_CountProperties(pContactInfo) + 1;
  3836. // make room for PR_CONTACT_DEFAULT_ADDRESS_INDEX and PR_CONTACT_EMAIL_ADDRESSES
  3837. // if we have the data to put in them
  3838. if (pWabContactInfo && pWabContactInfo->pszaEmails && CIS_GETSTRING(pContactInfo, idcisEmail))
  3839. ulcProps += 2;
  3840. // [PaulHi] @review 1/21/99
  3841. // make room for PR_WAB_HOTMAIL_SERVERIDS and PR_WAB_HOTMAIL_MODTIMES
  3842. // This part is ugly - only if these have not already been accounted for in pContactInfo
  3843. if (pWabContactInfo && pWabContactInfo->pszaContactIds)
  3844. {
  3845. if (!pContactInfo->pszModified)
  3846. ulcProps += 1;
  3847. if (!pContactInfo->pszId)
  3848. ulcProps += 1;
  3849. }
  3850. // Allocate a new buffer for the MAPI property array.
  3851. sc = MAPIAllocateBuffer(ulcProps * sizeof(SPropValue),
  3852. (LPVOID *)&lpaProps);
  3853. if (sc)
  3854. {
  3855. hr = ResultFromScode(sc);
  3856. goto out;
  3857. }
  3858. // Initialize the Property array
  3859. ZeroMemory(lpaProps, (ulcProps*sizeof(SPropValue)));
  3860. for (uli=0; uli<ulcProps; uli++)
  3861. lpaProps[uli].ulPropTag = PR_NULL;
  3862. if(HR_FAILED(hr = ContactInfo_TranslateProps(pWabSync, pContactInfo, pWabContactInfo, lpaProps)))
  3863. {
  3864. DebugPrintError(( TEXT("ContactInfo_TranslateProps Failed\n")));
  3865. goto out;
  3866. }
  3867. // Set the old guys props on the new guy - note that this overwrites any common props on
  3868. // potential duplicates when calling savechanges
  3869. if(HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, ulcProps, lpaProps, NULL)))
  3870. {
  3871. DebugPrintError(( TEXT("SetProps Failed\n")));
  3872. goto out;
  3873. }
  3874. if (fDeleteProps)
  3875. {
  3876. SizedSPropTagArray(ARRAYSIZE(rgPropMap), rgRemoveProps) = {0};
  3877. ContactInfo_DetermineDeleteProps(pContactInfo, (LPSPropTagArray)&rgRemoveProps);
  3878. if (rgRemoveProps.cValues > 0)
  3879. hr = lpMailUser->lpVtbl->DeleteProps(lpMailUser, (LPSPropTagArray)&rgRemoveProps, NULL);
  3880. }
  3881. // SaveChanges
  3882. if(HR_FAILED(hr = lpMailUser->lpVtbl->SaveChanges(lpMailUser, KEEP_OPEN_READONLY)))
  3883. {
  3884. DebugPrintError(( TEXT("SaveChanges Failed\n")));
  3885. if (!lpEntryID && HR_FAILED(hr = ContactInfo_BlendNewContact(pWabSync, pContactInfo)))
  3886. DebugPrintError(( TEXT("ContactInfo_BlendNewContact Failed\n")));
  3887. goto out;
  3888. }
  3889. out:
  3890. if (sBinary.lpb)
  3891. MAPIFreeBuffer(sBinary.lpb);
  3892. if (lpMailUser)
  3893. UlRelease(lpMailUser);
  3894. if (lpaProps)
  3895. MAPIFreeBuffer(lpaProps);
  3896. return hr;
  3897. }
  3898. HRESULT ContactInfo_BlendNewContact(LPWABSYNC pWabSync,
  3899. LPHTTPCONTACTINFO pContactInfo)
  3900. {
  3901. LPSPropValue lpaProps = NULL;
  3902. SizedADRLIST(1, rAdrList) = {0};
  3903. SCODE sc;
  3904. HRESULT hr = S_OK;
  3905. DWORD cbValue;
  3906. DWORD cCount = 0;
  3907. ULONG j = 0;
  3908. if (pContactInfo->pszDisplayName)
  3909. cCount++;
  3910. if (pContactInfo->pszEmail)
  3911. cCount++;
  3912. if (!cCount)
  3913. return MAPI_E_INVALID_PARAMETER;
  3914. // Allocate a new buffer for the MAPI property array.
  3915. sc = MAPIAllocateBuffer(cCount * sizeof(SPropValue),
  3916. (LPVOID *)&lpaProps);
  3917. if (sc)
  3918. {
  3919. hr = ResultFromScode(sc);
  3920. goto out;
  3921. }
  3922. cCount = 0;
  3923. if (pContactInfo->pszDisplayName)
  3924. {
  3925. lpaProps[cCount].ulPropTag = PR_DISPLAY_NAME;
  3926. lpaProps[cCount].dwAlignPad = 0;
  3927. if(sc = ScAnsiToWCMore((LPALLOCATEMORE )(&MAPIAllocateMore),(LPVOID) lpaProps, (LPSTR) pContactInfo->pszDisplayName, (LPWSTR *) (&(lpaProps[cCount].Value.LPSZ))))
  3928. goto out;
  3929. cCount++;
  3930. }
  3931. if (pContactInfo->pszEmail)
  3932. {
  3933. lpaProps[cCount].ulPropTag = PR_EMAIL_ADDRESS;
  3934. lpaProps[cCount].dwAlignPad = 0;
  3935. if(sc = ScAnsiToWCMore((LPALLOCATEMORE )(&MAPIAllocateMore),(LPVOID) lpaProps, (LPSTR) pContactInfo->pszEmail,(LPWSTR *) (&(lpaProps[cCount].Value.LPSZ))))
  3936. goto out;
  3937. cCount++;
  3938. }
  3939. rAdrList.cEntries = 1;
  3940. rAdrList.aEntries[0].cValues = cCount;
  3941. rAdrList.aEntries[0].rgPropVals = lpaProps;
  3942. hr = pWabSync->m_pAB->lpVtbl->ResolveName(pWabSync->m_pAB, (ULONG_PTR)pWabSync->m_hWnd,
  3943. WAB_RESOLVE_LOCAL_ONLY | WAB_RESOLVE_USE_CURRENT_PROFILE,
  3944. TEXT(""), (LPADRLIST)(&rAdrList));
  3945. lpaProps = NULL; //it was freed in ResolveName (!)
  3946. if (HR_FAILED(hr))
  3947. goto out;
  3948. for(j=0; j<rAdrList.aEntries[0].cValues; j++)
  3949. {
  3950. if(rAdrList.aEntries[0].rgPropVals[j].ulPropTag == PR_ENTRYID &&
  3951. rAdrList.aEntries[0].rgPropVals[j].Value.bin.lpb)
  3952. {
  3953. hr = ContactInfo_SaveToWAB(pWabSync,
  3954. pContactInfo,
  3955. NULL,
  3956. (LPENTRYID)rAdrList.aEntries[0].rgPropVals[j].Value.bin.lpb,
  3957. rAdrList.aEntries[0].rgPropVals[j].Value.bin.cb,
  3958. FALSE);
  3959. break;
  3960. }
  3961. }
  3962. for (j = 0; j < rAdrList.cEntries; j++)
  3963. MAPIFreeBuffer(rAdrList.aEntries[j].rgPropVals);
  3964. out:
  3965. if (lpaProps)
  3966. MAPIFreeBuffer(lpaProps);
  3967. return hr;
  3968. }
  3969. void UpdateSynchronizeMenus(HMENU hMenu, LPIAB lpIAB)
  3970. {
  3971. DWORD cItems, dwIndex;
  3972. MENUITEMINFO mii;
  3973. TCHAR szLogoffString[255];
  3974. TCHAR szRes[255];
  3975. if (!IsHTTPMailEnabled(lpIAB))
  3976. {
  3977. // loop through the other menu items looking for logoff
  3978. cItems = GetMenuItemCount(hMenu);
  3979. mii.cbSize = sizeof(MENUITEMINFO);
  3980. mii.fMask = MIIM_ID;
  3981. for (dwIndex = cItems; dwIndex > 0; --dwIndex)
  3982. {
  3983. GetMenuItemInfo(hMenu, dwIndex, TRUE, &mii);
  3984. // if this is the logoff item, delete it and the separator
  3985. // line that follows
  3986. if (mii.wID == IDM_TOOLS_SYNCHRONIZE_NOW)
  3987. {
  3988. DeleteMenu(hMenu, dwIndex - 1, MF_BYPOSITION);
  3989. DeleteMenu(hMenu, IDM_TOOLS_SYNCHRONIZE_NOW, MF_BYCOMMAND);
  3990. break;
  3991. }
  3992. }
  3993. }
  3994. else
  3995. {
  3996. // if there are no http mail accounts, disable the menu item
  3997. if (CountHTTPMailAccounts(lpIAB) == 0)
  3998. EnableMenuItem(hMenu, IDM_TOOLS_SYNCHRONIZE_NOW, MF_BYCOMMAND | MF_GRAYED);
  3999. }
  4000. }
  4001. HRESULT ContactInfo_LoadFromWAB(LPWABSYNC pWabSync,
  4002. LPHTTPCONTACTINFO pContactInfo,
  4003. LPWABCONTACTINFO pWabContact,
  4004. LPENTRYID lpEntryID,
  4005. ULONG cbEntryID)
  4006. {
  4007. LPENTRYID pEntryID = NULL;
  4008. ULONG cbLocEntryID = 0;
  4009. HRESULT hr;
  4010. LPMAILUSER lpMailUser = NULL;
  4011. LPSPropValue lpaProps = NULL;
  4012. ULONG ulcProps = 0;
  4013. ULONG ulObjectType;
  4014. SCODE sc;
  4015. Assert(pWabSync);
  4016. Assert(pContactInfo);
  4017. Assert(lpEntryID);
  4018. Assert(pWabSync->m_pAB);
  4019. if(HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, lpEntryID, NULL, 0, &ulObjectType, (LPUNKNOWN *) &lpMailUser)))
  4020. {
  4021. DebugPrintError(( TEXT("OpenEntry Failed\n")));
  4022. goto out;
  4023. }
  4024. if(HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, (LPSPropTagArray)(&ptaEidCSync), MAPI_UNICODE,
  4025. &ulcProps, &lpaProps)))
  4026. {
  4027. DebugPrintError(( TEXT("GetProps Failed\n")));
  4028. goto out;
  4029. }
  4030. if (HR_FAILED(hr = ContactInfo_PopulateProps(pWabSync, pContactInfo, pWabContact, lpaProps, ulcProps, ulObjectType)))
  4031. {
  4032. DebugPrintError(( TEXT("ContactInfo_PopulateProps Failed\n")));
  4033. goto out;
  4034. }
  4035. #ifdef HM_GROUP_SYNCING
  4036. // [PaulHi] Group sync. Don't break out a group display name
  4037. if ( (pContactInfo->tyContact == HTTPMAIL_CT_CONTACT) && pContactInfo->pszDisplayName &&
  4038. (!pContactInfo->pszGivenName || !pContactInfo->pszSurname) )
  4039. #else
  4040. if ( pContactInfo->pszDisplayName && (!pContactInfo->pszGivenName || !pContactInfo->pszSurname) )
  4041. #endif
  4042. {
  4043. LPVOID pBuffer;
  4044. LPTSTR pszFirstName = NULL, pszLastName = NULL;
  4045. LPTSTR lpName =
  4046. ConvertAtoW(pContactInfo->pszDisplayName);
  4047. if (ParseDisplayName(lpName, &pszFirstName, &pszLastName, NULL, &pBuffer))
  4048. {
  4049. LPSTR lp = NULL;
  4050. if (pszFirstName && !pContactInfo->pszGivenName)
  4051. {
  4052. lp = ConvertWtoA(pszFirstName);
  4053. pContactInfo->pszGivenName = _StrDup(lp);
  4054. LocalFreeAndNull(&lp);
  4055. }
  4056. if (pszLastName && !pContactInfo->pszSurname)
  4057. {
  4058. lp = ConvertWtoA(pszLastName);
  4059. pContactInfo->pszSurname = _StrDup(lp);
  4060. LocalFreeAndNull(&lp);
  4061. }
  4062. LocalFree(pBuffer);
  4063. }
  4064. LocalFreeAndNull(&lpName);
  4065. }
  4066. out:
  4067. if (lpMailUser)
  4068. UlRelease(lpMailUser);
  4069. if (lpaProps)
  4070. MAPIFreeBuffer(lpaProps);
  4071. return hr;
  4072. }
  4073. static BOOL _IsLegitNicknameChar(TCHAR ch)
  4074. {
  4075. if (ch >= 'A' && ch <= 'Z')
  4076. return TRUE;
  4077. if (ch >= 'a' && ch <= 'z')
  4078. return TRUE;
  4079. if (ch >= '0' && ch <= '9')
  4080. return TRUE;
  4081. if (ch == '-' || ch == '_')
  4082. return TRUE;
  4083. return FALSE;
  4084. }
  4085. HRESULT ContactInfo_GenerateNickname(LPHTTPCONTACTINFO pContactInfo)
  4086. {
  4087. HRESULT hr = S_OK;
  4088. LPSTR pszStr;
  4089. if (NULL == pContactInfo->pszNickname)
  4090. {
  4091. if (pContactInfo->pszEmail)
  4092. {
  4093. pContactInfo->pszNickname = _StrDup(pContactInfo->pszEmail);
  4094. }
  4095. else if (pContactInfo->pszDisplayName)
  4096. {
  4097. pContactInfo->pszNickname = _StrDup(pContactInfo->pszDisplayName);
  4098. }
  4099. else
  4100. {
  4101. char szNickname[25], szFmt[25];
  4102. LoadStringA(hinstMapiX, idsNicknameFmt, szFmt, sizeof(szFmt));
  4103. if (*szFmt == 0)
  4104. StrCpyNA(szFmt, "Nickname%d", ARRAYSIZE(szFmt));
  4105. wnsprintfA(szNickname, ARRAYSIZE(szNickname), szFmt, ((DWORD)GetTickCount() & 0x0000FFFF));
  4106. pContactInfo->pszNickname = _StrDup(szNickname);
  4107. }
  4108. if (!pContactInfo->pszNickname)
  4109. return E_OUTOFMEMORY;
  4110. pszStr = pContactInfo->pszNickname;
  4111. while (*pszStr)
  4112. {
  4113. // e-mail address should be unique enough...(?)
  4114. if (*pszStr == '@')
  4115. {
  4116. *pszStr = 0;
  4117. break;
  4118. }
  4119. if (!_IsLegitNicknameChar(*pszStr))
  4120. *pszStr = '_';
  4121. pszStr++;
  4122. }
  4123. }
  4124. else
  4125. {
  4126. char szNickname[25], szFmt[25];
  4127. SafeCoMemFree(pContactInfo->pszNickname);
  4128. LoadStringA(hinstMapiX, idsNicknameFmt, szFmt, sizeof(szFmt));
  4129. if (*szFmt == 0)
  4130. StrCpyNA(szFmt, "Nickname%d", ARRAYSIZE(szFmt));
  4131. wnsprintfA(szNickname, ARRAYSIZE(szNickname), szFmt, ((DWORD)GetTickCount() & 0x0000FFFF));
  4132. pContactInfo->pszNickname = _StrDup(szNickname);
  4133. }
  4134. return hr;
  4135. }
  4136. BOOL ContactInfo_Match(LPHTTPCONTACTINFO pciServer, LPHTTPCONTACTINFO pciClient)
  4137. {
  4138. LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
  4139. BOOL fResult = TRUE;
  4140. if (!pciServer)
  4141. return FALSE;
  4142. if (!pciClient)
  4143. return FALSE;
  4144. for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
  4145. {
  4146. if (CIS_GETSTRING(pciServer, i) && CIS_GETSTRING(pciClient, i))
  4147. {
  4148. if (lstrcmpA(CIS_GETSTRING(pciServer, i), CIS_GETSTRING(pciClient, i)))
  4149. return FALSE;
  4150. }
  4151. else if (CIS_GETSTRING(pciServer, i) || CIS_GETSTRING(pciClient, i))
  4152. {
  4153. if (idcisNickName == i && CIS_GETSTRING(pciServer, i))
  4154. fResult = FALSE;
  4155. else
  4156. return FALSE;
  4157. }
  4158. }
  4159. // if the only reason they don't match is the lack of local nickname and
  4160. // there is a server one, just copy the nickname locally
  4161. if (!fResult)
  4162. {
  4163. CIS_GETSTRING(pciClient, idcisNickName) = _StrDup(CIS_GETSTRING(pciServer, idcisNickName));
  4164. fResult = TRUE;
  4165. }
  4166. return fResult;
  4167. }
  4168. HRESULT ContactInfo_PreparePatch(LPHTTPCONTACTINFO pciFrom, LPHTTPCONTACTINFO pciTo)
  4169. {
  4170. HRESULT hr = S_OK;
  4171. LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
  4172. for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
  4173. {
  4174. if (CIS_GETSTRING(pciFrom, i) && !CIS_GETSTRING(pciTo, i))
  4175. {
  4176. CIS_GETSTRING(pciTo, i) = _StrDup("");
  4177. if (!CIS_GETSTRING(pciTo, i))
  4178. {
  4179. hr = E_OUTOFMEMORY;
  4180. goto exit;
  4181. }
  4182. }
  4183. if (CIS_GETSTRING(pciFrom, i) && CIS_GETSTRING(pciTo, i) && lstrcmpA(CIS_GETSTRING(pciFrom, i), CIS_GETSTRING(pciTo, i)) == 0)
  4184. SafeCoMemFree(CIS_GETSTRING(pciTo, i));
  4185. }
  4186. exit:
  4187. return hr;
  4188. }
  4189. HRESULT ContactInfo_EmptyNullItems(LPHTTPCONTACTINFO pci)
  4190. {
  4191. HRESULT hr = S_OK;
  4192. LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
  4193. for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
  4194. {
  4195. if (CIS_GETSTRING(pci, i) == NULL)
  4196. CIS_GETSTRING(pci, i) = _StrDup("");
  4197. }
  4198. return S_OK;
  4199. }
  4200. HRESULT ContactInfo_BlendResults(LPHTTPCONTACTINFO pciServer, LPHTTPCONTACTINFO pciClient, CONFLICT_DECISION *prgDecisions)
  4201. {
  4202. HRESULT hr = S_OK;
  4203. LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
  4204. for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
  4205. {
  4206. if (prgDecisions[i] == CONFLICT_SERVER)
  4207. {
  4208. SafeCoMemFree(CIS_GETSTRING(pciClient, i) );
  4209. if (CIS_GETSTRING(pciServer, i))
  4210. {
  4211. CIS_GETSTRING(pciClient, i) = _StrDup(CIS_GETSTRING(pciServer, i));
  4212. SafeCoMemFree(CIS_GETSTRING(pciServer, i));
  4213. }
  4214. else
  4215. CIS_GETSTRING(pciClient, i) = _StrDup("");
  4216. }
  4217. else if (prgDecisions[i] == CONFLICT_CLIENT)
  4218. {
  4219. SafeCoMemFree(CIS_GETSTRING(pciServer, i));
  4220. if (CIS_GETSTRING(pciClient, i))
  4221. CIS_GETSTRING(pciServer, i) = _StrDup(CIS_GETSTRING(pciClient, i));
  4222. else
  4223. CIS_GETSTRING(pciServer, i) = _StrDup("");
  4224. }
  4225. else
  4226. {
  4227. SafeCoMemFree(CIS_GETSTRING(pciClient, i));
  4228. SafeCoMemFree(CIS_GETSTRING(pciServer, i));
  4229. }
  4230. }
  4231. return hr;
  4232. }
  4233. INT_PTR CALLBACK SyncProgressDlgProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  4234. {
  4235. // Locals
  4236. LPWABSYNC pWabSync = (LPWABSYNC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  4237. switch (uMsg)
  4238. {
  4239. case WM_INITDIALOG:
  4240. pWabSync = (LPWABSYNC)lParam;
  4241. if (!pWabSync)
  4242. {
  4243. Assert (FALSE);
  4244. return 1;
  4245. }
  4246. #ifdef HM_GROUP_SYNCING
  4247. // [PaulHi] Implement group syncing. Identify what is currently
  4248. // being synchronized, email contacts or groups.
  4249. {
  4250. TCHAR rgtchCaption[MAX_PATH];
  4251. UINT uids = pWabSync->m_fSyncGroups ? idsSyncGroupsTitle : idsSyncContactsTitle;
  4252. rgtchCaption[0] = '\0';
  4253. LoadString(hinstMapiX, uids, rgtchCaption, MAX_PATH-1);
  4254. SetWindowText(hwnd, rgtchCaption);
  4255. }
  4256. #endif
  4257. CenterDialog (hwnd);
  4258. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pWabSync);
  4259. return 1;
  4260. case WM_SYNC_NEXTSTATE:
  4261. _WABSync_NextState(pWabSync);
  4262. break;
  4263. case WM_SYNC_NEXTOP:
  4264. if (!_WABSync_NextOp(pWabSync, (0 != wParam)))
  4265. WABSync_NextState(pWabSync);
  4266. break;
  4267. case WM_TIMER:
  4268. break;
  4269. case WM_COMMAND:
  4270. switch(GET_WM_COMMAND_ID(wParam,lParam))
  4271. {
  4272. case IDCANCEL:
  4273. if (pWabSync)
  4274. {
  4275. EnableWindow ((HWND)lParam, FALSE);
  4276. WABSync_Abort(pWabSync, E_UserCancel);
  4277. }
  4278. return 1;
  4279. }
  4280. break;
  4281. case WM_DESTROY:
  4282. // KillTimer(hwnd, IDT_PROGRESS_DELAY);
  4283. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) NULL);
  4284. break;
  4285. }
  4286. // Done
  4287. return 0;
  4288. }
  4289. HRESULT CopyMultiValueString(
  4290. SWStringArray *pInArray,
  4291. SLPSTRArray **ppOutArray)
  4292. {
  4293. SLPSTRArray *pResult = NULL;
  4294. SCODE sc;
  4295. HRESULT hr;
  4296. DWORD i, cb;
  4297. *ppOutArray = NULL;
  4298. sc = MAPIAllocateBuffer(sizeof(SLPSTRArray),
  4299. (LPVOID *)&pResult);
  4300. if (sc)
  4301. goto fail;
  4302. pResult->cValues = pInArray->cValues;
  4303. sc = MAPIAllocateMore(sizeof(LPSTR) * pResult->cValues, pResult,
  4304. (LPVOID *)&(pResult->lppszA));
  4305. if (sc)
  4306. goto fail;
  4307. for (i = 0; i < pResult->cValues; i ++)
  4308. {
  4309. if(sc = ScWCToAnsiMore((LPALLOCATEMORE ) (&MAPIAllocateMore),(LPVOID) pResult, (LPWSTR) pInArray->LPPSZ[i], (LPSTR *) (&(pResult->lppszA[i]))))
  4310. goto fail;
  4311. }
  4312. *ppOutArray = pResult;
  4313. return S_OK;
  4314. fail:
  4315. hr = ResultFromScode(sc);
  4316. FreeMultiValueString(pResult);
  4317. return hr;
  4318. }
  4319. HRESULT AppendToMultiValueString(SLPSTRArray *pInArray, LPSTR szStr)
  4320. {
  4321. LPSTR *ppStrA;
  4322. SCODE sc;
  4323. HRESULT hr;
  4324. DWORD i, cb;
  4325. ppStrA = pInArray->lppszA;
  4326. sc = MAPIAllocateMore(sizeof(LPSTR) * (pInArray->cValues + 1), pInArray,
  4327. (LPVOID *)&(pInArray->lppszA));
  4328. if (sc)
  4329. {
  4330. pInArray->lppszA = ppStrA;
  4331. goto fail;
  4332. }
  4333. CopyMemory(pInArray->lppszA, ppStrA, pInArray->cValues * sizeof(LPSTR));
  4334. cb = lstrlenA(szStr);
  4335. sc = MAPIAllocateMore(cb + 1, pInArray,
  4336. (LPVOID *)&(pInArray->lppszA[pInArray->cValues]));
  4337. if (sc)
  4338. goto fail;
  4339. StrCpyNA(pInArray->lppszA[pInArray->cValues], szStr, cb + 1);
  4340. pInArray->cValues++;
  4341. return S_OK;
  4342. fail:
  4343. hr = ResultFromScode(sc);
  4344. return hr;
  4345. }
  4346. HRESULT SetMultiValueStringValue(SLPSTRArray *pInArray, LPSTR szStr, DWORD dwIndex)
  4347. {
  4348. LPSTR *ppStrA;
  4349. SCODE sc;
  4350. HRESULT hr;
  4351. DWORD i, cb;
  4352. if (dwIndex >= pInArray->cValues)
  4353. return E_FAIL;
  4354. ppStrA = pInArray->lppszA;
  4355. cb = lstrlenA(szStr);
  4356. sc = MAPIAllocateMore(cb + 1, pInArray,
  4357. (LPVOID *)&(pInArray->lppszA[dwIndex]));
  4358. if (sc)
  4359. goto fail;
  4360. StrCpyNA(pInArray->lppszA[dwIndex], szStr, cb + 1);
  4361. return S_OK;
  4362. fail:
  4363. hr = ResultFromScode(sc);
  4364. return hr;
  4365. }
  4366. HRESULT FreeMultiValueString(SLPSTRArray *pInArray)
  4367. {
  4368. if (pInArray)
  4369. MAPIFreeBuffer(pInArray);
  4370. return S_OK;
  4371. }