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.
5258 lines
167 KiB
5258 lines
167 KiB
//
|
|
// HotSync.c
|
|
//
|
|
// Contains code to synchronize addresses and groups with
|
|
// HotMail servers
|
|
//
|
|
|
|
#define COBJMACROS
|
|
#include <_apipch.h>
|
|
#include <wab.h>
|
|
#define COBJMACROS
|
|
#include "HotSync.h"
|
|
#include "iso8601.h"
|
|
#include "uimisc.h"
|
|
#include "ui_cflct.h"
|
|
#include "ui_pwd.h"
|
|
#include "useragnt.h"
|
|
|
|
typedef enum {
|
|
CIS_STRING = 0,
|
|
CIS_BOOL,
|
|
CIS_DWORD
|
|
}CIS_TYPE;
|
|
|
|
typedef struct CONTACTINFO_STRUCTURE
|
|
{
|
|
CIS_TYPE tType;
|
|
DWORD dwOffset;
|
|
}CONTACTINFO_STRUCTURE;
|
|
|
|
enum {
|
|
idcisHref = 0,
|
|
idcisId,
|
|
idcisType,
|
|
idcisModified,
|
|
idcisDisplayName,
|
|
idcisGivenName,
|
|
idcisSurname,
|
|
idcisNickName,
|
|
idcisEmail,
|
|
idcisHomeStreet,
|
|
idcisHomeCity,
|
|
idcisHomeState,
|
|
idcisHomePostalCode,
|
|
idcisHomeCountry,
|
|
idcisCompany,
|
|
idcisWorkStreet,
|
|
idcisWorkCity,
|
|
idcisWorkState,
|
|
idcisWorkPostalCode,
|
|
idcisWorkCountry,
|
|
idcisHomePhone,
|
|
idcisHomeFax,
|
|
idcisWorkPhone,
|
|
idcisWorkFax,
|
|
idcisMobilePhone,
|
|
idcisOtherPhone,
|
|
idcisBday,
|
|
idcisPager
|
|
};
|
|
|
|
CONTACTINFO_STRUCTURE g_ContactInfoStructure[] =
|
|
{
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHref)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszId)},
|
|
{CIS_DWORD, offsetof(HTTPCONTACTINFO, tyContact)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszModified)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszDisplayName)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszGivenName)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszSurname)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszNickname)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszEmail)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeStreet)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeCity)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeState)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomePostalCode)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeCountry)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszCompany)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkStreet)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkCity)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkState)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkPostalCode)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkCountry)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomePhone)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszHomeFax)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkPhone)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszWorkFax)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszMobilePhone)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszOtherPhone)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszBday)},
|
|
{CIS_STRING, offsetof(HTTPCONTACTINFO, pszPager)}
|
|
};
|
|
|
|
#define CIS_FIRST_DATA_FIELD 5
|
|
|
|
#define CIS_GETSTRING(pci, i) (*((char **)(&((char *)pci)[g_ContactInfoStructure[i].dwOffset])))
|
|
#define CIS_GETTYPE(i) (g_ContactInfoStructure[i].tType)
|
|
|
|
IHTTPMailCallbackVtbl vtblIHTTPMAILCALLBACK = {
|
|
VTABLE_FILL
|
|
WABSync_QueryInterface,
|
|
WABSync_AddRef,
|
|
WABSync_Release,
|
|
WABSync_OnTimeout,
|
|
WABSync_OnLogonPrompt,
|
|
WABSync_OnPrompt,
|
|
WABSync_OnStatus,
|
|
WABSync_OnError,
|
|
WABSync_OnCommand,
|
|
WABSync_OnResponse,
|
|
WABSync_GetParentWindow
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
ieid_PR_DISPLAY_NAME = 0,
|
|
ieid_PR_OBJECT_TYPE,
|
|
ieid_PR_ENTRYID,
|
|
ieid_PR_LAST_MODIFICATION_TIME,
|
|
ieid_PR_WAB_HOTMAIL_CONTACTIDS,
|
|
ieid_PR_WAB_HOTMAIL_SERVERIDS,
|
|
ieid_PR_WAB_HOTMAIL_MODTIMES,
|
|
ieid_Max
|
|
};
|
|
|
|
static SizedSPropTagArray(ieid_Max, ptaEidSync)=
|
|
{
|
|
ieid_Max,
|
|
{
|
|
PR_DISPLAY_NAME,
|
|
PR_OBJECT_TYPE,
|
|
PR_ENTRYID,
|
|
PR_LAST_MODIFICATION_TIME,
|
|
PR_ENTRYID,
|
|
PR_ENTRYID,
|
|
PR_ENTRYID
|
|
}
|
|
};
|
|
|
|
enum {
|
|
ieidc_PR_DISPLAY_NAME = 0,
|
|
ieidc_PR_OBJECT_TYPE,
|
|
ieidc_PR_ENTRYID,
|
|
ieidc_PR_LAST_MODIFICATION_TIME,
|
|
ieidc_PR_GIVEN_NAME,
|
|
ieidc_PR_SURNAME,
|
|
ieidc_PR_NICKNAME,
|
|
ieidc_PR_EMAIL_ADDRESS,
|
|
ieidc_PR_HOME_ADDRESS_STREET,
|
|
ieidc_PR_HOME_ADDRESS_CITY,
|
|
ieidc_PR_HOME_ADDRESS_STATE_OR_PROVINCE,
|
|
ieidc_PR_HOME_ADDRESS_POSTAL_CODE,
|
|
ieidc_PR_HOME_ADDRESS_COUNTRY,
|
|
ieidc_PR_COMPANY_NAME,
|
|
ieidc_PR_BUSINESS_ADDRESS_STREET,
|
|
ieidc_PR_BUSINESS_ADDRESS_CITY,
|
|
ieidc_PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
|
|
ieidc_PR_BUSINESS_ADDRESS_POSTAL_CODE,
|
|
ieidc_PR_BUSINESS_ADDRESS_COUNTRY,
|
|
ieidc_PR_HOME_TELEPHONE_NUMBER,
|
|
ieidc_PR_HOME_FAX_NUMBER,
|
|
ieidc_PR_BUSINESS_TELEPHONE_NUMBER,
|
|
ieidc_PR_BUSINESS_FAX_NUMBER,
|
|
ieidc_PR_MOBILE_TELEPHONE_NUMBER,
|
|
ieidc_PR_OTHER_TELEPHONE_NUMBER,
|
|
ieidc_PR_BIRTHDAY,
|
|
ieidc_PR_PAGER,
|
|
ieidc_PR_CONTACT_EMAIL_ADDRESSES,
|
|
ieidc_PR_CONTACT_DEFAULT_ADDRESS_INDEX,
|
|
#ifdef HM_GROUP_SYNCING
|
|
ieidc_PR_WAB_DL_ENTRIES,
|
|
ieidc_PR_WAB_DL_ONEOFFS,
|
|
#endif
|
|
ieidc_PR_WAB_HOTMAIL_CONTACTIDS,
|
|
ieidc_PR_WAB_HOTMAIL_SERVERIDS,
|
|
ieidc_PR_WAB_HOTMAIL_MODTIMES,
|
|
ieidc_Max
|
|
};
|
|
|
|
static SizedSPropTagArray(ieidc_Max, ptaEidCSync)=
|
|
{
|
|
ieidc_Max,
|
|
{
|
|
PR_DISPLAY_NAME,
|
|
PR_OBJECT_TYPE,
|
|
PR_ENTRYID,
|
|
PR_LAST_MODIFICATION_TIME,
|
|
PR_GIVEN_NAME,
|
|
PR_SURNAME,
|
|
PR_NICKNAME,
|
|
PR_EMAIL_ADDRESS,
|
|
PR_HOME_ADDRESS_STREET,
|
|
PR_HOME_ADDRESS_CITY,
|
|
PR_HOME_ADDRESS_STATE_OR_PROVINCE,
|
|
PR_HOME_ADDRESS_POSTAL_CODE,
|
|
PR_HOME_ADDRESS_COUNTRY,
|
|
PR_COMPANY_NAME,
|
|
PR_BUSINESS_ADDRESS_STREET,
|
|
PR_BUSINESS_ADDRESS_CITY,
|
|
PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
|
|
PR_BUSINESS_ADDRESS_POSTAL_CODE,
|
|
PR_BUSINESS_ADDRESS_COUNTRY,
|
|
PR_HOME_TELEPHONE_NUMBER,
|
|
PR_HOME_FAX_NUMBER,
|
|
PR_BUSINESS_TELEPHONE_NUMBER,
|
|
PR_BUSINESS_FAX_NUMBER,
|
|
PR_MOBILE_TELEPHONE_NUMBER,
|
|
PR_OTHER_TELEPHONE_NUMBER,
|
|
PR_BIRTHDAY,
|
|
PR_PAGER_TELEPHONE_NUMBER,
|
|
PR_CONTACT_EMAIL_ADDRESSES,
|
|
PR_CONTACT_DEFAULT_ADDRESS_INDEX,
|
|
#ifdef HM_GROUP_SYNCING
|
|
PR_WAB_DL_ENTRIES,
|
|
PR_ENTRYID,
|
|
#endif
|
|
PR_ENTRYID,
|
|
PR_ENTRYID,
|
|
PR_ENTRYID,
|
|
}
|
|
};
|
|
|
|
// HM Nickname invalid characters
|
|
const ULONG MAX_INVALID_ARRAY_INDEX = 123;
|
|
static BOOL bInvalidCharArray[] =
|
|
{
|
|
TRUE, // 0
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE, // 9
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE, // 19
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE, // 29
|
|
TRUE,
|
|
TRUE,
|
|
TRUE, // 32 (x20) Space
|
|
TRUE, // !
|
|
TRUE, // "
|
|
TRUE, // #
|
|
TRUE, // $
|
|
TRUE, // %
|
|
TRUE, // &
|
|
TRUE, // '
|
|
TRUE, // (
|
|
TRUE, // )
|
|
TRUE, // 42 *
|
|
TRUE, // +
|
|
TRUE, // ,
|
|
TRUE, // -
|
|
TRUE, // .
|
|
TRUE, // /
|
|
FALSE, // 0
|
|
FALSE, // 1
|
|
FALSE, // 2
|
|
FALSE, // 3
|
|
FALSE, // 52 4
|
|
FALSE, // 5
|
|
FALSE, // 6
|
|
FALSE, // 7
|
|
FALSE, // 8
|
|
FALSE, // 9
|
|
TRUE, // :
|
|
TRUE, // ;
|
|
TRUE, // <
|
|
TRUE, // =
|
|
TRUE, // 62 >
|
|
TRUE, // ?
|
|
TRUE, // @
|
|
FALSE, // A
|
|
FALSE, // B
|
|
FALSE, // C
|
|
FALSE, // D
|
|
FALSE, // E
|
|
FALSE, // F
|
|
FALSE, // G
|
|
FALSE, // 72 H
|
|
FALSE, // I
|
|
FALSE, // J
|
|
FALSE, // K
|
|
FALSE, // L
|
|
FALSE, // M
|
|
FALSE, // N
|
|
FALSE, // O
|
|
FALSE, // P
|
|
FALSE, // Q
|
|
FALSE, // 82 R
|
|
FALSE, // S
|
|
FALSE, // T
|
|
FALSE, // U
|
|
FALSE, // V
|
|
FALSE, // W
|
|
FALSE, // X
|
|
FALSE, // Y
|
|
FALSE, // Z
|
|
TRUE, // [
|
|
TRUE, // 92 '\'
|
|
TRUE, // ]
|
|
TRUE, // ^
|
|
FALSE, // _
|
|
TRUE, // `
|
|
FALSE, // a
|
|
FALSE, // b
|
|
FALSE, // c
|
|
FALSE, // d
|
|
FALSE, // e
|
|
FALSE, // 102 f
|
|
FALSE, // g
|
|
FALSE, // h
|
|
FALSE, // i
|
|
FALSE, // j
|
|
FALSE, // k
|
|
FALSE, // l
|
|
FALSE, // m
|
|
FALSE, // n
|
|
FALSE, // o
|
|
FALSE, // 112 p
|
|
FALSE, // q
|
|
FALSE, // r
|
|
FALSE, // s
|
|
FALSE, // t
|
|
FALSE, // u
|
|
FALSE, // v
|
|
FALSE, // w
|
|
FALSE, // x
|
|
FALSE, // y
|
|
FALSE, // 122 z
|
|
};
|
|
|
|
extern HRESULT InitUserIdentityManager(LPIAB lpIAB, IUserIdentityManager ** lppUserIdentityManager);
|
|
|
|
// Address Book Sync Window Class Name
|
|
LPTSTR g_lpszSyncKey = TEXT("Software\\Microsoft\\WAB\\Synchronization\\");
|
|
|
|
LPTSTR g_szSyncClass = TEXT("WABSyncView");
|
|
extern VOID CenterDialog(HWND hwndDlg);
|
|
|
|
#define WM_SYNC_NEXTSTATE (WM_USER + 4)
|
|
#define WM_SYNC_NEXTOP (WM_USER + 5)
|
|
#define SafeCoMemFree(_pv) \
|
|
if (_pv) { \
|
|
CoTaskMemFree(_pv); \
|
|
_pv = NULL; \
|
|
} \
|
|
else
|
|
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
HRESULT HrSynchronize(HWND hWnd, LPADRBOOK lpIAB, LPCTSTR pszAccountID, BOOL bSyncGroups)
|
|
#else
|
|
HRESULT HrSynchronize(HWND hWnd, LPADRBOOK lpIAB, LPCTSTR pszAccountID)
|
|
#endif
|
|
{
|
|
HRESULT hr;
|
|
LPWABSYNC pWabSync = NULL;
|
|
|
|
// if (!bIsThereACurrentUser((LPIAB)lpIAB))
|
|
// return E_FAIL;
|
|
|
|
// [PaulHi] Raid 62149 Check to see if user is connected
|
|
{
|
|
DWORD dwConnectedState;
|
|
TCHAR tszCaption[256];
|
|
TCHAR tszMessage[256];
|
|
|
|
if ( !InternetGetConnectedState(&dwConnectedState, 0) || (dwConnectedState & INTERNET_CONNECTION_OFFLINE) )
|
|
{
|
|
LoadString(hinstMapiX, idsSyncError, tszCaption, CharSizeOf(tszCaption));
|
|
if (dwConnectedState & INTERNET_CONNECTION_OFFLINE)
|
|
LoadString(hinstMapiX, idsOffline, tszMessage, CharSizeOf(tszMessage));
|
|
else
|
|
LoadString(hinstMapiX, idsNoInternetConnect, tszMessage, CharSizeOf(tszMessage));
|
|
MessageBox(hWnd, tszMessage, tszCaption, MB_ICONEXCLAMATION | MB_OK);
|
|
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
// Create the wab sync object
|
|
hr = WABSync_Create(&pWabSync);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
// initializing it kicks off the whole process
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] 2/22/99 Hotmail syncing is now done in two passes. The first pass is
|
|
// as before and synchronizes the normal email contacts. The second pass synchronizes
|
|
// the group contacts. Group contacts contain references to email contacts so email
|
|
// contacts must be completely synchronized before groups can be synchronized.
|
|
hr = WABSync_Initialize(pWabSync, hWnd, lpIAB, pszAccountID, bSyncGroups);
|
|
#else
|
|
hr = WABSync_Initialize(pWabSync, hWnd, lpIAB, pszAccountID);
|
|
#endif
|
|
|
|
exit:
|
|
WABSync_Release((IHTTPMailCallback*)pWabSync);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static LPSTR _StrDup(LPCSTR pszStr)
|
|
{
|
|
LPMALLOC lpMalloc;
|
|
LPSTR pszResult = NULL;
|
|
|
|
if (!pszStr)
|
|
return NULL;
|
|
|
|
CoGetMalloc(MEMCTX_TASK, &lpMalloc);
|
|
if (lpMalloc)
|
|
{
|
|
DWORD cchSize = (lstrlenA(pszStr) + 1);
|
|
pszResult = (LPSTR) lpMalloc->lpVtbl->Alloc(lpMalloc, cchSize * sizeof(pszResult[0]));
|
|
|
|
if (pszResult)
|
|
StrCpyNA(pszResult, pszStr, cchSize);
|
|
lpMalloc->lpVtbl->Release(lpMalloc);
|
|
}
|
|
|
|
return pszResult;
|
|
}
|
|
|
|
void _FixHotmailDate(LPSTR pszDate)
|
|
{
|
|
if (!pszDate)
|
|
return;
|
|
|
|
while (*pszDate)
|
|
{
|
|
if (*pszDate == 'T')
|
|
{
|
|
*pszDate = 0;
|
|
break;
|
|
}
|
|
|
|
if (*pszDate == '.')
|
|
*pszDate = '-';
|
|
|
|
pszDate++;
|
|
}
|
|
}
|
|
|
|
BOOL LogTransactions(LPWABSYNC pWabSync)
|
|
{
|
|
BOOL fInit = FALSE, fLogging = FALSE;
|
|
LPTSTR pszLogKey = TEXT("Software\\Microsoft\\Outlook Express\\5.0\\Mail");
|
|
LPTSTR pszLogValue = TEXT("Log HTTPMail (0/1)");
|
|
IUserIdentityManager * lpUserIdentityManager = NULL;
|
|
IUserIdentity * lpUserIdentity = NULL;
|
|
HRESULT hr;
|
|
HKEY hkeyIdentity = NULL, hkeyLog = NULL;
|
|
DWORD dwValue, dwType, dwSize;
|
|
|
|
if(!bIsWABSessionProfileAware((LPIAB)(pWabSync->m_pAB)))
|
|
goto exit;
|
|
|
|
if(HR_FAILED(hr = InitUserIdentityManager((LPIAB)(pWabSync->m_pAB), &lpUserIdentityManager)))
|
|
goto exit;
|
|
|
|
fInit = TRUE;
|
|
|
|
if(HR_FAILED(hr = lpUserIdentityManager->lpVtbl->GetIdentityByCookie(lpUserIdentityManager,
|
|
(GUID *)&UID_GIBC_CURRENT_USER,
|
|
&lpUserIdentity)))
|
|
goto exit;
|
|
|
|
if (HR_FAILED(hr = lpUserIdentity->lpVtbl->OpenIdentityRegKey(lpUserIdentity,
|
|
KEY_READ, &hkeyIdentity)))
|
|
goto exit;
|
|
|
|
if (RegOpenKeyEx(hkeyIdentity, pszLogKey, 0, KEY_READ, &hkeyLog) != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if (RegQueryValueEx(hkeyLog, pszLogValue, NULL, &dwType, (LPBYTE) &dwValue, &dwSize) != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
fLogging = (dwValue == 1);
|
|
exit:
|
|
if(fInit)
|
|
UninitUserIdentityManager((LPIAB)(pWabSync->m_pAB));
|
|
|
|
if(lpUserIdentity)
|
|
lpUserIdentity->lpVtbl->Release(lpUserIdentity);
|
|
|
|
if (hkeyLog)
|
|
RegCloseKey(hkeyLog);
|
|
|
|
if (hkeyIdentity)
|
|
RegCloseKey(hkeyIdentity);
|
|
|
|
return fLogging;
|
|
}
|
|
|
|
DWORD CountHTTPMailAccounts(LPIAB lpIAB)
|
|
{
|
|
IImnAccountManager2 *lpAcctMgr;
|
|
IImnEnumAccounts *pEnumAccts = NULL;
|
|
DWORD dwCount = 0;
|
|
HRESULT hr;
|
|
|
|
if (FAILED(hr = InitAccountManager(lpIAB, &lpAcctMgr, NULL)) || NULL == lpAcctMgr)
|
|
goto exit;
|
|
|
|
if (FAILED(hr = lpAcctMgr->lpVtbl->Enumerate(lpAcctMgr, SRV_HTTPMAIL,&pEnumAccts)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pEnumAccts->lpVtbl->GetCount(pEnumAccts, &dwCount)))
|
|
dwCount = 0;
|
|
|
|
exit:
|
|
if( pEnumAccts)
|
|
pEnumAccts->lpVtbl->Release(pEnumAccts);
|
|
|
|
return dwCount;
|
|
}
|
|
|
|
HRESULT _FindHTTPMailAccount(HWND hwnd, IImnAccountManager2 *lpAcctMgr, LPSTR pszAcctName, ULONG ccb)
|
|
{
|
|
IImnEnumAccounts *pEnumAccts = NULL;
|
|
DWORD dwCount = 0;
|
|
IImnAccount *pAccount = NULL;
|
|
HRESULT hr;
|
|
|
|
Assert(lpAcctMgr);
|
|
|
|
if (FAILED(hr = lpAcctMgr->lpVtbl->Enumerate(lpAcctMgr, SRV_HTTPMAIL,&pEnumAccts)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pEnumAccts->lpVtbl->GetCount(pEnumAccts, &dwCount)) || dwCount == 0)
|
|
goto exit;
|
|
|
|
if (dwCount > 1)
|
|
{
|
|
if (!ChooseHotmailServer(hwnd, pEnumAccts, pszAcctName, ccb))
|
|
{
|
|
hr = E_UserCancel;
|
|
goto exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hr = pEnumAccts->lpVtbl->GetNext(pEnumAccts, &pAccount)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pAccount->lpVtbl->GetProp(pAccount, AP_ACCOUNT_ID, pszAcctName, &ccb)))
|
|
goto exit;
|
|
}
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
if( pAccount)
|
|
pAccount->lpVtbl->Release(pAccount);
|
|
|
|
if( pEnumAccts)
|
|
pEnumAccts->lpVtbl->Release(pEnumAccts);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// HrMakeContactId
|
|
//
|
|
// Helper function to convert ANSI strings and create UNICODE contact ID
|
|
// string.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT hrMakeContactId(
|
|
LPTSTR lptszContactId, // [out]
|
|
int nCharNum, // [in]
|
|
LPCTSTR lptcszProfileId, // [in]
|
|
LPCSTR lpcszAccountId, // [in]
|
|
LPCSTR lpcszLoginName) // [in]
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR lpwszAccountId = NULL;
|
|
LPWSTR lpwszLoginName = NULL;
|
|
|
|
// Validate arguments
|
|
if ( !lptszContactId ||
|
|
!lptcszProfileId ||
|
|
!lpcszAccountId ||
|
|
!lpcszLoginName)
|
|
{
|
|
Assert(0);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Check buffer size. Account for the two extra '-' characters.
|
|
if ( nCharNum <= (lstrlen(lptcszProfileId) + lstrlenA(lpcszAccountId) + lstrlenA(lpcszLoginName) + 2) )
|
|
{
|
|
Assert(0);
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
lpwszAccountId = ConvertAtoW(lpcszAccountId);
|
|
lpwszLoginName = ConvertAtoW(lpcszLoginName);
|
|
|
|
if (!lpwszAccountId || !lpwszLoginName)
|
|
{
|
|
Assert(0);
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
wnsprintf(lptszContactId, nCharNum, TEXT("%s-%s-%s"), lptcszProfileId, lpwszAccountId, lpwszLoginName);
|
|
}
|
|
|
|
LocalFreeAndNull(&lpwszAccountId);
|
|
LocalFreeAndNull(&lpwszLoginName);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hrAppendName
|
|
//
|
|
// Helper function to take a double byte name string, converts it to single
|
|
// byte and appends it to the given name string, using ',' as the delimiter.
|
|
// The name string pointer will be allocated and reallocated as needed. The
|
|
// caller is responible for freeing the name string with CoTaskMemFree().
|
|
//
|
|
// Parameters
|
|
// [IN/OUT] lpszNameString - name string pointer
|
|
// [IN] ulCharCount - current name string size in char
|
|
// [IN] double byte character string to append
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LPCSTR lpszDelimiter = ",";
|
|
|
|
ULONG ulAppendName(
|
|
LPSTR * lppszNameString,
|
|
ULONG ulCharCount,
|
|
LPCTSTR lptszName)
|
|
{
|
|
ULONG ulLen = 0;
|
|
ULONG ulNewLen = 0;
|
|
ULONG ulNew = ulCharCount;
|
|
LPSTR lpszTemp = NULL;
|
|
|
|
Assert(lppszNameString);
|
|
Assert(lptszName);
|
|
|
|
// Check size of new string
|
|
ulNewLen = (ULONG)lstrlen(lptszName) + 2; // Include delimiter character and termination
|
|
if (*lppszNameString)
|
|
ulLen = ulNewLen + (ULONG)lstrlenA(*lppszNameString);
|
|
else
|
|
ulLen = ulNewLen;
|
|
if (ulLen > ulCharCount)
|
|
{
|
|
ulNew = (ulNewLen > MAX_PATH) ? (ulCharCount+ulNewLen+MAX_PATH) : (ulCharCount+MAX_PATH);
|
|
lpszTemp = CoTaskMemAlloc(ulNew * sizeof(WCHAR));
|
|
if (!lpszTemp)
|
|
{
|
|
Assert(0);
|
|
goto error_out;
|
|
}
|
|
*lpszTemp = '\0';
|
|
|
|
if (*lppszNameString)
|
|
{
|
|
StrCpyNA(lpszTemp, *lppszNameString, ulNew);
|
|
CoTaskMemFree(*lppszNameString);
|
|
}
|
|
*lppszNameString = lpszTemp;
|
|
ulCharCount = ulNew;
|
|
}
|
|
|
|
// Append new string name
|
|
{
|
|
LPSTR lptsz = ConvertWtoA(lptszName);
|
|
if (**lppszNameString != '\0')
|
|
StrCatBuffA(*lppszNameString, lpszDelimiter, ulCharCount);
|
|
StrCatBuffA(*lppszNameString, lptsz, ulCharCount);
|
|
LocalFreeAndNull(&lptsz);
|
|
}
|
|
|
|
return ulNew;
|
|
|
|
error_out:
|
|
|
|
// Error, return NULL string pointer
|
|
if (*lppszNameString)
|
|
{
|
|
CoTaskMemFree(*lppszNameString);
|
|
*lppszNameString = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hrAppendGroupContact
|
|
//
|
|
// Helper function to a group's PR_WAB_DL_ENTRIES and/or PR_WAB_DL_ONEOFFS
|
|
// names and append to the given name string. This name string is in the same
|
|
// format as what is retrieved from a HotMail server, and is compared directly
|
|
// with the corresponding HotMail group.
|
|
//
|
|
// a) PR_WAB_DL_ENTRIES are WAB entry ID contacts that map to HM contacts
|
|
// distinquished by nickname.
|
|
// b) PR_WAB_DL_ONEOFFS are WAB entry ID one-offs with user and email embedded
|
|
// directly in the entry ID structure.
|
|
//
|
|
// Parameters
|
|
// [IN] pWabSync
|
|
// [IN] ulPropTag
|
|
// [IN] lpProp - Pointer to property struct
|
|
// [IN/OUT] lppszHMEmailName - HM string with new names appended
|
|
// !!NOTE that this needs to be freed by caller using CoMemTaskFree()!!
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT hrAppendGroupContact(
|
|
LPWABSYNC pWabSync, // [IN]
|
|
ULONG ulPropTag, // [IN]
|
|
LPSPropValue lpProp, // [IN]
|
|
LPSTR * lppszHMEmailName) // [IN/OUT]
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSPropValue lpaProps = NULL;
|
|
ULONG ulcProps = 0;
|
|
ULONG ul;
|
|
ULONG ulCharSize = 0;
|
|
|
|
Assert(pWabSync);
|
|
Assert(lppszHMEmailName);
|
|
Assert( (ulPropTag == PR_WAB_DL_ENTRIES) || (ulPropTag == PR_WAB_DL_ONEOFFS) );
|
|
|
|
// Check each DL entry and check whether it is another WAB (mail user) contact
|
|
// EID or a WAB One-Off email/name string EID.
|
|
if (ulPropTag == PR_WAB_DL_ONEOFFS)
|
|
{
|
|
// Wab one-off is equivalent to a HM direct email name
|
|
for (ul=0; ul<lpProp->Value.MVbin.cValues; ul++)
|
|
{
|
|
ULONG cbEntryID = lpProp->Value.MVbin.lpbin[ul].cb;
|
|
LPENTRYID lpEntryID = (LPENTRYID)lpProp->Value.MVbin.lpbin[ul].lpb;
|
|
BYTE bType;
|
|
LPTSTR lptstrDisplayName, lptstrAddrType;
|
|
LPTSTR lptstrAddress = NULL;
|
|
|
|
bType = IsWABEntryID(cbEntryID, lpEntryID,
|
|
&lptstrDisplayName,
|
|
&lptstrAddrType,
|
|
&lptstrAddress, NULL, NULL);
|
|
if (lptstrAddress)
|
|
{
|
|
// Append the one-off email name
|
|
ulCharSize = ulAppendName(lppszHMEmailName, ulCharSize, lptstrAddress);
|
|
if (ulCharSize == 0)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto out;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
}
|
|
else if (ulPropTag == PR_WAB_DL_ENTRIES)
|
|
{
|
|
// WAB mail user contact is equivalent to a HM contact
|
|
for (ul=0; ul<lpProp->Value.MVbin.cValues; ul++)
|
|
{
|
|
HRESULT hr;
|
|
LPMAILUSER lpMailUser;
|
|
ULONG ulObjectType;
|
|
ULONG cbEntryID = lpProp->Value.MVbin.lpbin[ul].cb;
|
|
LPENTRYID lpEntryID = (LPENTRYID)lpProp->Value.MVbin.lpbin[ul].lpb;
|
|
|
|
hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, lpEntryID,
|
|
NULL, 0, &ulObjectType, (LPUNKNOWN *)&lpMailUser);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPSPropValue lpaProps;
|
|
ULONG ulcProps;
|
|
|
|
Assert(ulObjectType == MAPI_MAILUSER);
|
|
|
|
// HM contacts are designated by the nickname field, so this is all
|
|
// we need to append to the name string.
|
|
hr = lpMailUser->lpVtbl->GetProps(lpMailUser, NULL, MAPI_UNICODE, &ulcProps, &lpaProps);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULONG ulc;
|
|
LPCTSTR lptszNickname = NULL;
|
|
for (ulc=0; ulc<ulcProps; ulc++)
|
|
{
|
|
if (lpaProps[ulc].ulPropTag == PR_NICKNAME)
|
|
break;
|
|
}
|
|
if (ulc == ulcProps)
|
|
{
|
|
// No nickname. This means that the preceeding contact sync has
|
|
// failed or not completed in some way. Skip.
|
|
Assert(0);
|
|
continue;
|
|
}
|
|
else
|
|
lptszNickname = (LPCTSTR)lpaProps[ulc].Value.lpszW;
|
|
|
|
ulCharSize = ulAppendName(lppszHMEmailName, ulCharSize, lptszNickname);
|
|
if (ulCharSize == 0)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Trace("Unknown property tag type");
|
|
Assert(0);
|
|
}
|
|
|
|
out:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hrParseHMGroupEmail
|
|
//
|
|
// Helper function to parse a HM group email string into nickname names
|
|
// (contacts) and email names (one-offs). The name arrays are simply pointers
|
|
// into the passed in email name string and so are valid as long at that
|
|
// input string is valid. Note that this function modifies the input string
|
|
// lptszEmailName.
|
|
//
|
|
// Parameters
|
|
// [IN] lptszEmailName - email string to parse
|
|
// [OUT] patszContacts - array of parsed contact (nickname) names if requested
|
|
// [OUT] pcContacts - number of contact names
|
|
// [OUT] patszOneOffs - array of parsed one-off (email) names if requested
|
|
// [OUT] pcOneOffs - number of one-off names
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// It looks like HM allows four possible text delimiters: ' ', ',', ';', '+'
|
|
const TCHAR tszSpace[] = TEXT(" ");
|
|
const TCHAR tszComma[] = TEXT(",");
|
|
const TCHAR tszSemi[] = TEXT(";");
|
|
const TCHAR tszPlus[] = TEXT("+");
|
|
const TCHAR tszAt[] = TEXT("@");
|
|
|
|
HRESULT hrParseHMGroupEmail(
|
|
LPTSTR lptszEmailName,
|
|
LPTSTR ** patszContacts,
|
|
ULONG * pcContacts,
|
|
LPTSTR ** patszOneOffs,
|
|
ULONG * pcOneOffs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cCount = 1;
|
|
ULONG ul;
|
|
LPTSTR lptszTemp = lptszEmailName;
|
|
LPTSTR * atszContacts = NULL;
|
|
LPTSTR * atszOneOffs = NULL;
|
|
ULONG cContacts = 0;
|
|
ULONG cOneOffs = 0;
|
|
|
|
Assert( lptszEmailName && (pcContacts || pcOneOffs) );
|
|
|
|
// Strip all leading and ending spaces
|
|
TrimSpaces(lptszTemp);
|
|
|
|
// Count
|
|
while (*lptszTemp)
|
|
{
|
|
if ( ((*lptszTemp) == (*tszSpace)) ||
|
|
((*lptszTemp) == (*tszComma)) ||
|
|
((*lptszTemp) == (*tszSemi)) ||
|
|
((*lptszTemp) == (*tszPlus)) )
|
|
{
|
|
++cCount;
|
|
|
|
// Increment to next valid name
|
|
++lptszTemp;
|
|
while ( ((*lptszTemp) == (*tszSpace)) ||
|
|
((*lptszTemp) == (*tszComma)) ||
|
|
((*lptszTemp) == (*tszSemi)) ||
|
|
((*lptszTemp) == (*tszPlus)) )
|
|
{
|
|
++lptszTemp;
|
|
}
|
|
}
|
|
else
|
|
++lptszTemp;
|
|
}
|
|
|
|
// Create Contacts and One-Offs name pointer arrays
|
|
atszContacts = LocalAlloc(LMEM_ZEROINIT, (cCount * sizeof(LPTSTR)));
|
|
if (!atszContacts)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto out;
|
|
}
|
|
atszOneOffs = LocalAlloc(LMEM_ZEROINIT, (cCount * sizeof(LPTSTR)));
|
|
if (!atszOneOffs)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto out;
|
|
}
|
|
|
|
// Fill the name pointer arrays and counts
|
|
{
|
|
LPTSTR lptszName = lptszEmailName;
|
|
BOOL fIsEmail = FALSE;
|
|
|
|
lptszTemp = lptszName;
|
|
while(*lptszTemp)
|
|
{
|
|
// Determine whether this name is a nickname or email. I am assuning
|
|
// that all email names will have the '@' character.
|
|
if ((*lptszTemp) == (*tszAt))
|
|
fIsEmail = TRUE;
|
|
|
|
if ( ((*lptszTemp) == (*tszSpace)) ||
|
|
((*lptszTemp) == (*tszComma)) ||
|
|
((*lptszTemp) == (*tszSemi)) ||
|
|
((*lptszTemp) == (*tszPlus)) )
|
|
{
|
|
*lptszTemp = '\0';
|
|
++lptszTemp;
|
|
|
|
if (fIsEmail)
|
|
{
|
|
atszOneOffs[cOneOffs++] = lptszName;
|
|
Assert(cOneOffs <= cCount);
|
|
fIsEmail = FALSE;
|
|
}
|
|
else
|
|
{
|
|
atszContacts[cContacts++] = lptszName;
|
|
Assert(cContacts <= cCount);
|
|
}
|
|
|
|
// Increment to next valid name
|
|
while ( ((*lptszTemp) == (*tszSpace)) ||
|
|
((*lptszTemp) == (*tszComma)) ||
|
|
((*lptszTemp) == (*tszSemi)) ||
|
|
((*lptszTemp) == (*tszPlus)) )
|
|
{
|
|
++lptszTemp;
|
|
}
|
|
|
|
lptszName = lptszTemp;
|
|
}
|
|
else
|
|
++lptszTemp;
|
|
}
|
|
// Pick up last item
|
|
if (*lptszName)
|
|
{
|
|
if (fIsEmail)
|
|
{
|
|
atszOneOffs[cOneOffs++] = lptszName;
|
|
Assert(cOneOffs <= cCount);
|
|
}
|
|
else
|
|
{
|
|
atszContacts[cContacts++] = lptszName;
|
|
Assert(cContacts <= cCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pass back contact name array if requested
|
|
if (cContacts && pcContacts)
|
|
{
|
|
*pcContacts = cContacts;
|
|
}
|
|
if (patszContacts)
|
|
(*patszContacts) = atszContacts;
|
|
|
|
// Pass back one-off name array if requested
|
|
if (cOneOffs && pcOneOffs )
|
|
{
|
|
*pcOneOffs = cOneOffs;
|
|
}
|
|
if (patszOneOffs)
|
|
(*patszOneOffs) = atszOneOffs;
|
|
|
|
out:
|
|
|
|
if ( FAILED(hr) || !patszContacts )
|
|
LocalFreeAndNull((LPVOID *)&atszContacts);
|
|
|
|
if ( FAILED(hr) || !patszOneOffs )
|
|
LocalFreeAndNull((LPVOID *)&atszOneOffs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hrCreateGroupMVBin
|
|
//
|
|
// Creates either a PR_WAB_DL_ENTRIES or PR_WAB_DL_ONEOFFS MVBin property and
|
|
// adds it to the passed in property array.
|
|
//
|
|
// If the proptag is PR_WAB_DL_ENTRIES then the atszNames array is assumed to
|
|
// contain valid WAB contact nicknames. The first contact's (mail user) EID
|
|
// with that nickname is added to the MVBin property. It is assumed that
|
|
// nicknames are unique (after contact syncing which is performed first) as is
|
|
// required by Hotmail.
|
|
//
|
|
// If the proptag is PR_WAB_DL_ONEOFFS then the atszNames array is assumed to
|
|
// contain valid email names. WAB one-off EIDs are created from these and
|
|
// added to the MVBin property.
|
|
//
|
|
// Parameters
|
|
// [IN] pWabSync
|
|
// [IN] ulPropTag
|
|
// [IN] atszNames - Array of wide char names
|
|
// [IN] cCount - Number of items in above array
|
|
// [IN/OUT] lpPropArray
|
|
// [IN/OUT] pdwLoc - Current lpPropArray index
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT hrCreateGroupMVBin(
|
|
LPWABSYNC pWabSync,
|
|
ULONG ulPropTag,
|
|
LPTSTR * atszNames,
|
|
ULONG cCount,
|
|
LPSPropValue lpPropArray,
|
|
DWORD * pdwLoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ul;
|
|
|
|
Assert(atszNames);
|
|
Assert(lpPropArray);
|
|
Assert(pdwLoc);
|
|
|
|
// Set up this property as error. When the MVbin values are added via
|
|
// AddPropToMVPBin() the tag type will change to valid PT_MV_BINARY type.
|
|
lpPropArray[*pdwLoc].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulPropTag));
|
|
lpPropArray[*pdwLoc].dwAlignPad = 0;
|
|
lpPropArray[*pdwLoc].Value.MVbin.cValues = 0;
|
|
lpPropArray[*pdwLoc].Value.MVbin.lpbin = NULL;
|
|
|
|
if (ulPropTag == PR_WAB_DL_ENTRIES)
|
|
{
|
|
// Search for WAB mail users with these nicknames
|
|
for (ul=0; ul<cCount; ul++)
|
|
{
|
|
SPropertyRestriction PropRes;
|
|
SPropValue Prop = {0};
|
|
LPSBinary rgsbEntryIDs = NULL;
|
|
ULONG ulCount = 1;
|
|
|
|
// Set up search restriction
|
|
Prop.ulPropTag = PR_NICKNAME;
|
|
Prop.Value.LPSZ = atszNames[ul];
|
|
PropRes.lpProp = &Prop;
|
|
PropRes.relop = RELOP_EQ;
|
|
PropRes.ulPropTag = PR_NICKNAME;
|
|
|
|
if (SUCCEEDED(FindRecords(((LPIAB)pWabSync->m_pAB)->lpPropertyStore->hPropertyStore,
|
|
NULL, // pmbinFolder
|
|
0, // ulFlags
|
|
TRUE, // Always TRUE
|
|
&PropRes, // Propertyrestriction
|
|
&ulCount, // IN: number of matches to find, OUT: number found
|
|
&rgsbEntryIDs)))
|
|
{
|
|
// Add EID property
|
|
if (ulCount > 0)
|
|
{
|
|
if ( FAILED(AddPropToMVPBin(
|
|
lpPropArray,
|
|
*pdwLoc,
|
|
rgsbEntryIDs[0].lpb,
|
|
rgsbEntryIDs[0].cb,
|
|
FALSE)) ) // Don't add duplicates, not
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
FreeEntryIDs(((LPIAB)pWabSync->m_pAB)->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs);
|
|
}
|
|
else
|
|
{
|
|
// All contacts should be in WAB unless the preceeding mail user contact
|
|
// sync failed.
|
|
DebugTrace(TEXT("hrCreateGroupMVBin - Failed to find HM group contact\n"));
|
|
}
|
|
}
|
|
}
|
|
else if (ulPropTag == PR_WAB_DL_ONEOFFS)
|
|
{
|
|
for (ul=0; ul<cCount; ul++)
|
|
{
|
|
ULONG cbEID = 0;
|
|
LPENTRYID lpEID = NULL;
|
|
LPTSTR lptszName = NULL;
|
|
LPTSTR lptszSMTP = TEXT("");
|
|
LPTSTR lptszEmail = atszNames[ul];
|
|
LPTSTR lptszTemp = NULL;
|
|
int nLen = lstrlen(atszNames[ul]) + 1;
|
|
|
|
// A WAB DL OneOff must have a valid display name. Take the first
|
|
// part of the email name for this.
|
|
lptszName = LocalAlloc(LMEM_ZEROINIT, (nLen * sizeof(WCHAR)));
|
|
if (!lptszName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto out;
|
|
}
|
|
StrCpyN(lptszName, lptszEmail, nLen);
|
|
lptszTemp = lptszName;
|
|
while ( *lptszTemp &&
|
|
(*lptszTemp) != (*tszAt) )
|
|
{
|
|
++lptszTemp;
|
|
}
|
|
(*lptszTemp) = '\0';
|
|
|
|
// Creates UNICODE string embedded WAB one-off EID
|
|
if ( SUCCEEDED(CreateWABEntryID(WAB_ONEOFF,
|
|
(LPVOID)lptszName,
|
|
(LPVOID)lptszSMTP,
|
|
(LPVOID)lptszEmail,
|
|
0, 0, NULL,
|
|
&cbEID,
|
|
&lpEID)) )
|
|
{
|
|
if ( FAILED(AddPropToMVPBin(
|
|
lpPropArray,
|
|
*pdwLoc,
|
|
lpEID,
|
|
cbEID,
|
|
FALSE)) ) // Don't add duplicates, not
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
LocalFreeAndNull(&lptszName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
out:
|
|
|
|
++(*pdwLoc);
|
|
return hr;
|
|
}
|
|
#endif // HM_GROUP_SYNCING
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hrStripInvalidChars
|
|
//
|
|
// Helper function to remove disallowed characters. HM only allows
|
|
// alphanumeric and '-' and '_' characters in a nickname. All illegal chars
|
|
// are removed from the string.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT hrStripInvalidChars(LPSTR lpszName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR lpszAddTo = NULL;
|
|
|
|
Assert(lpszName);
|
|
|
|
lpszAddTo = lpszName;
|
|
while (*lpszName)
|
|
{
|
|
// @review Currently the look up table only contains 122 characters. Make
|
|
// it full 256? How will HM change when it adds intenational suppport?
|
|
if ( ((UCHAR)(*lpszName) < MAX_INVALID_ARRAY_INDEX) && !bInvalidCharArray[*lpszName] )
|
|
{
|
|
*lpszAddTo = *lpszName;
|
|
++lpszAddTo;
|
|
}
|
|
++lpszName;
|
|
}
|
|
*lpszAddTo = '\0';
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// ****************************************************************************************************
|
|
// C H O T S Y N C C L A S S
|
|
//
|
|
// Class to handle the synchronizing of WAB and Hotmail contacts
|
|
//
|
|
|
|
HRESULT WABSync_Create(LPWABSYNC *ppWabSync)
|
|
{
|
|
Assert(ppWabSync);
|
|
|
|
*ppWabSync = LocalAlloc(LMEM_ZEROINIT, sizeof(WABSYNC));
|
|
|
|
// fix up the prop tag array structure to take into account the variable values
|
|
ptaEidSync.aulPropTag[ieid_PR_WAB_HOTMAIL_CONTACTIDS] = PR_WAB_HOTMAIL_CONTACTIDS;
|
|
ptaEidSync.aulPropTag[ieid_PR_WAB_HOTMAIL_SERVERIDS] = PR_WAB_HOTMAIL_SERVERIDS;
|
|
ptaEidSync.aulPropTag[ieid_PR_WAB_HOTMAIL_MODTIMES] = PR_WAB_HOTMAIL_MODTIMES;
|
|
|
|
// fix up the other prop tag array structure to take into account the variable values
|
|
ptaEidCSync.aulPropTag[ieidc_PR_WAB_HOTMAIL_CONTACTIDS] = PR_WAB_HOTMAIL_CONTACTIDS;
|
|
ptaEidCSync.aulPropTag[ieidc_PR_WAB_HOTMAIL_SERVERIDS] = PR_WAB_HOTMAIL_SERVERIDS;
|
|
ptaEidCSync.aulPropTag[ieidc_PR_WAB_HOTMAIL_MODTIMES] = PR_WAB_HOTMAIL_MODTIMES;
|
|
#ifdef HM_GROUP_SYNCING
|
|
ptaEidCSync.aulPropTag[ieidc_PR_WAB_DL_ONEOFFS] = PR_WAB_DL_ONEOFFS;
|
|
#endif
|
|
|
|
if (*ppWabSync)
|
|
{
|
|
(*ppWabSync)->vtbl = &vtblIHTTPMAILCALLBACK;
|
|
(*ppWabSync)->m_cRef = 1;
|
|
(*ppWabSync)->m_state = SYNC_STATE_INITIALIZING;
|
|
(*ppWabSync)->m_ixpStatus = IXP_DISCONNECTED;
|
|
ZeroMemory(&(*ppWabSync)->m_rInetServerInfo, sizeof(INETSERVER));
|
|
}
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void WABSync_Delete(LPWABSYNC pWabSync)
|
|
{
|
|
Assert(pWabSync);
|
|
|
|
ZeroMemory(&(pWabSync->m_rInetServerInfo), sizeof(INETSERVER)); // Done for security
|
|
|
|
if (pWabSync->m_pOps)
|
|
{
|
|
WABSync_FreeOps(pWabSync);
|
|
Vector_Delete(pWabSync->m_pOps);
|
|
pWabSync->m_pOps = NULL;
|
|
}
|
|
|
|
if (pWabSync->m_pWabItems)
|
|
{
|
|
WABSync_FreeItems(pWabSync);
|
|
Vector_Delete(pWabSync->m_pWabItems);
|
|
}
|
|
|
|
if (pWabSync->m_pszAccountId)
|
|
CoTaskMemFree(pWabSync->m_pszAccountId);
|
|
|
|
if (pWabSync->m_pAB)
|
|
pWabSync->m_pAB->lpVtbl->Release(pWabSync->m_pAB);
|
|
|
|
if (pWabSync->m_pTransport)
|
|
IHTTPMailTransport_Release(pWabSync->m_pTransport);
|
|
|
|
if (pWabSync->m_pszRootUrl)
|
|
CoTaskMemFree(pWabSync->m_pszRootUrl);
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] If we are ending a mail contact sync, kick off a second pass
|
|
// to synchronize the group contacts.
|
|
// @review - We may want to skip group syncing if an error occurs during the
|
|
// first pass contact syncing.
|
|
if (!pWabSync->m_fSyncGroups && pWabSync->m_hParentWnd)
|
|
PostMessage(pWabSync->m_hParentWnd, WM_USER_SYNCGROUPS, 0, 0L);
|
|
#endif
|
|
|
|
LocalFree(pWabSync);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// IUnknown Members
|
|
//----------------------------------------------------------------------
|
|
HRESULT WABSync_QueryInterface (IHTTPMailCallback __RPC_FAR *lpunkobj,
|
|
REFIID riid,
|
|
LPVOID FAR * lppUnk)
|
|
{
|
|
SCODE sc;
|
|
LPWABSYNC lpWabSync = (LPWABSYNC)lpunkobj;
|
|
|
|
if (IsEqualGUID(riid, &IID_IUnknown) ||
|
|
IsEqualGUID(riid, &IID_IHTTPMailCallback) ||
|
|
IsEqualGUID(riid, &IID_ITransportCallback))
|
|
{
|
|
sc = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*lppUnk = NULL; // OLE requires zeroing [out] parameters
|
|
sc = E_NOINTERFACE;
|
|
goto error;
|
|
}
|
|
|
|
/* We found the requested interface so increment the reference count.
|
|
*/
|
|
lpWabSync ->m_cRef++;
|
|
|
|
*lppUnk = lpunkobj;
|
|
|
|
return hrSuccess;
|
|
|
|
error:
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
ULONG WABSync_AddRef(IHTTPMailCallback __RPC_FAR *This)
|
|
{
|
|
LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
return InterlockedIncrement(&pWabSync->m_cRef);
|
|
}
|
|
|
|
ULONG WABSync_Release(IHTTPMailCallback __RPC_FAR *This)
|
|
{
|
|
LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
LONG cRef = InterlockedDecrement(&pWabSync->m_cRef);
|
|
|
|
Assert(cRef >= 0);
|
|
|
|
if (0 == cRef)
|
|
WABSync_Delete(pWabSync);
|
|
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// IHTTPMailCallback Members
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP WABSync_OnTimeout (IHTTPMailCallback __RPC_FAR *This, DWORD *pdwTimeout, IInternetTransport *pTransport)
|
|
{
|
|
// LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_OnLogonPrompt (IHTTPMailCallback __RPC_FAR *This, LPINETSERVER pInetServer, IInternetTransport *pTransport)
|
|
{
|
|
LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
if (PromptUserForPassword(pInetServer, pWabSync->m_hWnd))
|
|
{
|
|
return S_OK;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP_(INT) WABSync_OnPrompt (IHTTPMailCallback __RPC_FAR *This, HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
|
|
{
|
|
// LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_OnStatus (IHTTPMailCallback __RPC_FAR *This, IXPSTATUS ixpstatus, IInternetTransport *pTransport)
|
|
{
|
|
// LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_OnError (IHTTPMailCallback __RPC_FAR *This, IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
|
|
{
|
|
// LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_OnCommand (IHTTPMailCallback __RPC_FAR *This, CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport)
|
|
{
|
|
// LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_GetParentWindow (IHTTPMailCallback __RPC_FAR *This, HWND *pHwndParent)
|
|
{
|
|
LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
|
|
*pHwndParent = pWabSync->m_hWnd;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_OnResponse (IHTTPMailCallback __RPC_FAR *This, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
LPWABSYNC pWabSync = (LPWABSYNC)This;
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert(pWabSync);
|
|
Assert(pResponse);
|
|
|
|
if (FAILED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
switch (pResponse->rIxpResult.hrResult)
|
|
{
|
|
case IXP_E_HTTP_INSUFFICIENT_STORAGE:
|
|
case IXP_E_HTTP_ROOT_PROP_NOT_FOUND:
|
|
case IXP_E_HTTP_NOT_IMPLEMENTED:
|
|
WABSync_Abort(pWabSync, pResponse->rIxpResult.hrResult);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pWabSync->m_fAborted)
|
|
return E_FAIL;
|
|
|
|
if (SYNC_STATE_SERVER_CONTACT_DISCOVERY == pWabSync->m_state)
|
|
{
|
|
if (pResponse->command == HTTPMAIL_GETPROP)
|
|
hr = WABSync_HandleContactsRootResponse(pWabSync, pResponse);
|
|
else
|
|
hr = WABSync_HandleIDListResponse(pWabSync, pResponse);
|
|
}
|
|
else if ((SYNC_STATE_PROCESS_OPS == pWabSync->m_state || SYNC_STATE_PROCESS_MERGED_CONFLICTS == pWabSync->m_state)
|
|
&& pWabSync->m_pOps)
|
|
{
|
|
LPHOTSYNCOP pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
|
|
Assert(pOp);
|
|
|
|
if (pOp)
|
|
hr = Syncop_HandleResponse(pOp, pResponse);
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
if (FAILED(hr))
|
|
WABSync_AbortOp(pWabSync, hr);
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
STDMETHODIMP WABSync_Initialize(LPWABSYNC pWabSync, HWND hWnd, IAddrBook *pAB, LPCTSTR pszAccountID, BOOL bSyncGroups)
|
|
#else
|
|
STDMETHODIMP WABSync_Initialize(LPWABSYNC pWabSync, HWND hWnd, IAddrBook *pAB, LPCTSTR pszAccountID)
|
|
#endif
|
|
{
|
|
IImnAccountManager2 *lpAcctMgr = NULL;
|
|
IImnAccount *pAccount = NULL;
|
|
HRESULT hr;
|
|
char szAcctName[CCHMAX_ACCOUNT_NAME+1];
|
|
DWORD ccb = CCHMAX_ACCOUNT_NAME;
|
|
LPSTR pszUserAgent = NULL;
|
|
#ifdef HM_GROUP_SYNCING
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
#endif
|
|
|
|
Assert(pWabSync);
|
|
Assert(pAB);
|
|
|
|
pWabSync->m_hParentWnd = hWnd;
|
|
pWabSync->m_pTransport = NULL;
|
|
pWabSync->m_fSkipped = FALSE;
|
|
#ifdef HM_GROUP_SYNCING
|
|
pWabSync->m_fSyncGroups = bSyncGroups;
|
|
#endif
|
|
|
|
pWabSync->m_hWnd = CreateDialogParam (hinstMapiX, MAKEINTRESOURCE (iddSyncProgress),
|
|
pWabSync->m_hParentWnd, SyncProgressDlgProc, (LPARAM)pWabSync);
|
|
|
|
|
|
if (!pWabSync->m_hWnd)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
ShowWindow(pWabSync->m_hWnd, SW_SHOW);
|
|
if (pWabSync->m_hParentWnd)
|
|
EnableWindow (pWabSync->m_hParentWnd, FALSE);
|
|
|
|
WABSync_BeginSynchronize(pWabSync);
|
|
|
|
InitWABUserAgent(TRUE);
|
|
|
|
if (FAILED(hr = InitAccountManager(NULL, &lpAcctMgr, NULL)))
|
|
goto exit;
|
|
|
|
if (pszAccountID == NULL)
|
|
{
|
|
if (FAILED(hr = _FindHTTPMailAccount(pWabSync->m_hWnd, lpAcctMgr, szAcctName, CCHMAX_ACCOUNT_NAME)))
|
|
goto exit;
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] We don't want the user to have to choose the HM account twice (once for contact and
|
|
// then for group syncing). So save the account ID here.
|
|
LocalFreeAndNull(&(lpPTGData->lptszHMAccountId));
|
|
lpPTGData->lptszHMAccountId = ConvertAtoW(szAcctName);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
LPSTR lpAcctA = ConvertWtoA((LPWSTR)pszAccountID);
|
|
StrCpyNA(szAcctName, lpAcctA, ARRAYSIZE(szAcctName));
|
|
LocalFreeAndNull(&lpAcctA);
|
|
}
|
|
|
|
// Get the account
|
|
hr = lpAcctMgr->lpVtbl->FindAccount(lpAcctMgr, AP_ACCOUNT_ID, szAcctName, &pAccount);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = lpAcctMgr->lpVtbl->FindAccount(lpAcctMgr, AP_ACCOUNT_NAME, szAcctName, &pAccount);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
|
|
if (SUCCEEDED(hr = pAccount->lpVtbl->GetProp(pAccount, AP_ACCOUNT_ID, szAcctName, &ccb)))
|
|
pWabSync->m_pszAccountId = _StrDup(szAcctName);
|
|
|
|
pWabSync->m_pAB = pAB;
|
|
|
|
pWabSync->m_pAB->lpVtbl->AddRef(pWabSync->m_pAB);
|
|
|
|
// Create the Transport
|
|
hr = CoCreateInstance( &CLSID_IHTTPMailTransport,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
&IID_IHTTPMailTransport,
|
|
(LPVOID *)&(pWabSync->m_pTransport));
|
|
|
|
if (FAILED(hr) || !pWabSync->m_pTransport)
|
|
goto exit;
|
|
|
|
pszUserAgent = GetWABUserAgentString();
|
|
if (!pszUserAgent)
|
|
goto exit;
|
|
|
|
// Initialize the transport
|
|
hr = IHTTPMailTransport_InitNew(pWabSync->m_pTransport, pszUserAgent, (LogTransactions(pWabSync) ? "C:\\WabSync.log" : NULL),(IHTTPMailCallback*)pWabSync);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
// Create the SERVERINFO
|
|
hr = IHTTPMailTransport_InetServerFromAccount(pWabSync->m_pTransport, pAccount, &pWabSync->m_rInetServerInfo);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
StrCpyNA(pWabSync->m_szLoginName, pWabSync->m_rInetServerInfo.szUserName, ARRAYSIZE(pWabSync->m_szLoginName));
|
|
|
|
// Check if I can connect
|
|
hr = IHTTPMailTransport_Connect(pWabSync->m_pTransport,&pWabSync->m_rInetServerInfo,TRUE,TRUE);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = WABSync_LoadLastModInfo(pWabSync);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = WABSync_BuildWabContactList(pWabSync);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
WABSync_NextState(pWabSync);
|
|
|
|
exit:
|
|
if (pszUserAgent)
|
|
LocalFree(pszUserAgent);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (pWabSync->m_pTransport)
|
|
IHTTPMailTransport_Release(pWabSync->m_pTransport);
|
|
pWabSync->m_pTransport = NULL;
|
|
WABSync_Abort(pWabSync, hr);
|
|
|
|
if (pWabSync->m_pAB)
|
|
{
|
|
pWabSync->m_pAB->lpVtbl->Release(pWabSync->m_pAB);
|
|
pWabSync->m_pAB = NULL;
|
|
}
|
|
}
|
|
|
|
// don't release the lpAcctMgr since the WAB maintains a global reference.
|
|
|
|
if (pAccount)
|
|
pAccount->lpVtbl->Release(pAccount);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// CHotSync::Abort
|
|
//
|
|
// Blow away all of the pending items in the queue.
|
|
//
|
|
STDMETHODIMP WABSync_Abort(LPWABSYNC pWabSync, HRESULT hr)
|
|
{
|
|
LPHOTSYNCOP pOp;
|
|
TCHAR szMsg[512], szCaption[255], szRes[512];
|
|
|
|
Assert(pWabSync);
|
|
|
|
pWabSync->m_fAborted = TRUE;
|
|
|
|
if (pWabSync->m_pOps)
|
|
{
|
|
DWORD dwIndex, cOps = Vector_GetLength(pWabSync->m_pOps);
|
|
|
|
for (dwIndex = 0; dwIndex < cOps; ++dwIndex)
|
|
{
|
|
pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
|
|
|
|
if (pOp)
|
|
{
|
|
Syncop_Abort(pOp);
|
|
Syncop_Delete(pOp);
|
|
}
|
|
|
|
Vector_RemoveItem(pWabSync->m_pOps, 0);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr) && hr != E_UserCancel)
|
|
{
|
|
switch (hr)
|
|
{
|
|
case IXP_E_HTTP_INSUFFICIENT_STORAGE:
|
|
LoadString(hinstMapiX, idsOutOfServerSpace, szMsg, CharSizeOf(szMsg));
|
|
break;
|
|
|
|
case IXP_E_HTTP_ROOT_PROP_NOT_FOUND:
|
|
case IXP_E_HTTP_NOT_IMPLEMENTED:
|
|
LoadString(hinstMapiX, idsSyncNotHandled, szMsg, CharSizeOf(szMsg));
|
|
break;
|
|
|
|
default:
|
|
LoadString(hinstMapiX, idsSyncAborted, szRes, CharSizeOf(szRes));
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, hr);
|
|
break;
|
|
}
|
|
LoadString(hinstMapiX, idsSyncError, szCaption, CharSizeOf(szCaption));
|
|
MessageBox(pWabSync->m_hWnd, szMsg, szCaption, MB_ICONEXCLAMATION | MB_OK);
|
|
}
|
|
|
|
WABSync_FinishSynchronize(pWabSync, hr);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// CHotSync::AbortOp
|
|
//
|
|
// Abort the current operation (for some reason)
|
|
//
|
|
STDMETHODIMP WABSync_AbortOp(LPWABSYNC pWabSync, HRESULT hr)
|
|
{
|
|
LPHOTSYNCOP pOp;
|
|
|
|
Assert(pWabSync);
|
|
|
|
pWabSync->m_cAborts++;
|
|
|
|
// do something with the knowledge of this abort (log to whatever)
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
int __cdecl CompareOpTypes(const void* lpvA, const void* lpvB)
|
|
{
|
|
LPHOTSYNCOP pSyncOpA;
|
|
LPHOTSYNCOP pSyncOpB;
|
|
|
|
pSyncOpA = *((LPHOTSYNCOP*)lpvA);
|
|
pSyncOpB = *((LPHOTSYNCOP*)lpvB);
|
|
|
|
return (pSyncOpA->m_bOpType - pSyncOpB->m_bOpType);
|
|
}
|
|
|
|
|
|
STDMETHODIMP WABSync_RequestContactsRootProperty(LPWABSYNC pWabSync)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(pWabSync);
|
|
Assert(pWabSync->m_pTransport);
|
|
|
|
hr = pWabSync->m_pTransport->lpVtbl->GetProperty(pWabSync->m_pTransport, HTTPMAIL_PROP_CONTACTS, &pWabSync->m_pszRootUrl);
|
|
|
|
if(hr == E_PENDING)
|
|
hr = S_OK;
|
|
else if (SUCCEEDED(hr) && pWabSync->m_pszRootUrl)
|
|
WABSync_RequestServerIDList(pWabSync);
|
|
else
|
|
WABSync_Abort(pWabSync, hr); //something went terribly wrong
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_HandleContactsRootResponse(LPWABSYNC pWabSync, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
Assert(pWabSync);
|
|
|
|
pWabSync->m_pszRootUrl = NULL;
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
if (pResponse->rGetPropInfo.type == HTTPMAIL_PROP_CONTACTS)
|
|
{
|
|
pWabSync->m_pszRootUrl = pResponse->rGetPropInfo.pszProp;
|
|
pResponse->rGetPropInfo.pszProp = NULL;
|
|
}
|
|
}
|
|
|
|
if (pWabSync->m_pszRootUrl)
|
|
WABSync_RequestServerIDList(pWabSync);
|
|
else
|
|
WABSync_Abort(pWabSync, pResponse->rIxpResult.hrResult);
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_RequestServerIDList(LPWABSYNC pWabSync)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(pWabSync);
|
|
Assert(pWabSync->m_pTransport);
|
|
Assert(pWabSync->m_pszRootUrl && *pWabSync->m_pszRootUrl);
|
|
|
|
WABSync_Progress(pWabSync, idsSyncGathering, -1);
|
|
|
|
hr = pWabSync->m_pTransport->lpVtbl->ListContactInfos(pWabSync->m_pTransport, pWabSync->m_pszRootUrl, 0);
|
|
|
|
if FAILED(hr)
|
|
WABSync_Abort(pWabSync, hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_FindContactByServerId(LPWABSYNC pWabSync, LPSTR pszServerId, LPWABCONTACTINFO *ppContact, DWORD *pdwIndex)
|
|
{
|
|
DWORD cItems, dwIndex;
|
|
LPWABCONTACTINFO pContact;
|
|
|
|
Assert(pWabSync);
|
|
Assert(pWabSync->m_pWabItems);
|
|
|
|
cItems = Vector_GetLength(pWabSync->m_pWabItems);
|
|
|
|
for (dwIndex = 0; dwIndex < cItems; dwIndex++)
|
|
{
|
|
pContact = (LPWABCONTACTINFO)Vector_GetItem(pWabSync->m_pWabItems, dwIndex);
|
|
|
|
if (pContact && pContact->pszHotmailId && lstrcmpA(pContact->pszHotmailId, pszServerId) == 0)
|
|
{
|
|
*ppContact = pContact;
|
|
*pdwIndex = dwIndex;
|
|
return S_OK;
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_HandleIDListResponse(LPWABSYNC pWabSync, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr;
|
|
LPHOTSYNCOP pNewOp;
|
|
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
ULONG cItems = pResponse->rContactInfoList.cContactInfo;
|
|
LPHTTPCONTACTINFO prgId = pResponse->rContactInfoList.prgContactInfo;
|
|
DWORD dwItem;
|
|
|
|
for (dwItem = 0; dwItem < cItems; dwItem++)
|
|
{
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] We synchronize contacts and groups separately
|
|
if ( (!pWabSync->m_fSyncGroups && (prgId[dwItem].tyContact == HTTPMAIL_CT_CONTACT)) ||
|
|
(pWabSync->m_fSyncGroups && (prgId[dwItem].tyContact == HTTPMAIL_CT_GROUP)) )
|
|
#else
|
|
if (HTTPMAIL_CT_GROUP == prgId[dwItem].tyContact)
|
|
{
|
|
// ignore groups for now
|
|
continue;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
LPWABCONTACTINFO pContact;
|
|
DWORD dwIndex;
|
|
FILETIME ftModTime = {0,0};
|
|
|
|
pNewOp = NULL;
|
|
// [PaulHi] 12/17/98 Raid #61548
|
|
// The Exchange server will pass in contacts with no file mod time,
|
|
// which really hoses the sync process. We could just skip these
|
|
// contacts but to keep things simple we abort the sync process here.
|
|
// Note that HotMail servers work correctly.
|
|
//
|
|
// @todo [PaulHi]
|
|
// After IE5 ship of WAB, fix this by creating a conflict op code and
|
|
// let user straighten out any differences. Also time stamp so future
|
|
// syncs will work.
|
|
hr = iso8601ToFileTime(prgId[dwItem].pszModified, &ftModTime, TRUE, TRUE);
|
|
if (FAILED(hr))
|
|
{
|
|
WABSync_Abort(pWabSync, hr);
|
|
return hr;
|
|
}
|
|
|
|
if (SUCCEEDED(WABSync_FindContactByServerId(pWabSync, prgId[dwItem].pszId, &pContact, &dwIndex)))
|
|
{
|
|
if (pContact->fDelete)
|
|
{
|
|
// it has been deleted from the wab. Now delete it from the server.
|
|
pContact->pszHotmailHref = prgId[dwItem].pszHref;
|
|
prgId[dwItem].pszHref = NULL;
|
|
|
|
pContact->pszModHotmail = prgId[dwItem].pszModified;
|
|
prgId[dwItem].pszModified = NULL;
|
|
|
|
pNewOp = Syncop_CreateServerDelete(pContact);
|
|
}
|
|
else
|
|
{
|
|
LONG lLocalCompare = CompareFileTime(&pWabSync->m_ftLastSync, &pContact->ftModWab);
|
|
LONG lServerCompare = pContact->pszModHotmail && prgId[dwItem].pszModified ? lstrcmpA(pContact->pszModHotmail, prgId[dwItem].pszModified) : -1;
|
|
|
|
SafeCoMemFree(pContact->pszHotmailHref);
|
|
pContact->pszHotmailHref = prgId[dwItem].pszHref;
|
|
prgId[dwItem].pszHref = NULL;
|
|
|
|
SafeCoMemFree(pContact->pszHotmailId);
|
|
pContact->pszHotmailId = prgId[dwItem].pszId;
|
|
prgId[dwItem].pszId = NULL;
|
|
|
|
SafeCoMemFree(pContact->pszModHotmail);
|
|
pContact->pszModHotmail = prgId[dwItem].pszModified;
|
|
prgId[dwItem].pszModified = NULL;
|
|
|
|
if (lLocalCompare >= 0)
|
|
{
|
|
// hasn't changed locally since last sync
|
|
|
|
if (lServerCompare)
|
|
{
|
|
// has changed on server, just update here
|
|
pNewOp = Syncop_CreateClientChange(pContact);
|
|
Assert(pNewOp);
|
|
Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
|
|
}
|
|
else
|
|
{
|
|
// hasn't changed anywhere. do nothing.
|
|
WABContact_Delete(pContact);
|
|
pContact = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// has changed locally.
|
|
|
|
if (lServerCompare)
|
|
{
|
|
// has changed on server, CONFLICT
|
|
pNewOp = Syncop_CreateConflict(pContact);
|
|
Assert(pNewOp);
|
|
Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
|
|
}
|
|
else
|
|
{
|
|
// Local change only, upload changes
|
|
pNewOp = Syncop_CreateServerChange(pContact);
|
|
Assert(pNewOp);
|
|
Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//remove the contact from the list of local contacts
|
|
Vector_RemoveItem(pWabSync->m_pWabItems, dwIndex);
|
|
}
|
|
else
|
|
{
|
|
// its not in the WAB, we need to add it there.
|
|
pContact = LocalAlloc(LMEM_ZEROINIT, sizeof(WABCONTACTINFO));
|
|
Assert(pContact);
|
|
|
|
if (pContact)
|
|
{
|
|
pContact->pszHotmailHref = prgId[dwItem].pszHref;
|
|
prgId[dwItem].pszHref = NULL;
|
|
|
|
pContact->pszHotmailId = prgId[dwItem].pszId;
|
|
prgId[dwItem].pszId = NULL;
|
|
|
|
pContact->pszModHotmail = prgId[dwItem].pszModified;
|
|
prgId[dwItem].pszModified = NULL;
|
|
|
|
pNewOp = Syncop_CreateClientAdd(pContact);
|
|
Assert(pNewOp);
|
|
Syncop_SetServerContactInfo(pNewOp, pContact, &prgId[dwItem]);
|
|
}
|
|
}
|
|
|
|
if (pNewOp)
|
|
{
|
|
Syncop_Init(pNewOp, (IHTTPMailCallback *)pWabSync, pWabSync->m_pTransport);
|
|
hr = Vector_AddItem(pWabSync->m_pOps, pNewOp);
|
|
}
|
|
else
|
|
{
|
|
if (pContact)
|
|
WABContact_Delete(pContact);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (pResponse->fDone)
|
|
{
|
|
//everything left in the contact list needs to either
|
|
//be added to the server or deleted locally.
|
|
LONG cItems, dwIndex;
|
|
LPWABCONTACTINFO pContact;
|
|
|
|
Assert(pWabSync->m_pWabItems);
|
|
|
|
cItems = Vector_GetLength(pWabSync->m_pWabItems);
|
|
|
|
if (cItems > 0)
|
|
{
|
|
for (dwIndex = cItems - 1; dwIndex >= 0; dwIndex--)
|
|
{
|
|
pNewOp = NULL;
|
|
pContact = (LPWABCONTACTINFO)Vector_GetItem(pWabSync->m_pWabItems, dwIndex);
|
|
|
|
if (pContact && pContact->pszHotmailId)
|
|
{
|
|
if (pContact->fDelete)
|
|
{
|
|
TCHAR tszServerId[MAX_PATH];
|
|
TCHAR tszKey[MAX_PATH];
|
|
HKEY hkey;
|
|
// now that the delete has completed, delete the tombstone from the registry.
|
|
hr = hrMakeContactId(
|
|
tszServerId,
|
|
MAX_PATH,
|
|
((LPIAB)(pWabSync->m_pAB))->szProfileID,
|
|
pWabSync->m_pszAccountId,
|
|
pWabSync->m_szLoginName);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
wnsprintf(tszKey, ARRAYSIZE(tszKey), TEXT("%s%s"), g_lpszSyncKey, tszServerId);
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tszKey, 0, KEY_SET_VALUE, &hkey))
|
|
{
|
|
LPTSTR lpKey =
|
|
ConvertAtoW(pContact->pszHotmailId);
|
|
RegDeleteValue(hkey, lpKey);
|
|
LocalFreeAndNull(&lpKey);
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//needs to be deleted locally
|
|
pNewOp = Syncop_CreateClientDelete(pContact);
|
|
}
|
|
}
|
|
else if (pContact)
|
|
{
|
|
//needs to be added remotely
|
|
pNewOp = Syncop_CreateServerAdd(pContact);
|
|
}
|
|
|
|
if (pNewOp)
|
|
{
|
|
//remove the contact from the list of local contacts
|
|
Vector_RemoveItem(pWabSync->m_pWabItems, dwIndex);
|
|
Syncop_Init(pNewOp, (IHTTPMailCallback *)pWabSync, pWabSync->m_pTransport);
|
|
hr = Vector_AddItem(pWabSync->m_pOps, pNewOp);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
WABSync_MergeAddsToConflicts(pWabSync);
|
|
|
|
pWabSync->m_cTotalOps = Vector_GetLength(pWabSync->m_pOps);
|
|
|
|
Vector_Sort(pWabSync->m_pOps, CompareOpTypes);
|
|
|
|
//Now go on to handling the operations
|
|
WABSync_NextState(pWabSync);
|
|
}
|
|
}
|
|
else
|
|
WABSync_Abort(pWabSync, pResponse->rIxpResult.hrResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_OperationCompleted(LPWABSYNC pWabSync, LPHOTSYNCOP pOp)
|
|
{
|
|
Assert(pWabSync->m_pOps);
|
|
Assert(pOp == Vector_GetItem(pWabSync->m_pOps, 0)); //completing op should be first op in the list
|
|
|
|
Syncop_Delete(pOp);
|
|
Vector_RemoveItem(pWabSync->m_pOps, 0);
|
|
|
|
// get the next operation and start it running.
|
|
// if there are no more operations, go to the next state
|
|
pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
|
|
if (pOp)
|
|
Syncop_Begin(pOp);
|
|
else
|
|
WABSync_NextState(pWabSync);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP WABSync_BeginSynchronize(LPWABSYNC pWabSync)
|
|
{
|
|
//Keep a reference to ourself while the UI is shown
|
|
WABSync_AddRef((IHTTPMailCallback *)pWabSync);
|
|
|
|
// begin ui
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP WABSync_FinishSynchronize(LPWABSYNC pWabSync, HRESULT hr)
|
|
{
|
|
// if there were any failures or the user didn't resolve all of the
|
|
// conflicts, then don't update the mod info so we have to do it again.
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Don't store the current mod time until the synchronization
|
|
// process is completely through, meaning that we are ending the second
|
|
// group contact syncing pass
|
|
if (SUCCEEDED(hr) && !pWabSync->m_fSkipped && pWabSync->m_fSyncGroups)
|
|
#else
|
|
if (SUCCEEDED(hr) && !pWabSync->m_fSkipped)
|
|
#endif
|
|
WABSync_SaveCurrentModInfo(pWabSync);
|
|
else if (!pWabSync->m_fAborted && FAILED(hr))
|
|
{
|
|
TCHAR szMsg[512], szCaption[255];
|
|
|
|
LoadString(hinstMapiX, idsSyncFailed, szMsg, CharSizeOf(szMsg));
|
|
LoadString(hinstMapiX, idsSyncError, szCaption, CharSizeOf(szCaption));
|
|
|
|
MessageBox(pWabSync->m_hWnd, szMsg, szCaption, MB_ICONEXCLAMATION | MB_OK);
|
|
}
|
|
|
|
if (pWabSync->m_pTransport)
|
|
{
|
|
IHTTPMailTransport_Release(pWabSync->m_pTransport);
|
|
pWabSync->m_pTransport = NULL;
|
|
}
|
|
|
|
if (pWabSync->m_hWnd)
|
|
{
|
|
if (pWabSync->m_hParentWnd)
|
|
EnableWindow (pWabSync->m_hParentWnd, TRUE);
|
|
|
|
DestroyWindow(pWabSync->m_hWnd);
|
|
pWabSync->m_hWnd = NULL;
|
|
}
|
|
InitWABUserAgent(FALSE);
|
|
|
|
WABSync_Release((IHTTPMailCallback *)pWabSync);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void WABSync_CheckForLocalDeletions(LPWABSYNC pWabSync)
|
|
{
|
|
TCHAR tszKey[MAX_PATH], tszId[MAX_PATH];
|
|
TCHAR tszServerId[MAX_PATH];
|
|
DWORD dwType = 0;
|
|
DWORD dwValue = 0;
|
|
HKEY hkey = NULL;
|
|
DWORD dwSize;
|
|
HRESULT hr = E_FAIL;
|
|
DWORD cRecords, i, cb, lResult;
|
|
|
|
Assert(pWabSync);
|
|
Assert(*pWabSync->m_szLoginName);
|
|
|
|
// [PaulHi] Assemble the contact ID string
|
|
if ( FAILED(hrMakeContactId(
|
|
tszServerId,
|
|
MAX_PATH,
|
|
((LPIAB)(pWabSync->m_pAB))->szProfileID,
|
|
pWabSync->m_pszAccountId,
|
|
pWabSync->m_szLoginName)) )
|
|
{
|
|
return;
|
|
}
|
|
wnsprintf(tszKey, ARRAYSIZE(tszKey), TEXT("%s%s"), g_lpszSyncKey, tszServerId);
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tszKey, 0, KEY_READ, &hkey))
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, 0, NULL, NULL, NULL, &cRecords, NULL, NULL, NULL, NULL) &&
|
|
cRecords > 0)
|
|
{
|
|
// Start Enumerating the keys
|
|
for (i = 0; i < cRecords; i++)
|
|
{
|
|
// Enumerate Friendly Names
|
|
cb = CharSizeOf(tszId);
|
|
lResult = RegEnumValue(hkey, i, tszId, &cb, 0, NULL, NULL, NULL);
|
|
|
|
if (ERROR_SUCCESS == lResult && *tszId)
|
|
{
|
|
WABCONTACTINFO *lpWCI;
|
|
|
|
lpWCI = LocalAlloc(LMEM_ZEROINIT, sizeof(WABCONTACTINFO));
|
|
|
|
if (!lpWCI)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
DebugPrintError(( TEXT("WABCONTACTINFO Alloc Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
lpWCI->fDelete = TRUE;
|
|
|
|
{
|
|
LPSTR lpID =
|
|
ConvertWtoA(tszId);
|
|
lpWCI->pszHotmailId = _StrDup(lpID);
|
|
LocalFreeAndNull(&lpID);
|
|
}
|
|
if (FAILED(Vector_AddItem(pWabSync->m_pWabItems, lpWCI)))
|
|
goto out;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
out:
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
STDMETHODIMP WABSync_BuildWabContactList(LPWABSYNC pWabSync)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulObjType;
|
|
LPENTRYID pEntryID = NULL;
|
|
ULONG cbEntryID = 0;
|
|
LPABCONT lpContainer = NULL;
|
|
ULONG ulObjectType;
|
|
LPMAPITABLE lpABTable = NULL;
|
|
LPSRowSet lpRowAB = NULL;
|
|
int cNumRows = 0;
|
|
int nRows=0;
|
|
|
|
Assert(pWabSync->m_pAB);
|
|
|
|
Vector_Create(&pWabSync->m_pOps);
|
|
if (pWabSync->m_pOps == NULL)
|
|
{
|
|
WABSync_Abort(pWabSync, E_OUTOFMEMORY);
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
Vector_Create(&pWabSync->m_pWabItems);
|
|
if (pWabSync->m_pWabItems == NULL)
|
|
{
|
|
WABSync_Abort(pWabSync, E_OUTOFMEMORY);
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
WABSync_CheckForLocalDeletions(pWabSync);
|
|
|
|
if (HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->GetPAB(pWabSync->m_pAB, &cbEntryID, &pEntryID)))
|
|
{
|
|
DebugPrintError(( TEXT("GetPAB Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, // size of EntryID to open
|
|
pEntryID, // EntryID to open
|
|
NULL, // interface
|
|
0, // flags
|
|
&ulObjType,
|
|
(LPUNKNOWN *)&lpContainer);
|
|
|
|
MAPIFreeBuffer(pEntryID);
|
|
|
|
pEntryID = NULL;
|
|
|
|
if (HR_FAILED(hr))
|
|
{
|
|
DebugPrintError(( TEXT("OpenEntry Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
if (HR_FAILED(hr = lpContainer->lpVtbl->GetContentsTable(lpContainer, MAPI_UNICODE | WAB_PROFILE_CONTENTS, &lpABTable)))
|
|
{
|
|
DebugPrintError(( TEXT("GetContentsTable Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
hr = lpABTable->lpVtbl->SetColumns(lpABTable, (LPSPropTagArray)&ptaEidSync, 0 );
|
|
|
|
if(HR_FAILED(hr))
|
|
goto out;
|
|
|
|
// Reset to the beginning of the table
|
|
//
|
|
hr = lpABTable->lpVtbl->SeekRow(lpABTable, BOOKMARK_BEGINNING, 0, NULL );
|
|
|
|
if(HR_FAILED(hr))
|
|
goto out;
|
|
|
|
// Read all the rows of the table one by one
|
|
//
|
|
do {
|
|
|
|
hr = lpABTable->lpVtbl->QueryRows(lpABTable, 1, 0, &lpRowAB);
|
|
|
|
if(HR_FAILED(hr))
|
|
break;
|
|
|
|
if(lpRowAB)
|
|
{
|
|
cNumRows = lpRowAB->cRows;
|
|
|
|
if (cNumRows)
|
|
{
|
|
LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieid_PR_DISPLAY_NAME].Value.LPSZ;
|
|
LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieid_PR_ENTRYID].Value.bin.lpb;
|
|
ULONG cbEID = lpRowAB->aRow[0].lpProps[ieid_PR_ENTRYID].Value.bin.cb;
|
|
|
|
//
|
|
// There are 2 kinds of objects - the MAPI_MAILUSER contact object
|
|
// and the MAPI_DISTLIST contact object
|
|
//
|
|
#ifdef HM_GROUP_SYNCING
|
|
if( (!pWabSync->m_fSyncGroups && (lpRowAB->aRow[0].lpProps[ieid_PR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)) ||
|
|
(pWabSync->m_fSyncGroups && (lpRowAB->aRow[0].lpProps[ieid_PR_OBJECT_TYPE].Value.l == MAPI_DISTLIST)) )
|
|
#else
|
|
// Only consider MAILUSER objects
|
|
if (lpRowAB->aRow[0].lpProps[ieid_PR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
|
|
#endif
|
|
{
|
|
WABCONTACTINFO *lpWCI;
|
|
HTTPCONTACTINFO hci;
|
|
|
|
lpWCI = LocalAlloc(LMEM_ZEROINIT, sizeof(WABCONTACTINFO));
|
|
|
|
if (!lpWCI)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
DebugPrintError(( TEXT("WABCONTACTINFO Alloc Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
lpWCI->lpEID = LocalAlloc(LMEM_ZEROINIT, cbEID);
|
|
|
|
if (!lpWCI->lpEID)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
DebugPrintError(( TEXT("WABCONTACTINFO.ENTRYID Alloc Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
lpWCI->cbEID = cbEID;
|
|
CopyMemory(lpWCI->lpEID, lpEID, cbEID);
|
|
|
|
lpWCI->ftModWab = lpRowAB->aRow[0].lpProps[ieid_PR_LAST_MODIFICATION_TIME].Value.ft;
|
|
|
|
lpWCI->pszHotmailId = NULL;
|
|
lpWCI->pszModHotmail = NULL;
|
|
|
|
if (SUCCEEDED(ContactInfo_LoadFromWAB(pWabSync, &hci, lpWCI, lpEID, cbEID)))
|
|
{
|
|
lpWCI->pszHotmailId = _StrDup(hci.pszId);
|
|
lpWCI->pszModHotmail = _StrDup(hci.pszModified);
|
|
ContactInfo_Free(&hci);
|
|
}
|
|
|
|
// search the multi value list of longs for the proper server id. If found,
|
|
// then get the appropriate hotmail id and mod id.
|
|
|
|
if (FAILED(Vector_AddItem(pWabSync->m_pWabItems, lpWCI)))
|
|
goto out;
|
|
}
|
|
}
|
|
FreeProws(lpRowAB );
|
|
}
|
|
|
|
}while ( SUCCEEDED(hr) && cNumRows && lpRowAB) ;
|
|
|
|
|
|
out:
|
|
if (HR_FAILED(hr))
|
|
{
|
|
if (pWabSync->m_pWabItems)
|
|
WABSync_FreeItems(pWabSync);
|
|
if (lpContainer)
|
|
lpContainer->lpVtbl->Release(lpContainer);
|
|
if (lpABTable)
|
|
lpABTable->lpVtbl->Release(lpABTable);
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT WABSync_LoadLastModInfo(LPWABSYNC pWabSync)
|
|
{
|
|
TCHAR szKey[MAX_PATH];
|
|
DWORD dwType = 0;
|
|
DWORD dwValue = 0;
|
|
HKEY hKey = NULL;
|
|
DWORD dwSize;
|
|
HRESULT hr = E_FAIL;
|
|
FILETIME ftValue;
|
|
|
|
Assert(pWabSync);
|
|
Assert(*pWabSync->m_szLoginName);
|
|
|
|
StrCpyN(szKey, g_lpszSyncKey, ARRAYSIZE(szKey));
|
|
#ifndef UNICODE
|
|
StrCatBuff(szKey, pWabSync->m_szLoginName, ARRAYSIZE(szKey));
|
|
#else
|
|
{
|
|
LPTSTR lpName = ConvertAtoW(pWabSync->m_szLoginName);
|
|
StrCatBuff(szKey, lpName, ARRAYSIZE(szKey));
|
|
LocalFreeAndNull(&lpName);
|
|
}
|
|
#endif
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_READ, &hKey))
|
|
{
|
|
dwSize = sizeof(DWORD);
|
|
hr = RegQueryValueEx( hKey, TEXT("Server ID"), NULL, &dwType, (LPBYTE) &dwValue, &dwSize);
|
|
if (dwValue && ERROR_SUCCESS == hr)
|
|
{
|
|
pWabSync->m_dwServerID = dwValue;
|
|
}
|
|
else
|
|
goto fail;
|
|
|
|
dwSize = sizeof(FILETIME);
|
|
if (ERROR_SUCCESS == (hr = RegQueryValueEx( hKey, TEXT("Server Last Sync"), NULL, &dwType, (LPBYTE) &ftValue, &dwSize)))
|
|
{
|
|
pWabSync->m_ftLastSync = ftValue;
|
|
}
|
|
else
|
|
goto fail;
|
|
}
|
|
else
|
|
{
|
|
// the key for this user account isn't there.
|
|
// create a new one and return default values.
|
|
|
|
// a random number would be nice here, instead we will
|
|
// use the low DWORD of a date time....
|
|
GetSystemTimeAsFileTime(&ftValue);
|
|
pWabSync->m_dwServerID = ftValue.dwLowDateTime;
|
|
|
|
// NULL filetime since we haven't synced yet, everything is after the last sync
|
|
ZeroMemory(&pWabSync->m_ftLastSync, sizeof(FILETIME));
|
|
|
|
hr = WABSync_SaveCurrentModInfo(pWabSync);
|
|
}
|
|
|
|
fail:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT WABSync_SaveCurrentModInfo(LPWABSYNC pWabSync)
|
|
{
|
|
TCHAR szKey[MAX_PATH];
|
|
HKEY hKey = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
Assert(pWabSync);
|
|
Assert(*pWabSync->m_szLoginName);
|
|
|
|
StrCpyN(szKey, g_lpszSyncKey, ARRAYSIZE(szKey));
|
|
|
|
{
|
|
LPTSTR lpName = ConvertAtoW(pWabSync->m_szLoginName);
|
|
StrCatBuff(szKey, lpName, ARRAYSIZE(szKey));
|
|
LocalFreeAndNull(&lpName);
|
|
}
|
|
|
|
|
|
if(ERROR_SUCCESS == ( hr = RegCreateKey(HKEY_CURRENT_USER, szKey, &hKey)))
|
|
{
|
|
GetSystemTimeAsFileTime(&pWabSync->m_ftLastSync);
|
|
|
|
hr = RegSetValueEx( hKey, TEXT("Server ID"), 0, REG_DWORD, (BYTE *)&pWabSync->m_dwServerID, sizeof(DWORD));
|
|
hr = RegSetValueEx( hKey, TEXT("Server Last Sync"), 0, REG_BINARY, (BYTE *)&pWabSync->m_ftLastSync, sizeof(FILETIME));
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void WABSync_Progress(LPWABSYNC pWabSync, DWORD dwResId, DWORD dwCount)
|
|
{
|
|
TCHAR szRes[MAX_PATH], szMsg[MAX_PATH];
|
|
HWND hwndText;
|
|
|
|
LoadString(hinstMapiX, dwResId, szRes, CharSizeOf(szRes));
|
|
if (dwCount != -1)
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, dwCount);
|
|
else
|
|
StrCpyN(szMsg, szRes, ARRAYSIZE(szMsg));
|
|
|
|
hwndText = GetDlgItem(pWabSync->m_hWnd, IDC_SYNC_MSG);
|
|
if (hwndText)
|
|
{
|
|
SetWindowText(hwndText, szMsg);
|
|
}
|
|
|
|
SendDlgItemMessage(pWabSync->m_hWnd, IDC_SYNC_PROGBAR, PBM_SETRANGE, 0, MAKELPARAM(0, pWabSync->m_cTotalOps));
|
|
SendDlgItemMessage(pWabSync->m_hWnd, IDC_SYNC_PROGBAR, PBM_SETPOS, pWabSync->m_cTotalOps - dwCount, 0);
|
|
}
|
|
|
|
void WABSync_NextState(LPWABSYNC pWabSync)
|
|
{
|
|
PostMessage(pWabSync->m_hWnd, WM_SYNC_NEXTSTATE, 0, (LPARAM)pWabSync);
|
|
}
|
|
|
|
void _WABSync_NextState(LPWABSYNC pWabSync)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(pWabSync);
|
|
|
|
pWabSync->m_state++;
|
|
|
|
switch(pWabSync->m_state)
|
|
{
|
|
case SYNC_STATE_SERVER_CONTACT_DISCOVERY:
|
|
WABSync_Progress(pWabSync, idsSyncConnecting, -1);
|
|
hr = WABSync_RequestContactsRootProperty(pWabSync);
|
|
break;
|
|
|
|
case SYNC_STATE_PROCESS_OPS:
|
|
WABSync_Progress(pWabSync, idsSyncSynchronizing, Vector_GetLength(pWabSync->m_pOps));
|
|
if (pWabSync->m_pOps && Vector_GetLength(pWabSync->m_pOps) > 0)
|
|
{
|
|
if (WABSync_NextOp(pWabSync, FALSE))
|
|
return;
|
|
}
|
|
// fall through if there are no ops
|
|
pWabSync->m_state++;
|
|
|
|
case SYNC_STATE_PROCESS_CONFLICTS:
|
|
WABSync_Progress(pWabSync, idsSyncConflicts, Vector_GetLength(pWabSync->m_pOps));
|
|
if (pWabSync->m_pOps && Vector_GetLength(pWabSync->m_pOps) > 0)
|
|
{
|
|
if(SUCCEEDED(WABSync_DoConflicts(pWabSync)))
|
|
return;
|
|
}
|
|
// fall through if there are no ops
|
|
pWabSync->m_state++;
|
|
if (pWabSync->m_fAborted)
|
|
return;
|
|
|
|
case SYNC_STATE_PROCESS_MERGED_CONFLICTS:
|
|
WABSync_Progress(pWabSync, idsSyncFinishing, Vector_GetLength(pWabSync->m_pOps));
|
|
if (pWabSync->m_pOps && Vector_GetLength(pWabSync->m_pOps) > 0)
|
|
{
|
|
if (WABSync_NextOp(pWabSync, FALSE))
|
|
return;
|
|
}
|
|
// fall through if there are no ops
|
|
pWabSync->m_state++;
|
|
|
|
case SYNC_STATE_DONE:
|
|
WABSync_FinishSynchronize(pWabSync, (pWabSync->m_cAborts == 0 ? S_OK : E_FAIL));
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL _WABSync_NextOp(LPWABSYNC pWabSync, BOOL fPopFirst)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPHOTSYNCOP pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
|
|
|
|
Assert(pWabSync->m_state == SYNC_STATE_PROCESS_OPS || pWabSync->m_state == SYNC_STATE_PROCESS_MERGED_CONFLICTS);
|
|
Assert(pOp);
|
|
|
|
if (pOp && fPopFirst)
|
|
{
|
|
LPVECTOR pVector;
|
|
pVector = pWabSync->m_pOps;
|
|
Assert(pVector);
|
|
Vector_Remove(pVector, pOp);
|
|
Syncop_Delete(pOp);
|
|
pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
|
|
}
|
|
|
|
if (pWabSync->m_state == SYNC_STATE_PROCESS_OPS)
|
|
WABSync_Progress(pWabSync, idsSyncSynchronizing, Vector_GetLength(pWabSync->m_pOps));
|
|
else if (pWabSync->m_state == SYNC_STATE_PROCESS_MERGED_CONFLICTS)
|
|
WABSync_Progress(pWabSync, idsSyncFinishing, Vector_GetLength(pWabSync->m_pOps));
|
|
|
|
if (pOp)
|
|
hr = Syncop_Begin(pOp);
|
|
|
|
return (SUCCEEDED(hr));
|
|
}
|
|
|
|
BOOL WABSync_NextOp(LPWABSYNC pWabSync, BOOL fPopFirst)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPHOTSYNCOP pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, 0);
|
|
|
|
if (!pOp)
|
|
return FALSE;
|
|
PostMessage(pWabSync->m_hWnd, WM_SYNC_NEXTOP, fPopFirst, (LPARAM)pWabSync);
|
|
return TRUE;
|
|
}
|
|
|
|
void WABSync_FreeOps(LPWABSYNC pWabSync)
|
|
{
|
|
LPHOTSYNCOP pOp;
|
|
|
|
if (pWabSync->m_pOps)
|
|
{
|
|
LONG dwIndex, cItems = Vector_GetLength(pWabSync->m_pOps);
|
|
|
|
for (dwIndex = cItems - 1; dwIndex >= 0; --dwIndex)
|
|
{
|
|
pOp = (LPHOTSYNCOP)Vector_GetItem(pWabSync->m_pOps, dwIndex);
|
|
|
|
if (pOp)
|
|
{
|
|
Vector_RemoveItem(pWabSync->m_pOps, dwIndex);
|
|
Syncop_Abort(pOp);
|
|
Syncop_Delete(pOp);
|
|
}
|
|
|
|
if (dwIndex == 0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void WABSync_FreeItems(LPWABSYNC pWabSync)
|
|
{
|
|
LPWABCONTACTINFO lprWCI;
|
|
|
|
if (pWabSync->m_pWabItems)
|
|
{
|
|
LONG dwIndex, cItems = Vector_GetLength(pWabSync->m_pWabItems);
|
|
|
|
for (dwIndex = cItems - 1; dwIndex >= 0; --dwIndex)
|
|
{
|
|
lprWCI = (LPWABCONTACTINFO)Vector_GetItem(pWabSync->m_pWabItems, dwIndex);
|
|
|
|
if (lprWCI)
|
|
{
|
|
if (lprWCI->lpEID)
|
|
LocalFree(lprWCI->lpEID);
|
|
LocalFree(lprWCI);
|
|
}
|
|
|
|
Vector_RemoveItem(pWabSync->m_pWabItems, dwIndex);
|
|
|
|
if (dwIndex == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
HRESULT WABSync_DoConflicts(LPWABSYNC pWabSync)
|
|
{
|
|
LONG dwIndex, cConflicts = 0, cItems = Vector_GetLength(pWabSync->m_pOps);
|
|
LPHOTSYNCOP pOp;
|
|
LPHTTPCONFLICTINFO pConflicts = NULL;
|
|
if (cItems == 0)
|
|
{
|
|
WABSync_NextState(pWabSync);
|
|
return S_OK;
|
|
}
|
|
|
|
pConflicts = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONFLICTINFO) * cItems);
|
|
if (!pConflicts)
|
|
return E_OUTOFMEMORY;
|
|
|
|
for (dwIndex = 0; dwIndex < cItems; dwIndex++)
|
|
{
|
|
pOp = Vector_GetItem(pWabSync->m_pOps, dwIndex);
|
|
Assert(pOp->m_bOpType == SYNCOP_CONFLICT);
|
|
|
|
if (!pOp || pOp->m_bOpType != SYNCOP_CONFLICT)
|
|
continue;
|
|
|
|
Assert(pOp->m_pServerContact);
|
|
Assert(pOp->m_pClientContact);
|
|
|
|
pConflicts[dwIndex].pciServer = pOp->m_pServerContact;
|
|
pConflicts[dwIndex].pciClient = pOp->m_pClientContact;
|
|
cConflicts++;
|
|
}
|
|
|
|
if (ResolveConflicts(pWabSync->m_hParentWnd, pConflicts, cConflicts))
|
|
{
|
|
HRESULT hr = S_OK;
|
|
for (dwIndex = 0; dwIndex < cConflicts; dwIndex++)
|
|
{
|
|
BOOL fChanged = FALSE;
|
|
DWORD dw;
|
|
|
|
pOp = Vector_GetItem(pWabSync->m_pOps, dwIndex);
|
|
Assert(pOp->m_bOpType == SYNCOP_CONFLICT);
|
|
|
|
Assert(pOp->m_pServerContact);
|
|
Assert(pOp->m_pClientContact);
|
|
|
|
for (dw = 0; dw < CONFLICT_DECISION_COUNT; dw++)
|
|
{
|
|
if (pConflicts[dwIndex].rgcd[dw] != 0)
|
|
{
|
|
fChanged = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fChanged)
|
|
{
|
|
hr = ContactInfo_BlendResults(pOp->m_pServerContact, pOp->m_pClientContact, (CONFLICT_DECISION *)&(pConflicts[dwIndex].rgcd));
|
|
pOp->m_bState = OP_STATE_MERGED;
|
|
}
|
|
else
|
|
{
|
|
// toss out the conflict since they didn't want to change anything
|
|
pOp->m_bState = OP_STATE_DONE;
|
|
}
|
|
|
|
// if any of it was skipped, we need to remember this and not update the timestamps.
|
|
if (pConflicts[dwIndex].fContainsSkip)
|
|
{
|
|
pOp->m_fPartialSkip = TRUE;
|
|
pWabSync->m_fSkipped = TRUE;
|
|
}
|
|
}
|
|
//reset progress to new total ops
|
|
pWabSync->m_cTotalOps = Vector_GetLength(pWabSync->m_pOps);
|
|
|
|
// HACK to get back into processing ops
|
|
WABSync_NextState(pWabSync);
|
|
return hr;
|
|
}
|
|
else
|
|
WABSync_Abort(pWabSync, E_UserCancel);
|
|
|
|
if (pConflicts)
|
|
LocalFree(pConflicts);
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
void WABSync_MergeAddsToConflicts(LPWABSYNC pWabSync)
|
|
{
|
|
DWORD dwOpCount;
|
|
DWORD dwCliAddIndex, dwSvrAddIndex;
|
|
LPHOTSYNCOP pCliOp, pOp, pNewOp;
|
|
BOOL fMerged = FALSE;
|
|
HRESULT hr;
|
|
|
|
dwOpCount = Vector_GetLength(pWabSync->m_pOps);
|
|
|
|
// search for Client Adds. If found, look for a server add for the
|
|
// same contact.
|
|
for (dwCliAddIndex = 0; dwCliAddIndex < dwOpCount; dwCliAddIndex++)
|
|
{
|
|
fMerged = FALSE;
|
|
pCliOp = Vector_GetItem(pWabSync->m_pOps, dwCliAddIndex);
|
|
if (pCliOp && pCliOp->m_bOpType == SYNCOP_CLIENT_ADD)
|
|
{
|
|
for (dwSvrAddIndex = 0; dwSvrAddIndex < dwOpCount; dwSvrAddIndex++)
|
|
{
|
|
pOp = Vector_GetItem(pWabSync->m_pOps, dwSvrAddIndex);
|
|
if (pOp && pOp->m_bOpType == SYNCOP_SERVER_ADD)
|
|
{
|
|
if (pOp->m_pClientContact && pOp->m_pClientContact->pszEmail &&
|
|
pCliOp->m_pServerContact && pCliOp->m_pServerContact->pszEmail)
|
|
{
|
|
if (lstrcmpiA(pCliOp->m_pServerContact->pszEmail, pOp->m_pClientContact->pszEmail) == 0)
|
|
{
|
|
pNewOp = Syncop_CreateConflict(pCliOp->m_pContactInfo);
|
|
Assert(pNewOp);
|
|
|
|
if (pNewOp)
|
|
{
|
|
pNewOp->m_pContactInfo->lpEID = pOp->m_pContactInfo->lpEID;
|
|
pNewOp->m_pContactInfo->cbEID = pOp->m_pContactInfo->cbEID;
|
|
pNewOp->m_pContactInfo->pszaContactIds = pOp->m_pContactInfo->pszaContactIds;
|
|
pNewOp->m_pContactInfo->pszaServerIds = pOp->m_pContactInfo->pszaServerIds;
|
|
pNewOp->m_pContactInfo->pszaModtimes = pOp->m_pContactInfo->pszaModtimes;
|
|
pNewOp->m_pContactInfo->pszaEmails = pOp->m_pContactInfo->pszaEmails;
|
|
pOp->m_pContactInfo->pszaContactIds = NULL;
|
|
pOp->m_pContactInfo->pszaServerIds = NULL;
|
|
pOp->m_pContactInfo->pszaModtimes = NULL;
|
|
pOp->m_pContactInfo->pszaEmails = NULL;
|
|
pOp->m_pContactInfo->lpEID = NULL;
|
|
pOp->m_pContactInfo->cbEID = 0;
|
|
|
|
pCliOp->m_pContactInfo = NULL;
|
|
pNewOp->m_pServerContact = pCliOp->m_pServerContact;
|
|
pCliOp->m_pServerContact = NULL;
|
|
|
|
Syncop_Init(pNewOp, (IHTTPMailCallback *)pWabSync, pWabSync->m_pTransport);
|
|
hr = Vector_AddItem(pWabSync->m_pOps, pNewOp);
|
|
|
|
if (dwSvrAddIndex < dwCliAddIndex)
|
|
--dwCliAddIndex;
|
|
Vector_Remove(pWabSync->m_pOps, pOp);
|
|
|
|
Vector_Remove(pWabSync->m_pOps, pCliOp);
|
|
|
|
dwOpCount = Vector_GetLength(pWabSync->m_pOps);
|
|
fMerged = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (fMerged)
|
|
-- dwCliAddIndex;
|
|
}
|
|
}
|
|
|
|
|
|
// ****************************************************************************************************
|
|
// V E C T O R "C L A S S"
|
|
//
|
|
// Basic vector class (resizable / sortable array of LPVOIDs).
|
|
//
|
|
|
|
|
|
HRESULT Vector_Create(LPVECTOR *ppVector)
|
|
{
|
|
Assert(ppVector);
|
|
|
|
*ppVector = LocalAlloc(LMEM_ZEROINIT, sizeof(VECTOR));
|
|
|
|
if (*ppVector)
|
|
{
|
|
(*ppVector)->m_dwGrowBy = 4;
|
|
return S_OK;
|
|
}
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
/*
|
|
Vector_Delete
|
|
|
|
Clean up any memory that was allocated in the Vector object
|
|
*/
|
|
void Vector_Delete(LPVECTOR pVector)
|
|
{
|
|
Assert(pVector);
|
|
|
|
if (pVector->m_pItems)
|
|
LocalFree(pVector->m_pItems);
|
|
|
|
if (pVector)
|
|
LocalFree(pVector);
|
|
}
|
|
|
|
/*
|
|
Vector_GetLength
|
|
|
|
Get the number of items in the vector.
|
|
*/
|
|
DWORD Vector_GetLength(LPVECTOR pVector)
|
|
{
|
|
Assert(pVector);
|
|
|
|
return pVector->m_cItems;
|
|
}
|
|
|
|
/*
|
|
Vector_AddItem
|
|
|
|
Add a item to the end of the item list.
|
|
*/
|
|
HRESULT Vector_AddItem(LPVECTOR pVector, LPVOID lpvItem)
|
|
{
|
|
DWORD dwNewIndex;
|
|
DWORD dw;
|
|
|
|
Assert(pVector);
|
|
|
|
// make more room for pointers, if necessary
|
|
if (pVector->m_cSpaces == pVector->m_cItems)
|
|
{
|
|
LPVOID pNewItems;
|
|
DWORD dwOldSize = pVector->m_cSpaces * sizeof(char *);
|
|
|
|
pVector->m_cSpaces += pVector->m_dwGrowBy;
|
|
|
|
pNewItems = LocalAlloc(LMEM_ZEROINIT, sizeof(char *) * pVector->m_cSpaces);
|
|
|
|
if (!pNewItems)
|
|
{
|
|
pVector->m_cSpaces -= pVector->m_dwGrowBy;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
if (pVector->m_pItems)
|
|
{
|
|
CopyMemory(pNewItems, pVector->m_pItems, dwOldSize);
|
|
LocalFree(pVector->m_pItems);
|
|
}
|
|
|
|
pVector->m_pItems = (LPVOID *)pNewItems;
|
|
pVector->m_dwGrowBy = pVector->m_dwGrowBy << 1; // double the size for the next time we grow it.
|
|
}
|
|
}
|
|
|
|
//now put the item in the next location
|
|
dwNewIndex = pVector->m_cItems++;
|
|
|
|
pVector->m_pItems[dwNewIndex] = lpvItem;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
Vector_Remove
|
|
|
|
Remove a given item from the vector
|
|
*/
|
|
void Vector_Remove(LPVECTOR pVector, LPVOID lpvItem)
|
|
{
|
|
DWORD dw;
|
|
|
|
for (dw = 0; dw < pVector->m_cItems; dw++)
|
|
{
|
|
if (pVector->m_pItems[dw] == lpvItem)
|
|
{
|
|
Vector_RemoveItem(pVector, dw);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Vector_RemoveItem
|
|
|
|
Remove a item at zero based index iIndex
|
|
*/
|
|
|
|
void Vector_RemoveItem(LPVECTOR pVector, DWORD dwIndex)
|
|
{
|
|
int iCopySize;
|
|
DWORD dw;
|
|
|
|
Assert(pVector);
|
|
Assert(dwIndex < pVector->m_cItems);
|
|
|
|
// move the other pItems down
|
|
for (dw = dwIndex+1; dw < pVector->m_cItems; dw ++)
|
|
pVector->m_pItems[dw - 1] = pVector->m_pItems[dw];
|
|
|
|
// null out the last item in the list and decrement the counter.
|
|
pVector->m_pItems[--pVector->m_cItems] = NULL;
|
|
}
|
|
|
|
/*
|
|
CVector::GetItem
|
|
|
|
Return the pointer to the item at zero based index iIndex.
|
|
|
|
Return the item at the given index. Note that the char pointer
|
|
is still owned by the item list and should not be deleted.
|
|
*/
|
|
|
|
LPVOID Vector_GetItem(LPVECTOR pVector, DWORD dwIndex)
|
|
{
|
|
Assert(pVector);
|
|
Assert(dwIndex < pVector->m_cItems || dwIndex == 0);
|
|
|
|
if (dwIndex < pVector->m_cItems )
|
|
return pVector->m_pItems[dwIndex];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void Vector_Sort(LPVECTOR pVector, FnCompareFunc lpfnCompare)
|
|
{
|
|
qsort(pVector->m_pItems, pVector->m_cItems, sizeof(LPVOID), lpfnCompare);
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateServerAdd(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_SERVER_ADD;
|
|
pOp->m_pfnHandleResponse = Syncop_ServerAddResponse;
|
|
pOp->m_pfnBegin = Syncop_ServerAddBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateServerDelete(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_SERVER_DELETE;
|
|
pOp->m_pfnHandleResponse = Syncop_ServerDeleteResponse;
|
|
pOp->m_pfnBegin = Syncop_ServerDeleteBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateServerChange(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_SERVER_CHANGE;
|
|
pOp->m_pfnHandleResponse = Syncop_ServerChangeResponse;
|
|
pOp->m_pfnBegin = Syncop_ServerChangeBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateClientAdd(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
Assert(pContactInfo);
|
|
Assert(pOp);
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_CLIENT_ADD;
|
|
pOp->m_pfnHandleResponse = Syncop_ClientAddResponse;
|
|
pOp->m_pfnBegin = Syncop_ClientAddBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateClientDelete(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_CLIENT_DELETE;
|
|
pOp->m_pfnHandleResponse = Syncop_ClientDeleteResponse;
|
|
pOp->m_pfnBegin = Syncop_ClientDeleteBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateClientChange(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_CLIENT_CHANGE;
|
|
pOp->m_pfnHandleResponse = Syncop_ClientChangeResponse;
|
|
pOp->m_pfnBegin = Syncop_ClientChangeBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
LPHOTSYNCOP Syncop_CreateConflict(LPWABCONTACTINFO pContactInfo)
|
|
{
|
|
LPHOTSYNCOP pOp = LocalAlloc(LMEM_ZEROINIT, sizeof(HOTSYNCOP));
|
|
|
|
if (pOp)
|
|
{
|
|
pOp->m_bOpType = SYNCOP_CONFLICT;
|
|
pOp->m_pfnHandleResponse = Syncop_ConflictResponse;
|
|
pOp->m_pfnBegin = Syncop_ConflictBegin;
|
|
pOp->m_pContactInfo = pContactInfo;
|
|
}
|
|
|
|
return pOp;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_Init(LPHOTSYNCOP pSyncOp, IHTTPMailCallback *pHotSync, IHTTPMailTransport *pTransport)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pHotSync == NULL);
|
|
Assert(pSyncOp->m_pTransport == NULL);
|
|
|
|
pSyncOp->m_pClientContact = NULL;
|
|
pSyncOp->m_pHotSync = pHotSync;
|
|
pSyncOp->m_pTransport = pTransport;
|
|
pSyncOp->m_bState = OP_STATE_INITIALIZING;
|
|
pSyncOp->m_fPartialSkip = FALSE;
|
|
pSyncOp->m_dwRetries = 0;
|
|
|
|
if (pSyncOp->m_pTransport)
|
|
IHTTPMailTransport_AddRef(pSyncOp->m_pTransport);
|
|
|
|
if (pSyncOp->m_pHotSync)
|
|
IHTTPMailCallback_AddRef(pSyncOp->m_pHotSync);
|
|
|
|
if (pSyncOp->m_bOpType == SYNCOP_SERVER_ADD ||
|
|
pSyncOp->m_bOpType == SYNCOP_SERVER_CHANGE ||
|
|
pSyncOp->m_bOpType == SYNCOP_CLIENT_CHANGE ||
|
|
pSyncOp->m_bOpType == SYNCOP_CONFLICT )
|
|
{
|
|
pSyncOp->m_pClientContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
|
|
if (pSyncOp->m_pClientContact)
|
|
hr = ContactInfo_LoadFromWAB(((LPWABSYNC)pSyncOp->m_pHotSync),
|
|
pSyncOp->m_pClientContact,
|
|
pSyncOp->m_pContactInfo,
|
|
pSyncOp->m_pContactInfo->lpEID,
|
|
pSyncOp->m_pContactInfo->cbEID);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT Syncop_Delete(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
Assert(pSyncOp);
|
|
|
|
if (pSyncOp->m_pTransport)
|
|
IHTTPMailTransport_Release(pSyncOp->m_pTransport);
|
|
|
|
if (pSyncOp->m_pHotSync)
|
|
IHTTPMailCallback_Release(pSyncOp->m_pHotSync);
|
|
|
|
if (pSyncOp->m_pServerContact)
|
|
{
|
|
ContactInfo_Free(pSyncOp->m_pServerContact);
|
|
LocalFree(pSyncOp->m_pServerContact);
|
|
}
|
|
|
|
if (pSyncOp->m_pClientContact)
|
|
{
|
|
ContactInfo_Free(pSyncOp->m_pClientContact);
|
|
LocalFree(pSyncOp->m_pClientContact);
|
|
}
|
|
|
|
if (pSyncOp->m_pContactInfo)
|
|
{
|
|
WABContact_Delete(pSyncOp->m_pContactInfo);
|
|
}
|
|
|
|
LocalFree(pSyncOp);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT Syncop_HandleResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pfnHandleResponse);
|
|
Assert(pSyncOp->m_bOpType != SYNCOP_SERVER_INVALID);
|
|
|
|
return (pSyncOp->m_pfnHandleResponse)(pSyncOp, pResponse);
|
|
|
|
}
|
|
|
|
HRESULT Syncop_Begin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pfnBegin);
|
|
Assert(pSyncOp->m_bOpType != SYNCOP_SERVER_INVALID);
|
|
|
|
return (pSyncOp->m_pfnBegin)(pSyncOp);
|
|
}
|
|
|
|
HRESULT Syncop_Abort(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
Assert(pSyncOp);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT Syncop_ServerAddResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pWabSync = (LPWABSYNC)(pSyncOp->m_pHotSync);
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pWabSync);
|
|
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rPostContactInfo.pszHref)
|
|
{
|
|
pSyncOp->m_pClientContact->pszId = pResponse->rPostContactInfo.pszId;
|
|
pResponse->rPostContactInfo.pszId = NULL;
|
|
|
|
pSyncOp->m_pClientContact->pszModified = pResponse->rPostContactInfo.pszModified;
|
|
pResponse->rPostContactInfo.pszModified = NULL;
|
|
|
|
hr = ContactInfo_SaveToWAB(pWabSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo,
|
|
pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
|
|
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
|
|
}
|
|
else
|
|
{
|
|
if (IXP_E_HTTP_CONFLICT == pResponse->rIxpResult.hrResult)
|
|
{
|
|
// if we get a conflict, it is probably because the nickname we
|
|
// generated is not unique. Lets try to generate a new one, but
|
|
// don't try this more than twice.
|
|
if (pSyncOp->m_dwRetries <= 2)
|
|
{
|
|
pSyncOp->m_dwRetries ++;
|
|
if (SUCCEEDED(hr = ContactInfo_GenerateNickname(pSyncOp->m_pClientContact)))
|
|
hr = pSyncOp->m_pTransport->lpVtbl->PostContact(pSyncOp->m_pTransport, ((LPWABSYNC)pSyncOp->m_pHotSync)->m_pszRootUrl, pSyncOp->m_pClientContact, 0);
|
|
|
|
}
|
|
else
|
|
{ // [PaulHi] 12/3/98 After trying three different nicknames, abort this
|
|
// synchronization operation.
|
|
hr = pResponse->rIxpResult.hrResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pResponse->rPostContactInfo.pszHref)
|
|
{
|
|
// TODO : delete the server version here?
|
|
|
|
// we have the reference, just not the timestamp or id. Guess the id, and
|
|
// throw in a crappy timestamp so that it will get fixed up next time
|
|
char *pszId = NULL, *psz;
|
|
|
|
psz = pResponse->rPostContactInfo.pszHref;
|
|
while (*psz)
|
|
{
|
|
if ('/' == *psz)
|
|
{
|
|
if (psz[1] == 0)
|
|
*psz = 0;
|
|
else
|
|
pszId = ++psz;
|
|
}
|
|
else
|
|
psz++;
|
|
}
|
|
|
|
if (pszId)
|
|
{
|
|
pSyncOp->m_pClientContact->pszId = _StrDup(pszId);
|
|
pResponse->rPostContactInfo.pszId = NULL;
|
|
|
|
pResponse->rPostContactInfo.pszModified = _StrDup( "1993-01-01T00:00");
|
|
hr = ContactInfo_SaveToWAB(pWabSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo,
|
|
pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
|
|
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
hr = pResponse->rIxpResult.hrResult;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ServerAddBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if (!pSyncOp->m_pClientContact)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_GET;
|
|
|
|
if (pSyncOp->m_pClientContact->pszNickname || SUCCEEDED(hr = ContactInfo_GenerateNickname(pSyncOp->m_pClientContact)))
|
|
hr = pSyncOp->m_pTransport->lpVtbl->PostContact(pSyncOp->m_pTransport, ((LPWABSYNC)pSyncOp->m_pHotSync)->m_pszRootUrl, pSyncOp->m_pClientContact, 0);
|
|
}
|
|
|
|
exit:
|
|
if (FAILED(hr))
|
|
{
|
|
if (pSyncOp->m_pClientContact)
|
|
{
|
|
ContactInfo_Free(pSyncOp->m_pClientContact);
|
|
LocalFree(pSyncOp->m_pClientContact);
|
|
pSyncOp->m_pClientContact = NULL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT Syncop_ServerDeleteResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = pResponse->rIxpResult.hrResult;
|
|
LPWABSYNC pWabSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
TCHAR tszServerId[MAX_PATH];
|
|
TCHAR tszKey[MAX_PATH];
|
|
HKEY hkey = NULL;
|
|
|
|
// now that the delete has completed, delete the tombstone from the registry.
|
|
if ( FAILED(hrMakeContactId(
|
|
tszServerId,
|
|
MAX_PATH,
|
|
((LPIAB)(pWabSync->m_pAB))->szProfileID,
|
|
pWabSync->m_pszAccountId,
|
|
pWabSync->m_szLoginName)) )
|
|
{
|
|
return hr;
|
|
}
|
|
wnsprintf(tszKey, ARRAYSIZE(tszKey), TEXT("%s%s"), g_lpszSyncKey, tszServerId);
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tszKey, 0, KEY_SET_VALUE, &hkey))
|
|
{
|
|
LPTSTR lpKey =
|
|
ConvertAtoW(pSyncOp->m_pContactInfo->pszHotmailId);
|
|
RegDeleteValue(hkey, lpKey);
|
|
LocalFreeAndNull(&lpKey);
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ServerDeleteBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
|
|
hr = pSyncOp->m_pTransport->lpVtbl->CommandDELETE(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ServerChangeResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = pResponse->rIxpResult.hrResult;
|
|
LPWABSYNC pWabSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
|
|
{
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
|
|
{
|
|
// assume the whole struct
|
|
Assert(pResponse->rContactInfoList.prgContactInfo);
|
|
Assert(pResponse->rContactInfoList.cContactInfo == 1);
|
|
|
|
if (!pSyncOp->m_pServerContact)
|
|
pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
|
|
|
|
*pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
|
|
ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
if (!ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_PUT;
|
|
hr = ContactInfo_PreparePatch(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact);
|
|
hr = pSyncOp->m_pTransport->lpVtbl->PatchContact(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, pSyncOp->m_pClientContact, 0);
|
|
}
|
|
else
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
}
|
|
}
|
|
else if (OP_STATE_SERVER_PUT == pSyncOp->m_bState)
|
|
{
|
|
// if it succeeded, save the new values mod stamp, etc to the wab
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
|
|
{
|
|
SafeCoMemFree(pSyncOp->m_pClientContact->pszId);
|
|
pSyncOp->m_pClientContact->pszId = pResponse->rPostContactInfo.pszId;
|
|
pResponse->rPostContactInfo.pszId = NULL;
|
|
|
|
SafeCoMemFree(pSyncOp->m_pClientContact->pszModified);
|
|
pSyncOp->m_pClientContact->pszModified = pResponse->rPostContactInfo.pszModified;
|
|
pResponse->rPostContactInfo.pszModified = NULL;
|
|
|
|
hr = ContactInfo_SaveToWAB(pWabSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
|
|
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ServerChangeBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pTransport);
|
|
Assert(pSyncOp->m_pContactInfo);
|
|
Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
|
|
|
|
if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
|
|
{
|
|
if (pSyncOp->m_pServerContact)
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
if (!ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_PUT;
|
|
hr = ContactInfo_PreparePatch(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact);
|
|
|
|
hr = pSyncOp->m_pTransport->lpVtbl->PatchContact(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, pSyncOp->m_pClientContact, 0);
|
|
}
|
|
else
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_GET;
|
|
hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT Syncop_ClientAddResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
|
|
{
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
|
|
{
|
|
// assume the whole struct
|
|
Assert(pResponse->rContactInfoList.prgContactInfo);
|
|
Assert(pResponse->rContactInfoList.cContactInfo == 1);
|
|
|
|
if (!pSyncOp->m_pServerContact)
|
|
pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
|
|
|
|
*pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
|
|
ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, NULL, NULL, 0, FALSE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
hr = pResponse->rIxpResult.hrResult;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ClientAddBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pTransport);
|
|
Assert(pSyncOp->m_pContactInfo);
|
|
Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
|
|
|
|
if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
|
|
{
|
|
if (pSyncOp->m_pServerContact)
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, NULL, NULL, 0, FALSE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_GET;
|
|
hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT Syncop_ClientDeleteResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
Assert(pSyncOp);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ClientDeleteBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
LPABCONT lpWABCont = NULL;
|
|
LPWABSYNC pWabSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
HRESULT hr = S_OK;
|
|
ULONG cbWABEID = 0;
|
|
LPENTRYID lpWABEID = NULL;
|
|
ULONG ulObjType;
|
|
SBinaryArray SBA = {0};
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if(HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->GetPAB(pWabSync->m_pAB, &cbWABEID, &lpWABEID)))
|
|
goto exit;
|
|
|
|
if(HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB,
|
|
cbWABEID, // size of EntryID to open
|
|
lpWABEID, // EntryID to open
|
|
NULL, // interface
|
|
0, // flags
|
|
&ulObjType,
|
|
(LPUNKNOWN *)&lpWABCont)))
|
|
goto exit;
|
|
|
|
if(!(SBA.lpbin = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary))))
|
|
goto exit;
|
|
|
|
SetSBinary(&(SBA.lpbin[0]), pSyncOp->m_pContactInfo->cbEID, (LPBYTE)pSyncOp->m_pContactInfo->lpEID);
|
|
|
|
SBA.cValues = 1;
|
|
|
|
if(HR_FAILED(hr = lpWABCont->lpVtbl->DeleteEntries( lpWABCont, (LPENTRYLIST) &SBA, 0)))
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
exit:
|
|
if(SBA.lpbin && SBA.cValues)
|
|
{
|
|
LocalFreeAndNull((LPVOID *) (&(SBA.lpbin[0].lpb)));
|
|
LocalFreeAndNull(&SBA.lpbin);
|
|
}
|
|
|
|
if(lpWABCont)
|
|
UlRelease(lpWABCont);
|
|
|
|
if(lpWABEID)
|
|
FreeBufferAndNull(&lpWABEID);
|
|
|
|
if (!WABSync_NextOp(pWabSync, TRUE))
|
|
WABSync_NextState(pWabSync);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT Syncop_ClientChangeResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
|
|
{
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
|
|
{
|
|
// assume the whole struct
|
|
Assert(pResponse->rContactInfoList.prgContactInfo);
|
|
Assert(pResponse->rContactInfoList.cContactInfo == 1);
|
|
|
|
if (!pSyncOp->m_pServerContact)
|
|
pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
|
|
|
|
*pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
|
|
ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
ContactInfo_EmptyNullItems(pSyncOp->m_pServerContact);
|
|
ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
hr = pResponse->rIxpResult.hrResult;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT Syncop_ClientChangeBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pTransport);
|
|
Assert(pSyncOp->m_pContactInfo);
|
|
Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
|
|
|
|
if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
|
|
{
|
|
if (pSyncOp->m_pServerContact)
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
ContactInfo_EmptyNullItems(pSyncOp->m_pServerContact);
|
|
ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_GET;
|
|
hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT Syncop_ConflictResponse(LPHOTSYNCOP pSyncOp, LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
|
|
if (OP_STATE_SERVER_GET == pSyncOp->m_bState)
|
|
{
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
|
|
{
|
|
// assume the whole struct
|
|
Assert(pResponse->rContactInfoList.prgContactInfo);
|
|
Assert(pResponse->rContactInfoList.cContactInfo == 1);
|
|
|
|
if (!pSyncOp->m_pServerContact)
|
|
pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
|
|
|
|
*pSyncOp->m_pServerContact = *pResponse->rContactInfoList.prgContactInfo;
|
|
ContactInfo_Clear(pResponse->rContactInfoList.prgContactInfo);
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
// if the records match as far as we're concerned, we are done.
|
|
if (ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
|
|
{
|
|
// update the timestamp so it isn't a conflict next time.
|
|
ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
{
|
|
// move this item to the end, once all conflicts are loaded, then we
|
|
// will do the dialog
|
|
Vector_Remove(pHotSync->m_pOps, pSyncOp);
|
|
Vector_AddItem(pHotSync->m_pOps, pSyncOp);
|
|
|
|
if (!WABSync_NextOp(pHotSync, FALSE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
}
|
|
else
|
|
hr = pResponse->rIxpResult.hrResult;
|
|
}
|
|
else if (OP_STATE_SERVER_PUT == pSyncOp->m_bState)
|
|
{
|
|
// if it succeeded, save the new values mod stamp, etc to the wab
|
|
if (SUCCEEDED(pResponse->rIxpResult.hrResult) && pResponse->rContactInfoList.prgContactInfo)
|
|
{
|
|
SafeCoMemFree(pSyncOp->m_pClientContact->pszId);
|
|
pSyncOp->m_pClientContact->pszId = pResponse->rPostContactInfo.pszId;
|
|
pResponse->rPostContactInfo.pszId = NULL;
|
|
|
|
SafeCoMemFree(pSyncOp->m_pClientContact->pszModified);
|
|
pSyncOp->m_pClientContact->pszModified = pResponse->rPostContactInfo.pszModified;
|
|
pResponse->rPostContactInfo.pszModified = NULL;
|
|
|
|
if (!pSyncOp->m_fPartialSkip)
|
|
hr = ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, FALSE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT Syncop_ConflictBegin(LPHOTSYNCOP pSyncOp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABSYNC pHotSync = (LPWABSYNC)pSyncOp->m_pHotSync;
|
|
|
|
Assert(pSyncOp);
|
|
Assert(pSyncOp->m_pTransport);
|
|
Assert(pSyncOp->m_pContactInfo);
|
|
Assert(pSyncOp->m_pContactInfo->pszHotmailHref);
|
|
|
|
if (OP_STATE_INITIALIZING == pSyncOp->m_bState)
|
|
{
|
|
if (pSyncOp->m_pServerContact)
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_LOADED;
|
|
|
|
// if the records match as far as we're concerned, we are done.
|
|
if (ContactInfo_Match(pSyncOp->m_pServerContact, pSyncOp->m_pClientContact))
|
|
{
|
|
// update the timestamp so it isn't a conflict next time.
|
|
ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pServerContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
|
|
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
else
|
|
{
|
|
// move this item to the end, once all conflicts are loaded, then we
|
|
// will do the dialog
|
|
Vector_Remove(pHotSync->m_pOps, pSyncOp);
|
|
Vector_AddItem(pHotSync->m_pOps, pSyncOp);
|
|
|
|
if (!WABSync_NextOp(pHotSync, FALSE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSyncOp->m_bState = OP_STATE_SERVER_GET;
|
|
hr = pSyncOp->m_pTransport->lpVtbl->ContactInfo(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, 0);
|
|
}
|
|
}
|
|
else if (OP_STATE_LOADED == pSyncOp->m_bState)
|
|
WABSync_NextState(pHotSync);
|
|
else if (OP_STATE_MERGED == pSyncOp->m_bState)
|
|
{
|
|
hr = ContactInfo_SaveToWAB(pHotSync, pSyncOp->m_pClientContact, pSyncOp->m_pContactInfo, pSyncOp->m_pContactInfo->lpEID, pSyncOp->m_pContactInfo->cbEID, TRUE);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
pSyncOp->m_bState = OP_STATE_SERVER_PUT;
|
|
hr = pSyncOp->m_pTransport->lpVtbl->PatchContact(pSyncOp->m_pTransport, pSyncOp->m_pContactInfo->pszHotmailHref, pSyncOp->m_pServerContact, 0);
|
|
}
|
|
else if (OP_STATE_DONE == pSyncOp->m_bState)
|
|
{
|
|
if (!WABSync_NextOp(pHotSync, TRUE))
|
|
WABSync_NextState(pHotSync);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void Syncop_SetServerContactInfo(LPHOTSYNCOP pSyncOp, LPWABCONTACTINFO pWabContactInfo, LPHTTPCONTACTINFO pContactInfo)
|
|
{
|
|
if (!pSyncOp)
|
|
return;
|
|
|
|
if (!pSyncOp->m_pServerContact)
|
|
pSyncOp->m_pServerContact = LocalAlloc(LMEM_ZEROINIT, sizeof(HTTPCONTACTINFO));
|
|
|
|
if (!pSyncOp->m_pServerContact)
|
|
return;
|
|
|
|
*pSyncOp->m_pServerContact = *pContactInfo;
|
|
ContactInfo_Clear(pContactInfo);
|
|
pSyncOp->m_pServerContact->pszId = _StrDup(pWabContactInfo->pszHotmailId);
|
|
pSyncOp->m_pServerContact->pszModified = _StrDup(pWabContactInfo->pszModHotmail);
|
|
}
|
|
|
|
void WABContact_Delete(LPWABCONTACTINFO pContact)
|
|
{
|
|
Assert(pContact);
|
|
|
|
if (pContact->pszHotmailHref)
|
|
CoTaskMemFree(pContact->pszHotmailHref);
|
|
|
|
if (pContact->pszModHotmail)
|
|
CoTaskMemFree(pContact->pszModHotmail);
|
|
|
|
if (pContact->pszHotmailId)
|
|
CoTaskMemFree(pContact->pszHotmailId);
|
|
|
|
if (pContact->pszaContactIds)
|
|
FreeMultiValueString(pContact->pszaContactIds);
|
|
|
|
if (pContact->pszaServerIds)
|
|
FreeMultiValueString(pContact->pszaServerIds);
|
|
|
|
if (pContact->pszaModtimes)
|
|
FreeMultiValueString(pContact->pszaModtimes);
|
|
|
|
if (pContact->pszaEmails)
|
|
FreeMultiValueString(pContact->pszaEmails);
|
|
|
|
if (pContact->lpEID)
|
|
LocalFree(pContact->lpEID);
|
|
|
|
LocalFree(pContact);
|
|
}
|
|
|
|
void ContactInfo_Clear(LPHTTPCONTACTINFO pContactInfo)
|
|
{
|
|
ZeroMemory(pContactInfo, sizeof(HTTPCONTACTINFO));
|
|
}
|
|
|
|
void ContactInfo_Free(LPHTTPCONTACTINFO pContactInfo)
|
|
{
|
|
DWORD i, dwSize = ARRAYSIZE(g_ContactInfoStructure);
|
|
if (!pContactInfo)
|
|
return;
|
|
|
|
for (i = 0; i < dwSize; i++)
|
|
{
|
|
if (CIS_STRING == CIS_GETTYPE(i))
|
|
SafeCoMemFree(CIS_GETSTRING(pContactInfo, i));
|
|
}
|
|
}
|
|
|
|
ULONG rgPropMap[] = {
|
|
PR_ENTRYID, //href
|
|
PR_ENTRYID, //id
|
|
PR_ENTRYID, //type
|
|
PR_ENTRYID, //modified
|
|
PR_DISPLAY_NAME,
|
|
PR_GIVEN_NAME,
|
|
PR_SURNAME,
|
|
PR_NICKNAME,
|
|
PR_EMAIL_ADDRESS,
|
|
PR_HOME_ADDRESS_STREET,
|
|
PR_HOME_ADDRESS_CITY,
|
|
PR_HOME_ADDRESS_STATE_OR_PROVINCE,
|
|
PR_HOME_ADDRESS_POSTAL_CODE,
|
|
PR_HOME_ADDRESS_COUNTRY,
|
|
PR_COMPANY_NAME,
|
|
PR_BUSINESS_ADDRESS_STREET,
|
|
PR_BUSINESS_ADDRESS_CITY,
|
|
PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
|
|
PR_BUSINESS_ADDRESS_POSTAL_CODE,
|
|
PR_BUSINESS_ADDRESS_COUNTRY,
|
|
PR_HOME_TELEPHONE_NUMBER,
|
|
PR_HOME_FAX_NUMBER,
|
|
PR_BUSINESS_TELEPHONE_NUMBER,
|
|
PR_BUSINESS_FAX_NUMBER,
|
|
PR_MOBILE_TELEPHONE_NUMBER,
|
|
PR_OTHER_TELEPHONE_NUMBER,
|
|
PR_BIRTHDAY,
|
|
PR_PAGER_TELEPHONE_NUMBER
|
|
};
|
|
|
|
DWORD ContactInfo_CountProperties(LPHTTPCONTACTINFO pContactInfo)
|
|
{
|
|
DWORD cProps = 0;
|
|
DWORD dwIndex, dwSize = ARRAYSIZE(g_ContactInfoStructure);
|
|
|
|
// skip href
|
|
for (dwIndex = 1; dwIndex < dwSize; dwIndex ++)
|
|
{
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Skip email name here if we are group syncing
|
|
if ( (pContactInfo->tyContact == HTTPMAIL_CT_GROUP) && (dwIndex == idcisEmail) )
|
|
continue;
|
|
#endif
|
|
if (CIS_STRING == CIS_GETTYPE(dwIndex) && CIS_GETSTRING(pContactInfo, dwIndex) && *(CIS_GETSTRING(pContactInfo, dwIndex)))
|
|
cProps++;
|
|
}
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Group syncing
|
|
if (pContactInfo->tyContact == HTTPMAIL_CT_GROUP)
|
|
{
|
|
LPTSTR lptszEmailName = ConvertAtoW( CIS_GETSTRING(pContactInfo, idcisEmail) );
|
|
if (lptszEmailName)
|
|
{
|
|
ULONG cContacts = 0;
|
|
ULONG cOneOffs = 0;
|
|
if ( SUCCEEDED(hrParseHMGroupEmail(lptszEmailName, NULL, &cContacts, NULL, &cOneOffs)) )
|
|
{
|
|
// One property for each set of mail user contacts or one-offs
|
|
cProps += (cContacts != 0) ? 1 : 0;
|
|
cProps += (cOneOffs != 0) ? 1 : 0;
|
|
}
|
|
|
|
LocalFreeAndNull(&lptszEmailName);
|
|
}
|
|
|
|
// A valid WAB DL must have a display name. HM groups only have nicknames so we
|
|
// need to reserve a PR_DISPLAY_NAME property.
|
|
// [PaulHi] Note, only do this if there is a valid Nickname field. The ContactInfo_SaveToWAB()
|
|
// function, which calls this function, is always in response to a server add or change.
|
|
// The pContactInfo fields reflect whatever was changed on the server. If there is a
|
|
// valid Nickname field then be sure we translate this to the WAB property DisplayName field.
|
|
// The WAB group display name corresponds to a HM group nickname.
|
|
if (pContactInfo->pszNickname)
|
|
++cProps; // This gets translated to a DisplayName in ContactInfo_TranslateProps()
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
if (pContactInfo->pszEmail && *(pContactInfo->pszEmail))
|
|
cProps++; //need to make room for the PR_ADDRTYPE too
|
|
#ifdef HM_GROUP_SYNCING
|
|
}
|
|
#endif
|
|
return cProps;
|
|
}
|
|
|
|
|
|
|
|
HRESULT ContactInfo_SetProp(ULONG ulPropTag, LPTSTR pszValue, LPSPropValue lpPropArray, DWORD *pdwLoc)
|
|
{
|
|
ULONG ulLen;
|
|
SCODE sc;
|
|
UNALIGNED LPTSTR *lppszValues;
|
|
HRESULT hr;
|
|
LPSTR lp = NULL;
|
|
|
|
Assert(pszValue);
|
|
|
|
switch (PROP_TYPE(ulPropTag))
|
|
{
|
|
// BUGBUG currently only works for PT_TSTRING or PT_MV_TSTRING properties
|
|
case PT_TSTRING:
|
|
// Get the value for this attribute
|
|
if (ulLen = lstrlen(pszValue))
|
|
{
|
|
lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
|
|
lpPropArray[*pdwLoc].dwAlignPad = 0;
|
|
|
|
// Allocate more space for the data
|
|
ulLen = (ulLen + 1) * sizeof(TCHAR);
|
|
sc = MAPIAllocateMore(ulLen, lpPropArray, (LPVOID *)&(lpPropArray[*pdwLoc].Value.LPSZ));
|
|
if (sc)
|
|
goto error;
|
|
StrCpyN(lpPropArray[*pdwLoc].Value.LPSZ, pszValue, ulLen);
|
|
|
|
// If this is PR_EMAIL_ADDRESS, create a PR_ADDRTYPE entry as well
|
|
if (PR_EMAIL_ADDRESS == ulPropTag)
|
|
{
|
|
// Remember where the email value was, so we can add it to
|
|
// PR_CONTACT_EMAIL_ADDRESSES later
|
|
// ulPrimaryEmailIndex = *pdwLoc;
|
|
(*pdwLoc)++;
|
|
|
|
lpPropArray[*pdwLoc].ulPropTag = PR_ADDRTYPE;
|
|
lpPropArray[*pdwLoc].dwAlignPad = 0;
|
|
lpPropArray[*pdwLoc].Value.LPSZ = (LPTSTR)szSMTP;
|
|
}
|
|
(*pdwLoc)++;
|
|
}
|
|
break;
|
|
|
|
case PT_MV_TSTRING:
|
|
lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
|
|
lpPropArray[*pdwLoc].dwAlignPad = 0;
|
|
lpPropArray[*pdwLoc].Value.MVSZ.cValues = 1;
|
|
sc = MAPIAllocateMore((2)*sizeof(LPTSTR), lpPropArray,
|
|
(LPVOID *)&(lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ));
|
|
if (sc)
|
|
goto error;
|
|
lppszValues = lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ;
|
|
|
|
ulLen = sizeof(TCHAR)*(lstrlen(pszValue) + 1);
|
|
// Allocate more space for the email address and copy it.
|
|
sc = MAPIAllocateMore(ulLen, lpPropArray, (LPVOID *)&(lppszValues[0]));
|
|
if (sc)
|
|
goto error;
|
|
StrCpyN(lppszValues[0], pszValue, ulLen);
|
|
lppszValues[1] = NULL;
|
|
|
|
(*pdwLoc)++;
|
|
|
|
break;
|
|
case PT_SYSTIME:
|
|
lp = ConvertWtoA(pszValue);
|
|
hr = iso8601ToFileTime(lp, (FILETIME *) (&lpPropArray[*pdwLoc].Value.ft), TRUE, TRUE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
|
|
lpPropArray[*pdwLoc].dwAlignPad = 0;
|
|
(*pdwLoc)++;
|
|
}
|
|
LocalFreeAndNull(&lp);
|
|
break;
|
|
|
|
default:
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return S_OK;
|
|
error:
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
HRESULT ContactInfo_SetMVSZProp(ULONG ulPropTag, SLPSTRArray *pszaValue, LPSPropValue lpPropArray, DWORD *pdwLoc)
|
|
{
|
|
ULONG ulLen;
|
|
ULONG cbValue;
|
|
SCODE sc;
|
|
UNALIGNED LPTSTR *lppszValues;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
LPTSTR lpVal = NULL;
|
|
|
|
Assert(pszaValue);
|
|
|
|
switch (PROP_TYPE(ulPropTag))
|
|
{
|
|
case PT_MV_TSTRING:
|
|
lpPropArray[*pdwLoc].ulPropTag = ulPropTag;
|
|
lpPropArray[*pdwLoc].dwAlignPad = 0;
|
|
lpPropArray[*pdwLoc].Value.MVSZ.cValues = pszaValue->cValues;
|
|
sc = MAPIAllocateMore((pszaValue->cValues+1)*sizeof(LPTSTR), lpPropArray,
|
|
(LPVOID *)&(lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ));
|
|
if (sc)
|
|
goto error;
|
|
lppszValues = lpPropArray[*pdwLoc].Value.MVSZ.LPPSZ;
|
|
|
|
for (i = 0; i < pszaValue->cValues; i ++)
|
|
{
|
|
ScAnsiToWCMore((LPALLOCATEMORE )(&MAPIAllocateMore), (LPVOID) lpPropArray, (LPSTR) (pszaValue->lppszA[i]), (LPWSTR *) (&(lppszValues[i])));
|
|
}
|
|
lppszValues[pszaValue->cValues] = NULL;
|
|
|
|
(*pdwLoc)++;
|
|
|
|
break;
|
|
|
|
default:
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return S_OK;
|
|
error:
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
HRESULT ContactInfo_TranslateProps(LPWABSYNC pWabSync, LPHTTPCONTACTINFO pContactInfo, LPWABCONTACTINFO pWabContactInfo, LPSPropValue lpaProps)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex, dwSize = ARRAYSIZE(rgPropMap);
|
|
DWORD dwPropIndex = 0, dwLoc = 0;
|
|
TCHAR szFullProfile[MAX_PATH];
|
|
DWORD dwStartIndex = 1;
|
|
|
|
// [PaulHi] Assemble the contact ID string
|
|
hr = hrMakeContactId(
|
|
szFullProfile,
|
|
MAX_PATH,
|
|
((LPIAB)(pWabSync->m_pAB))->szProfileID,
|
|
pWabSync->m_pszAccountId,
|
|
pWabSync->m_szLoginName);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// fix up the other prop tag array structure to take into account the variable values
|
|
rgPropMap[1] = PR_WAB_HOTMAIL_SERVERIDS;
|
|
rgPropMap[3] = PR_WAB_HOTMAIL_MODTIMES;
|
|
|
|
|
|
if (pWabContactInfo && pWabContactInfo->pszaContactIds)
|
|
{
|
|
DWORD i;
|
|
BOOL fFound = FALSE;
|
|
|
|
// [PaulHi] 1/21/99 We are assuming that pszaModtimes and pszaServerIds
|
|
// pointers are valid too. Check this.
|
|
Assert(pWabContactInfo->pszaModtimes);
|
|
Assert(pWabContactInfo->pszaServerIds);
|
|
|
|
for (i = 0; i < pWabContactInfo->pszaContactIds->cValues; i++)
|
|
{
|
|
LPTSTR lpVal =
|
|
ConvertAtoW(pWabContactInfo->pszaContactIds->lppszA[i]);
|
|
if (lstrcmp(szFullProfile, lpVal) == 0)
|
|
{
|
|
LocalFreeAndNull(&lpVal);
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
LocalFreeAndNull(&lpVal);
|
|
}
|
|
|
|
if (fFound)
|
|
{
|
|
SCODE sc;
|
|
ULONG cchSize = lstrlenA(CIS_GETSTRING(pContactInfo, idcisModified))+1;
|
|
|
|
// Allocate new memory for the string, sure the old memory we still be allocated but
|
|
// it will still be freed via the magic of MAPIAllocate* once the whole array gets freed.
|
|
sc = MAPIAllocateMore(sizeof(CHAR) * cchSize, pWabContactInfo->pszaModtimes,
|
|
(LPVOID *)&pWabContactInfo->pszaModtimes->lppszA[i]);
|
|
if (!sc)
|
|
{
|
|
// update the mod time
|
|
StrCpyNA(pWabContactInfo->pszaModtimes->lppszA[i], CIS_GETSTRING(pContactInfo, idcisModified), cchSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CIS_GETSTRING(pContactInfo, idcisId) && CIS_GETSTRING(pContactInfo, idcisModified))
|
|
{
|
|
// add this one to the list at the end
|
|
LPSTR lpValA =
|
|
ConvertWtoA(szFullProfile);
|
|
AppendToMultiValueString(pWabContactInfo->pszaContactIds, lpValA);
|
|
LocalFreeAndNull(&lpValA);
|
|
AppendToMultiValueString(pWabContactInfo->pszaServerIds, CIS_GETSTRING(pContactInfo, idcisId));
|
|
AppendToMultiValueString(pWabContactInfo->pszaModtimes, CIS_GETSTRING(pContactInfo, idcisModified));
|
|
}
|
|
}
|
|
|
|
ContactInfo_SetMVSZProp(PR_WAB_HOTMAIL_CONTACTIDS, pWabContactInfo->pszaContactIds, lpaProps, &dwLoc);
|
|
ContactInfo_SetMVSZProp(PR_WAB_HOTMAIL_SERVERIDS, pWabContactInfo->pszaServerIds, lpaProps, &dwLoc);
|
|
ContactInfo_SetMVSZProp(PR_WAB_HOTMAIL_MODTIMES, pWabContactInfo->pszaModtimes, lpaProps, &dwLoc);
|
|
|
|
dwStartIndex = 4;
|
|
}
|
|
else
|
|
hr = ContactInfo_SetProp(PR_WAB_HOTMAIL_CONTACTIDS, szFullProfile, lpaProps, &dwLoc);
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
if (!pWabSync->m_fSyncGroups)
|
|
{
|
|
// [PaulHi] Normal contact email addresses
|
|
#endif
|
|
// Set the other e-mail address fields
|
|
if (pWabContactInfo && pWabContactInfo->pszaEmails && CIS_GETSTRING(pContactInfo, idcisEmail))
|
|
{
|
|
DWORD dw, cStrs;
|
|
BOOL fFound = FALSE;
|
|
|
|
cStrs = pWabContactInfo->pszaEmails->cValues;
|
|
|
|
for (dw = 0; dw < cStrs; dw ++)
|
|
{
|
|
if (lstrcmpiA(pWabContactInfo->pszaEmails->lppszA[dw], CIS_GETSTRING(pContactInfo, idcisEmail)) == 0)
|
|
{
|
|
pWabContactInfo->dwEmailIndex = dw;
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
SetMultiValueStringValue(pWabContactInfo->pszaEmails, CIS_GETSTRING(pContactInfo, idcisEmail), pWabContactInfo->dwEmailIndex);
|
|
}
|
|
|
|
ContactInfo_SetMVSZProp(PR_CONTACT_EMAIL_ADDRESSES, pWabContactInfo->pszaEmails, lpaProps, &dwLoc);
|
|
//set the index
|
|
lpaProps[dwLoc].ulPropTag = PR_CONTACT_DEFAULT_ADDRESS_INDEX;
|
|
lpaProps[dwLoc].dwAlignPad = 0;
|
|
lpaProps[dwLoc].Value.ul = pWabContactInfo->dwEmailIndex;
|
|
dwLoc ++;
|
|
}
|
|
#ifdef HM_GROUP_SYNCING
|
|
}
|
|
else
|
|
{
|
|
// [PaulHi] Implement group syncing. If we are synchronizing groups then the HM contact
|
|
// email string is a series of contact nicknames and one-off email names. Parse this
|
|
// string and add each group contact.
|
|
LPTSTR lptszEmailName = ConvertAtoW( CIS_GETSTRING(pContactInfo, idcisEmail) );
|
|
if (lptszEmailName)
|
|
{
|
|
LPTSTR * atszContacts = NULL;
|
|
LPTSTR * atszOneOffs = NULL;
|
|
ULONG cContacts = 0;
|
|
ULONG cOneOffs = 0;
|
|
ULONG ul;
|
|
|
|
// The atszContacts and atszOneOffs arrays are just pointers into the lptszEmailName
|
|
// buffer. So these arrays are only valid as long as lptszEmailName is valid.
|
|
hr = hrParseHMGroupEmail(lptszEmailName, &atszContacts, &cContacts, &atszOneOffs, &cOneOffs);
|
|
if (FAILED(hr))
|
|
{
|
|
LocalFreeAndNull(&lptszEmailName);
|
|
goto out;
|
|
}
|
|
|
|
// Add multi-value property tags as appropriate
|
|
if (cContacts)
|
|
hrCreateGroupMVBin(pWabSync, PR_WAB_DL_ENTRIES, atszContacts, cContacts, lpaProps, &dwLoc);
|
|
if (cOneOffs)
|
|
hrCreateGroupMVBin(pWabSync, PR_WAB_DL_ONEOFFS, atszOneOffs, cOneOffs, lpaProps, &dwLoc);
|
|
|
|
// cleanup
|
|
LocalFreeAndNull((LPVOID *)&atszContacts);
|
|
LocalFreeAndNull((LPVOID *)&atszOneOffs);
|
|
LocalFreeAndNull(&lptszEmailName);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// skip the first ones since we just did them
|
|
for (dwIndex = dwStartIndex; dwIndex < dwSize; dwIndex ++)
|
|
{
|
|
if (CIS_STRING == CIS_GETTYPE(dwIndex) && CIS_GETSTRING(pContactInfo, dwIndex))
|
|
{
|
|
LPTSTR lptsz = ConvertAtoW(CIS_GETSTRING(pContactInfo, dwIndex));
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Special group syncing logic
|
|
if (pContactInfo->tyContact == HTTPMAIL_CT_GROUP)
|
|
{
|
|
// Don't add email name for groups
|
|
if (dwIndex == idcisEmail)
|
|
continue;
|
|
|
|
// Copy the nickname to the display name property. All WAB DL items
|
|
// MUST have a PR_DISPLAY_NAME property. Since HM groups only contain
|
|
// a nickname use the nickname as the display name.
|
|
if (dwIndex == idcisNickName)
|
|
{
|
|
hr = ContactInfo_SetProp(PR_DISPLAY_NAME, lptsz, lpaProps, &dwLoc);
|
|
if (FAILED(hr))
|
|
{
|
|
LocalFreeAndNull(&lptsz);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
hr = ContactInfo_SetProp(rgPropMap[dwIndex], lptsz, lpaProps, &dwLoc);
|
|
LocalFreeAndNull(&lptsz);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
out:
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
static LONG _FindPropTag(ULONG ulPropTag)
|
|
{
|
|
LONG lIndex, lSize = ARRAYSIZE(rgPropMap);
|
|
|
|
// skip href
|
|
for (lIndex = 1; lIndex < lSize; lIndex ++)
|
|
{
|
|
if (rgPropMap[lIndex] == ulPropTag)
|
|
return lIndex;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
HRESULT ContactInfo_DetermineDeleteProps(LPHTTPCONTACTINFO pContactInfo, LPSPropTagArray prgRemoveProps)
|
|
{
|
|
LPSTR *pProps = (LPSTR *)pContactInfo;
|
|
LONG lSize = ARRAYSIZE(rgPropMap);
|
|
LONG dwIndex;
|
|
|
|
prgRemoveProps->cValues = 0;
|
|
|
|
for (dwIndex = CIS_FIRST_DATA_FIELD; dwIndex < lSize; dwIndex ++)
|
|
{
|
|
if (CIS_STRING == CIS_GETTYPE(dwIndex) && CIS_GETSTRING(pContactInfo, dwIndex) && *(CIS_GETSTRING(pContactInfo, dwIndex)) == 0)
|
|
{
|
|
prgRemoveProps->aulPropTag[prgRemoveProps->cValues++] = rgPropMap[dwIndex];
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT ContactInfo_PopulateProps(
|
|
LPWABSYNC pWabSync,
|
|
LPHTTPCONTACTINFO pContactInfo,
|
|
LPWABCONTACTINFO pWabContactInfo,
|
|
LPSPropValue lpaProps,
|
|
ULONG ulcProps,
|
|
ULONG ulObjectType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lSize = ARRAYSIZE(rgPropMap);
|
|
DWORD dwPropIndex = 0, dwLoc = 0;
|
|
ULONG i, ulPropTag;
|
|
LONG lIndex;
|
|
char szBuffer[255];
|
|
ULONG ulIndServerIDs = -1, ulIndContactIDs = -1, ulIndModtimes = -1, ulIndEmails = -1;
|
|
LPSTR lpszA = NULL;
|
|
|
|
// fix up the other prop tag array structure to take into account the variable values
|
|
// @todo [PaulHi] Instead of using explict numbers create an enum for the array
|
|
// indices so we can remain consistent.
|
|
rgPropMap[1] = PR_WAB_HOTMAIL_SERVERIDS;
|
|
rgPropMap[3] = PR_WAB_HOTMAIL_MODTIMES;
|
|
|
|
ZeroMemory(pContactInfo, sizeof(HTTPCONTACTINFO));
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Set the contact type flag (mail user or group contact)
|
|
if (ulObjectType == MAPI_DISTLIST)
|
|
{
|
|
// group contact
|
|
pContactInfo->tyContact = HTTPMAIL_CT_GROUP;
|
|
pWabContactInfo->ulContactType = HTTPMAIL_CT_GROUP;
|
|
}
|
|
else
|
|
{
|
|
// mail user contact
|
|
pContactInfo->tyContact = HTTPMAIL_CT_CONTACT;
|
|
pWabContactInfo->ulContactType = HTTPMAIL_CT_CONTACT;
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < ulcProps; i++)
|
|
{
|
|
ulPropTag = lpaProps[i].ulPropTag;
|
|
|
|
lIndex = _FindPropTag(ulPropTag);
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
if (lIndex >= 0 && lIndex != 2) // The index==2 array position is tyContact, which we set above.
|
|
#else
|
|
if (lIndex >= 0)
|
|
#endif
|
|
{
|
|
Assert(lIndex < lSize);
|
|
|
|
SafeCoMemFree(CIS_GETSTRING(pContactInfo, lIndex));
|
|
|
|
switch (PROP_TYPE(ulPropTag))
|
|
{
|
|
case PT_TSTRING:
|
|
Assert(CIS_STRING == CIS_GETTYPE(lIndex));
|
|
if (CIS_GETSTRING(pContactInfo, lIndex))
|
|
SafeCoMemFree(CIS_GETSTRING(pContactInfo, lIndex));
|
|
|
|
lpszA =
|
|
ConvertWtoA(lpaProps[i].Value.LPSZ);
|
|
CIS_GETSTRING(pContactInfo, lIndex) = _StrDup(lpszA);
|
|
LocalFreeAndNull(&lpszA);
|
|
if (!CIS_GETSTRING(pContactInfo, lIndex))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case PT_SYSTIME:
|
|
Assert(CIS_STRING == CIS_GETTYPE(lIndex));
|
|
if (SUCCEEDED(FileTimeToiso8601((FILETIME *) (&lpaProps[i].Value.ft), szBuffer)))
|
|
{
|
|
CIS_GETSTRING(pContactInfo, lIndex) = _StrDup(szBuffer);
|
|
if (!CIS_GETSTRING(pContactInfo, lIndex))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
if (PR_BIRTHDAY == ulPropTag && CIS_GETSTRING(pContactInfo, lIndex))
|
|
{
|
|
// fix it up to be a hotmail formatted date
|
|
_FixHotmailDate(CIS_GETSTRING(pContactInfo, lIndex));
|
|
}
|
|
break;
|
|
|
|
case PT_MV_TSTRING:
|
|
if (ulPropTag == PR_WAB_HOTMAIL_SERVERIDS)
|
|
ulIndServerIDs = i;
|
|
else if (ulPropTag == PR_WAB_HOTMAIL_MODTIMES)
|
|
ulIndModtimes = i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ulPropTag == PR_WAB_HOTMAIL_CONTACTIDS)
|
|
ulIndContactIDs = i;
|
|
else if (ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
|
|
ulIndEmails = i;
|
|
else if (ulPropTag == PR_CONTACT_DEFAULT_ADDRESS_INDEX)
|
|
pWabContactInfo->dwEmailIndex = lpaProps[i].Value.ul;
|
|
#ifdef HM_GROUP_SYNCING
|
|
else if ( (ulObjectType == MAPI_DISTLIST) &&
|
|
(ulPropTag == PR_WAB_DL_ENTRIES) || (ulPropTag == PR_WAB_DL_ONEOFFS) )
|
|
{
|
|
LPSTR lpszNewEmailName = CIS_GETSTRING(pContactInfo, idcisEmail);
|
|
hr = hrAppendGroupContact(pWabSync,
|
|
ulPropTag,
|
|
&lpaProps[i],
|
|
&lpszNewEmailName);
|
|
CIS_GETSTRING(pContactInfo, idcisEmail) = lpszNewEmailName;
|
|
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Group syncing. HM group contact information consists only of an email and nickname.
|
|
// The WAB group display name becomes the HM group nickname.
|
|
if (ulObjectType == MAPI_DISTLIST)
|
|
{
|
|
LPSTR lpszDisplayName = CIS_GETSTRING(pContactInfo, idcisDisplayName);
|
|
LPSTR lpszNickName = CIS_GETSTRING(pContactInfo, idcisNickName);
|
|
|
|
if (lpszDisplayName)
|
|
{
|
|
if (lpszNickName)
|
|
CoTaskMemFree(lpszNickName);
|
|
|
|
CIS_GETSTRING(pContactInfo, idcisDisplayName) = NULL;
|
|
|
|
// [PaulHi]
|
|
// A HM group nickname cannot contain certain characters. So we remove all
|
|
// invalid characters in the name string. This change will be reflected
|
|
// in the WAB group name too (yuck).
|
|
hrStripInvalidChars(lpszDisplayName);
|
|
CIS_GETSTRING(pContactInfo,idcisNickName) = lpszDisplayName;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// Likewise email contact nicknames cannot contain certain characters or
|
|
// the post to HM server will fail.
|
|
LPSTR lpszNickName = CIS_GETSTRING(pContactInfo, idcisNickName);
|
|
|
|
if (lpszNickName)
|
|
hrStripInvalidChars(lpszNickName);
|
|
}
|
|
|
|
|
|
if (ulIndEmails != -1)
|
|
{
|
|
if (pWabContactInfo->pszaEmails)
|
|
FreeMultiValueString(pWabContactInfo->pszaEmails);
|
|
hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndEmails].Value.MVSZ), &pWabContactInfo->pszaEmails);
|
|
}
|
|
|
|
// If we have the indexes to all of the multivalues that we care about,
|
|
// try to get the appropriate values for the current identity.
|
|
if (ulIndContactIDs != -1 && ulIndModtimes != -1 && ulIndServerIDs != -1)
|
|
{
|
|
ULONG ulMVIndex = -1;
|
|
UNALIGNED LPTSTR *lppszValues;
|
|
TCHAR szFullProfile[MAX_PATH];
|
|
|
|
// [PaulHi] Assemble the contact ID string
|
|
hr = hrMakeContactId(
|
|
szFullProfile,
|
|
MAX_PATH,
|
|
((LPIAB)(pWabSync->m_pAB))->szProfileID,
|
|
pWabSync->m_pszAccountId,
|
|
pWabSync->m_szLoginName);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
// sanity check, all three multi values must contain the same number
|
|
// of values. If not they are out of sync and not to be trusted.
|
|
|
|
if (lpaProps[ulIndContactIDs].Value.MVSZ.cValues != lpaProps[ulIndModtimes].Value.MVSZ.cValues ||
|
|
lpaProps[ulIndModtimes].Value.MVSZ.cValues != lpaProps[ulIndServerIDs].Value.MVSZ.cValues)
|
|
{
|
|
Assert(FALSE);
|
|
goto exit;
|
|
}
|
|
|
|
if (pWabContactInfo->pszaContactIds)
|
|
FreeMultiValueString(pWabContactInfo->pszaContactIds);
|
|
hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndContactIDs].Value.MVSZ), &pWabContactInfo->pszaContactIds);
|
|
|
|
if (pWabContactInfo->pszaServerIds)
|
|
FreeMultiValueString(pWabContactInfo->pszaServerIds);
|
|
hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndServerIDs].Value.MVSZ), &pWabContactInfo->pszaServerIds);
|
|
|
|
if (pWabContactInfo->pszaModtimes)
|
|
FreeMultiValueString(pWabContactInfo->pszaModtimes);
|
|
hr = CopyMultiValueString((SWStringArray *) (&lpaProps[ulIndModtimes].Value.MVSZ), &pWabContactInfo->pszaModtimes);
|
|
|
|
if (PROP_TYPE(lpaProps[ulIndContactIDs].ulPropTag) == PT_MV_TSTRING)
|
|
{
|
|
lppszValues = lpaProps[ulIndContactIDs].Value.MVSZ.LPPSZ;
|
|
|
|
// find the index for this identity
|
|
for (i = 0; i < lpaProps[ulIndContactIDs].Value.MVSZ.cValues; i++)
|
|
{
|
|
if (lstrcmp(szFullProfile, lppszValues[i]) == 0)
|
|
{
|
|
ulMVIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ulMVIndex != -1)
|
|
{
|
|
ULONG ulLen;
|
|
LPSTR lpVal = NULL;
|
|
lpVal = ConvertWtoA(lpaProps[ulIndServerIDs].Value.MVSZ.LPPSZ[ulMVIndex]);
|
|
//Copy the values for this identity to the structure
|
|
pContactInfo->pszId = _StrDup(lpVal);
|
|
LocalFreeAndNull(&lpVal);
|
|
if (!pContactInfo->pszId)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
lpVal = ConvertWtoA(lpaProps[ulIndModtimes].Value.MVSZ.LPPSZ[ulMVIndex]);
|
|
pContactInfo->pszModified = _StrDup(lpVal);
|
|
LocalFreeAndNull(&lpVal);
|
|
if (!pContactInfo->pszModified)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if (FAILED(hr))
|
|
{
|
|
ContactInfo_Free(pContactInfo);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT ContactInfo_SaveToWAB(LPWABSYNC pWabSync,
|
|
LPHTTPCONTACTINFO pContactInfo,
|
|
LPWABCONTACTINFO pWabContactInfo,
|
|
LPENTRYID lpEntryID,
|
|
ULONG cbEntryID,
|
|
BOOL fDeleteProps)
|
|
{
|
|
LPENTRYID pEntryID = NULL;
|
|
ULONG cbLocEntryID = 0;
|
|
HRESULT hr;
|
|
LPMAILUSER lpMailUser = NULL;
|
|
LPSPropValue lpaProps = NULL;
|
|
ULONG ulcProps = 0;
|
|
ULONG ulObjectType;
|
|
SCODE sc;
|
|
SBinary sBinary;
|
|
ULONG uli;
|
|
|
|
Assert(pWabSync);
|
|
Assert(pContactInfo);
|
|
Assert(pWabSync->m_pAB);
|
|
|
|
if (HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->GetPAB(pWabSync->m_pAB, &sBinary.cb, (LPENTRYID*)&sBinary.lpb)))
|
|
{
|
|
DebugPrintError(( TEXT("GetPAB Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
Assert(sBinary.lpb);
|
|
|
|
if (lpEntryID)
|
|
{
|
|
if (HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, // size of EntryID to open
|
|
lpEntryID, // EntryID to open
|
|
NULL, // interface
|
|
MAPI_MODIFY, // flags
|
|
&ulObjectType,
|
|
(LPUNKNOWN *) &lpMailUser)))
|
|
{
|
|
DebugPrintError(( TEXT("OpenEntry Failed\n")));
|
|
goto out;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef HM_GROUP_SYNCING
|
|
ULONG ulObjectType = (pWabSync->m_fSyncGroups) ? MAPI_DISTLIST : MAPI_MAILUSER;
|
|
#else
|
|
ULONG ulObjectType = MAPI_MAILUSER;
|
|
#endif
|
|
|
|
fDeleteProps = FALSE;
|
|
if (HR_FAILED(hr = HrCreateNewObject(pWabSync->m_pAB,
|
|
&sBinary,
|
|
ulObjectType,
|
|
CREATE_CHECK_DUP_STRICT,
|
|
(LPMAPIPROP *) &lpMailUser)))
|
|
{
|
|
DebugPrintError(( TEXT("HRCreateNewObject Failed\n")));
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
Assert(lpMailUser);
|
|
|
|
//Add one for the contact's identity id
|
|
ulcProps = ContactInfo_CountProperties(pContactInfo) + 1;
|
|
|
|
// make room for PR_CONTACT_DEFAULT_ADDRESS_INDEX and PR_CONTACT_EMAIL_ADDRESSES
|
|
// if we have the data to put in them
|
|
if (pWabContactInfo && pWabContactInfo->pszaEmails && CIS_GETSTRING(pContactInfo, idcisEmail))
|
|
ulcProps += 2;
|
|
|
|
// [PaulHi] @review 1/21/99
|
|
// make room for PR_WAB_HOTMAIL_SERVERIDS and PR_WAB_HOTMAIL_MODTIMES
|
|
// This part is ugly - only if these have not already been accounted for in pContactInfo
|
|
if (pWabContactInfo && pWabContactInfo->pszaContactIds)
|
|
{
|
|
if (!pContactInfo->pszModified)
|
|
ulcProps += 1;
|
|
if (!pContactInfo->pszId)
|
|
ulcProps += 1;
|
|
}
|
|
|
|
// Allocate a new buffer for the MAPI property array.
|
|
sc = MAPIAllocateBuffer(ulcProps * sizeof(SPropValue),
|
|
(LPVOID *)&lpaProps);
|
|
if (sc)
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto out;
|
|
}
|
|
|
|
// Initialize the Property array
|
|
ZeroMemory(lpaProps, (ulcProps*sizeof(SPropValue)));
|
|
for (uli=0; uli<ulcProps; uli++)
|
|
lpaProps[uli].ulPropTag = PR_NULL;
|
|
|
|
if(HR_FAILED(hr = ContactInfo_TranslateProps(pWabSync, pContactInfo, pWabContactInfo, lpaProps)))
|
|
{
|
|
DebugPrintError(( TEXT("ContactInfo_TranslateProps Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
// Set the old guys props on the new guy - note that this overwrites any common props on
|
|
// potential duplicates when calling savechanges
|
|
if(HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, ulcProps, lpaProps, NULL)))
|
|
{
|
|
DebugPrintError(( TEXT("SetProps Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
if (fDeleteProps)
|
|
{
|
|
SizedSPropTagArray(ARRAYSIZE(rgPropMap), rgRemoveProps) = {0};
|
|
|
|
ContactInfo_DetermineDeleteProps(pContactInfo, (LPSPropTagArray)&rgRemoveProps);
|
|
|
|
if (rgRemoveProps.cValues > 0)
|
|
hr = lpMailUser->lpVtbl->DeleteProps(lpMailUser, (LPSPropTagArray)&rgRemoveProps, NULL);
|
|
}
|
|
|
|
// SaveChanges
|
|
if(HR_FAILED(hr = lpMailUser->lpVtbl->SaveChanges(lpMailUser, KEEP_OPEN_READONLY)))
|
|
{
|
|
DebugPrintError(( TEXT("SaveChanges Failed\n")));
|
|
|
|
if (!lpEntryID && HR_FAILED(hr = ContactInfo_BlendNewContact(pWabSync, pContactInfo)))
|
|
DebugPrintError(( TEXT("ContactInfo_BlendNewContact Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
if (sBinary.lpb)
|
|
MAPIFreeBuffer(sBinary.lpb);
|
|
|
|
if (lpMailUser)
|
|
UlRelease(lpMailUser);
|
|
|
|
if (lpaProps)
|
|
MAPIFreeBuffer(lpaProps);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ContactInfo_BlendNewContact(LPWABSYNC pWabSync,
|
|
LPHTTPCONTACTINFO pContactInfo)
|
|
{
|
|
LPSPropValue lpaProps = NULL;
|
|
SizedADRLIST(1, rAdrList) = {0};
|
|
SCODE sc;
|
|
HRESULT hr = S_OK;
|
|
DWORD cbValue;
|
|
DWORD cCount = 0;
|
|
ULONG j = 0;
|
|
|
|
if (pContactInfo->pszDisplayName)
|
|
cCount++;
|
|
|
|
if (pContactInfo->pszEmail)
|
|
cCount++;
|
|
|
|
if (!cCount)
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
// Allocate a new buffer for the MAPI property array.
|
|
sc = MAPIAllocateBuffer(cCount * sizeof(SPropValue),
|
|
(LPVOID *)&lpaProps);
|
|
if (sc)
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto out;
|
|
}
|
|
|
|
cCount = 0;
|
|
if (pContactInfo->pszDisplayName)
|
|
{
|
|
lpaProps[cCount].ulPropTag = PR_DISPLAY_NAME;
|
|
lpaProps[cCount].dwAlignPad = 0;
|
|
if(sc = ScAnsiToWCMore((LPALLOCATEMORE )(&MAPIAllocateMore),(LPVOID) lpaProps, (LPSTR) pContactInfo->pszDisplayName, (LPWSTR *) (&(lpaProps[cCount].Value.LPSZ))))
|
|
goto out;
|
|
cCount++;
|
|
}
|
|
|
|
if (pContactInfo->pszEmail)
|
|
{
|
|
lpaProps[cCount].ulPropTag = PR_EMAIL_ADDRESS;
|
|
lpaProps[cCount].dwAlignPad = 0;
|
|
if(sc = ScAnsiToWCMore((LPALLOCATEMORE )(&MAPIAllocateMore),(LPVOID) lpaProps, (LPSTR) pContactInfo->pszEmail,(LPWSTR *) (&(lpaProps[cCount].Value.LPSZ))))
|
|
goto out;
|
|
cCount++;
|
|
}
|
|
|
|
rAdrList.cEntries = 1;
|
|
rAdrList.aEntries[0].cValues = cCount;
|
|
rAdrList.aEntries[0].rgPropVals = lpaProps;
|
|
|
|
hr = pWabSync->m_pAB->lpVtbl->ResolveName(pWabSync->m_pAB, (ULONG_PTR)pWabSync->m_hWnd,
|
|
WAB_RESOLVE_LOCAL_ONLY | WAB_RESOLVE_USE_CURRENT_PROFILE,
|
|
TEXT(""), (LPADRLIST)(&rAdrList));
|
|
|
|
lpaProps = NULL; //it was freed in ResolveName (!)
|
|
|
|
if (HR_FAILED(hr))
|
|
goto out;
|
|
|
|
for(j=0; j<rAdrList.aEntries[0].cValues; j++)
|
|
{
|
|
if(rAdrList.aEntries[0].rgPropVals[j].ulPropTag == PR_ENTRYID &&
|
|
rAdrList.aEntries[0].rgPropVals[j].Value.bin.lpb)
|
|
{
|
|
hr = ContactInfo_SaveToWAB(pWabSync,
|
|
pContactInfo,
|
|
NULL,
|
|
(LPENTRYID)rAdrList.aEntries[0].rgPropVals[j].Value.bin.lpb,
|
|
rAdrList.aEntries[0].rgPropVals[j].Value.bin.cb,
|
|
FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < rAdrList.cEntries; j++)
|
|
MAPIFreeBuffer(rAdrList.aEntries[j].rgPropVals);
|
|
|
|
out:
|
|
|
|
if (lpaProps)
|
|
MAPIFreeBuffer(lpaProps);
|
|
|
|
return hr;
|
|
}
|
|
|
|
void UpdateSynchronizeMenus(HMENU hMenu, LPIAB lpIAB)
|
|
{
|
|
DWORD cItems, dwIndex;
|
|
MENUITEMINFO mii;
|
|
TCHAR szLogoffString[255];
|
|
TCHAR szRes[255];
|
|
|
|
if (!IsHTTPMailEnabled(lpIAB))
|
|
{
|
|
// loop through the other menu items looking for logoff
|
|
cItems = GetMenuItemCount(hMenu);
|
|
|
|
mii.cbSize = sizeof(MENUITEMINFO);
|
|
mii.fMask = MIIM_ID;
|
|
|
|
for (dwIndex = cItems; dwIndex > 0; --dwIndex)
|
|
{
|
|
GetMenuItemInfo(hMenu, dwIndex, TRUE, &mii);
|
|
|
|
// if this is the logoff item, delete it and the separator
|
|
// line that follows
|
|
if (mii.wID == IDM_TOOLS_SYNCHRONIZE_NOW)
|
|
{
|
|
DeleteMenu(hMenu, dwIndex - 1, MF_BYPOSITION);
|
|
DeleteMenu(hMenu, IDM_TOOLS_SYNCHRONIZE_NOW, MF_BYCOMMAND);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if there are no http mail accounts, disable the menu item
|
|
if (CountHTTPMailAccounts(lpIAB) == 0)
|
|
EnableMenuItem(hMenu, IDM_TOOLS_SYNCHRONIZE_NOW, MF_BYCOMMAND | MF_GRAYED);
|
|
}
|
|
}
|
|
|
|
HRESULT ContactInfo_LoadFromWAB(LPWABSYNC pWabSync,
|
|
LPHTTPCONTACTINFO pContactInfo,
|
|
LPWABCONTACTINFO pWabContact,
|
|
LPENTRYID lpEntryID,
|
|
ULONG cbEntryID)
|
|
{
|
|
LPENTRYID pEntryID = NULL;
|
|
ULONG cbLocEntryID = 0;
|
|
HRESULT hr;
|
|
LPMAILUSER lpMailUser = NULL;
|
|
LPSPropValue lpaProps = NULL;
|
|
ULONG ulcProps = 0;
|
|
ULONG ulObjectType;
|
|
SCODE sc;
|
|
|
|
Assert(pWabSync);
|
|
Assert(pContactInfo);
|
|
Assert(lpEntryID);
|
|
Assert(pWabSync->m_pAB);
|
|
|
|
if(HR_FAILED(hr = pWabSync->m_pAB->lpVtbl->OpenEntry(pWabSync->m_pAB, cbEntryID, lpEntryID, NULL, 0, &ulObjectType, (LPUNKNOWN *) &lpMailUser)))
|
|
{
|
|
DebugPrintError(( TEXT("OpenEntry Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
if(HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, (LPSPropTagArray)(&ptaEidCSync), MAPI_UNICODE,
|
|
&ulcProps, &lpaProps)))
|
|
{
|
|
DebugPrintError(( TEXT("GetProps Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
if (HR_FAILED(hr = ContactInfo_PopulateProps(pWabSync, pContactInfo, pWabContact, lpaProps, ulcProps, ulObjectType)))
|
|
{
|
|
DebugPrintError(( TEXT("ContactInfo_PopulateProps Failed\n")));
|
|
goto out;
|
|
}
|
|
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Group sync. Don't break out a group display name
|
|
if ( (pContactInfo->tyContact == HTTPMAIL_CT_CONTACT) && pContactInfo->pszDisplayName &&
|
|
(!pContactInfo->pszGivenName || !pContactInfo->pszSurname) )
|
|
#else
|
|
if ( pContactInfo->pszDisplayName && (!pContactInfo->pszGivenName || !pContactInfo->pszSurname) )
|
|
#endif
|
|
{
|
|
LPVOID pBuffer;
|
|
LPTSTR pszFirstName = NULL, pszLastName = NULL;
|
|
LPTSTR lpName =
|
|
ConvertAtoW(pContactInfo->pszDisplayName);
|
|
if (ParseDisplayName(lpName, &pszFirstName, &pszLastName, NULL, &pBuffer))
|
|
{
|
|
LPSTR lp = NULL;
|
|
if (pszFirstName && !pContactInfo->pszGivenName)
|
|
{
|
|
lp = ConvertWtoA(pszFirstName);
|
|
pContactInfo->pszGivenName = _StrDup(lp);
|
|
LocalFreeAndNull(&lp);
|
|
}
|
|
if (pszLastName && !pContactInfo->pszSurname)
|
|
{
|
|
lp = ConvertWtoA(pszLastName);
|
|
pContactInfo->pszSurname = _StrDup(lp);
|
|
LocalFreeAndNull(&lp);
|
|
}
|
|
|
|
LocalFree(pBuffer);
|
|
}
|
|
LocalFreeAndNull(&lpName);
|
|
}
|
|
|
|
out:
|
|
if (lpMailUser)
|
|
UlRelease(lpMailUser);
|
|
|
|
if (lpaProps)
|
|
MAPIFreeBuffer(lpaProps);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
static BOOL _IsLegitNicknameChar(TCHAR ch)
|
|
{
|
|
if (ch >= 'A' && ch <= 'Z')
|
|
return TRUE;
|
|
if (ch >= 'a' && ch <= 'z')
|
|
return TRUE;
|
|
if (ch >= '0' && ch <= '9')
|
|
return TRUE;
|
|
if (ch == '-' || ch == '_')
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT ContactInfo_GenerateNickname(LPHTTPCONTACTINFO pContactInfo)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszStr;
|
|
|
|
if (NULL == pContactInfo->pszNickname)
|
|
{
|
|
if (pContactInfo->pszEmail)
|
|
{
|
|
pContactInfo->pszNickname = _StrDup(pContactInfo->pszEmail);
|
|
}
|
|
else if (pContactInfo->pszDisplayName)
|
|
{
|
|
pContactInfo->pszNickname = _StrDup(pContactInfo->pszDisplayName);
|
|
}
|
|
else
|
|
{
|
|
char szNickname[25], szFmt[25];
|
|
|
|
LoadStringA(hinstMapiX, idsNicknameFmt, szFmt, sizeof(szFmt));
|
|
if (*szFmt == 0)
|
|
StrCpyNA(szFmt, "Nickname%d", ARRAYSIZE(szFmt));
|
|
|
|
wnsprintfA(szNickname, ARRAYSIZE(szNickname), szFmt, ((DWORD)GetTickCount() & 0x0000FFFF));
|
|
pContactInfo->pszNickname = _StrDup(szNickname);
|
|
}
|
|
|
|
if (!pContactInfo->pszNickname)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pszStr = pContactInfo->pszNickname;
|
|
while (*pszStr)
|
|
{
|
|
// e-mail address should be unique enough...(?)
|
|
if (*pszStr == '@')
|
|
{
|
|
*pszStr = 0;
|
|
break;
|
|
}
|
|
|
|
if (!_IsLegitNicknameChar(*pszStr))
|
|
*pszStr = '_';
|
|
|
|
pszStr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char szNickname[25], szFmt[25];
|
|
|
|
SafeCoMemFree(pContactInfo->pszNickname);
|
|
LoadStringA(hinstMapiX, idsNicknameFmt, szFmt, sizeof(szFmt));
|
|
if (*szFmt == 0)
|
|
StrCpyNA(szFmt, "Nickname%d", ARRAYSIZE(szFmt));
|
|
|
|
wnsprintfA(szNickname, ARRAYSIZE(szNickname), szFmt, ((DWORD)GetTickCount() & 0x0000FFFF));
|
|
pContactInfo->pszNickname = _StrDup(szNickname);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL ContactInfo_Match(LPHTTPCONTACTINFO pciServer, LPHTTPCONTACTINFO pciClient)
|
|
{
|
|
LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
|
|
BOOL fResult = TRUE;
|
|
|
|
if (!pciServer)
|
|
return FALSE;
|
|
|
|
if (!pciClient)
|
|
return FALSE;
|
|
|
|
for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
|
|
{
|
|
if (CIS_GETSTRING(pciServer, i) && CIS_GETSTRING(pciClient, i))
|
|
{
|
|
if (lstrcmpA(CIS_GETSTRING(pciServer, i), CIS_GETSTRING(pciClient, i)))
|
|
return FALSE;
|
|
}
|
|
else if (CIS_GETSTRING(pciServer, i) || CIS_GETSTRING(pciClient, i))
|
|
{
|
|
if (idcisNickName == i && CIS_GETSTRING(pciServer, i))
|
|
fResult = FALSE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// if the only reason they don't match is the lack of local nickname and
|
|
// there is a server one, just copy the nickname locally
|
|
if (!fResult)
|
|
{
|
|
CIS_GETSTRING(pciClient, idcisNickName) = _StrDup(CIS_GETSTRING(pciServer, idcisNickName));
|
|
fResult = TRUE;
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
HRESULT ContactInfo_PreparePatch(LPHTTPCONTACTINFO pciFrom, LPHTTPCONTACTINFO pciTo)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
|
|
|
|
for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
|
|
{
|
|
if (CIS_GETSTRING(pciFrom, i) && !CIS_GETSTRING(pciTo, i))
|
|
{
|
|
CIS_GETSTRING(pciTo, i) = _StrDup("");
|
|
if (!CIS_GETSTRING(pciTo, i))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (CIS_GETSTRING(pciFrom, i) && CIS_GETSTRING(pciTo, i) && lstrcmpA(CIS_GETSTRING(pciFrom, i), CIS_GETSTRING(pciTo, i)) == 0)
|
|
SafeCoMemFree(CIS_GETSTRING(pciTo, i));
|
|
}
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ContactInfo_EmptyNullItems(LPHTTPCONTACTINFO pci)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
|
|
|
|
for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
|
|
{
|
|
if (CIS_GETSTRING(pci, i) == NULL)
|
|
CIS_GETSTRING(pci, i) = _StrDup("");
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT ContactInfo_BlendResults(LPHTTPCONTACTINFO pciServer, LPHTTPCONTACTINFO pciClient, CONFLICT_DECISION *prgDecisions)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG i, lSize = ARRAYSIZE(g_ContactInfoStructure);
|
|
|
|
for (i = CIS_FIRST_DATA_FIELD; i < lSize; i ++)
|
|
{
|
|
if (prgDecisions[i] == CONFLICT_SERVER)
|
|
{
|
|
SafeCoMemFree(CIS_GETSTRING(pciClient, i) );
|
|
if (CIS_GETSTRING(pciServer, i))
|
|
{
|
|
CIS_GETSTRING(pciClient, i) = _StrDup(CIS_GETSTRING(pciServer, i));
|
|
SafeCoMemFree(CIS_GETSTRING(pciServer, i));
|
|
}
|
|
else
|
|
CIS_GETSTRING(pciClient, i) = _StrDup("");
|
|
}
|
|
else if (prgDecisions[i] == CONFLICT_CLIENT)
|
|
{
|
|
SafeCoMemFree(CIS_GETSTRING(pciServer, i));
|
|
if (CIS_GETSTRING(pciClient, i))
|
|
CIS_GETSTRING(pciServer, i) = _StrDup(CIS_GETSTRING(pciClient, i));
|
|
else
|
|
CIS_GETSTRING(pciServer, i) = _StrDup("");
|
|
}
|
|
else
|
|
{
|
|
SafeCoMemFree(CIS_GETSTRING(pciClient, i));
|
|
SafeCoMemFree(CIS_GETSTRING(pciServer, i));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
INT_PTR CALLBACK SyncProgressDlgProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Locals
|
|
LPWABSYNC pWabSync = (LPWABSYNC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
pWabSync = (LPWABSYNC)lParam;
|
|
if (!pWabSync)
|
|
{
|
|
Assert (FALSE);
|
|
return 1;
|
|
}
|
|
#ifdef HM_GROUP_SYNCING
|
|
// [PaulHi] Implement group syncing. Identify what is currently
|
|
// being synchronized, email contacts or groups.
|
|
{
|
|
TCHAR rgtchCaption[MAX_PATH];
|
|
UINT uids = pWabSync->m_fSyncGroups ? idsSyncGroupsTitle : idsSyncContactsTitle;
|
|
|
|
rgtchCaption[0] = '\0';
|
|
LoadString(hinstMapiX, uids, rgtchCaption, MAX_PATH-1);
|
|
SetWindowText(hwnd, rgtchCaption);
|
|
}
|
|
#endif
|
|
CenterDialog (hwnd);
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pWabSync);
|
|
return 1;
|
|
|
|
case WM_SYNC_NEXTSTATE:
|
|
_WABSync_NextState(pWabSync);
|
|
break;
|
|
|
|
case WM_SYNC_NEXTOP:
|
|
if (!_WABSync_NextOp(pWabSync, (0 != wParam)))
|
|
WABSync_NextState(pWabSync);
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(GET_WM_COMMAND_ID(wParam,lParam))
|
|
{
|
|
case IDCANCEL:
|
|
if (pWabSync)
|
|
{
|
|
EnableWindow ((HWND)lParam, FALSE);
|
|
WABSync_Abort(pWabSync, E_UserCancel);
|
|
}
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// KillTimer(hwnd, IDT_PROGRESS_DELAY);
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) NULL);
|
|
break;
|
|
}
|
|
|
|
// Done
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CopyMultiValueString(
|
|
SWStringArray *pInArray,
|
|
SLPSTRArray **ppOutArray)
|
|
{
|
|
SLPSTRArray *pResult = NULL;
|
|
SCODE sc;
|
|
HRESULT hr;
|
|
DWORD i, cb;
|
|
|
|
*ppOutArray = NULL;
|
|
|
|
sc = MAPIAllocateBuffer(sizeof(SLPSTRArray),
|
|
(LPVOID *)&pResult);
|
|
if (sc)
|
|
goto fail;
|
|
|
|
pResult->cValues = pInArray->cValues;
|
|
|
|
sc = MAPIAllocateMore(sizeof(LPSTR) * pResult->cValues, pResult,
|
|
(LPVOID *)&(pResult->lppszA));
|
|
if (sc)
|
|
goto fail;
|
|
|
|
for (i = 0; i < pResult->cValues; i ++)
|
|
{
|
|
if(sc = ScWCToAnsiMore((LPALLOCATEMORE ) (&MAPIAllocateMore),(LPVOID) pResult, (LPWSTR) pInArray->LPPSZ[i], (LPSTR *) (&(pResult->lppszA[i]))))
|
|
goto fail;
|
|
}
|
|
|
|
*ppOutArray = pResult;
|
|
return S_OK;
|
|
|
|
fail:
|
|
hr = ResultFromScode(sc);
|
|
FreeMultiValueString(pResult);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT AppendToMultiValueString(SLPSTRArray *pInArray, LPSTR szStr)
|
|
{
|
|
LPSTR *ppStrA;
|
|
SCODE sc;
|
|
HRESULT hr;
|
|
DWORD i, cb;
|
|
|
|
ppStrA = pInArray->lppszA;
|
|
sc = MAPIAllocateMore(sizeof(LPSTR) * (pInArray->cValues + 1), pInArray,
|
|
(LPVOID *)&(pInArray->lppszA));
|
|
if (sc)
|
|
{
|
|
pInArray->lppszA = ppStrA;
|
|
goto fail;
|
|
}
|
|
|
|
CopyMemory(pInArray->lppszA, ppStrA, pInArray->cValues * sizeof(LPSTR));
|
|
|
|
cb = lstrlenA(szStr);
|
|
|
|
sc = MAPIAllocateMore(cb + 1, pInArray,
|
|
(LPVOID *)&(pInArray->lppszA[pInArray->cValues]));
|
|
if (sc)
|
|
goto fail;
|
|
|
|
StrCpyNA(pInArray->lppszA[pInArray->cValues], szStr, cb + 1);
|
|
pInArray->cValues++;
|
|
return S_OK;
|
|
|
|
fail:
|
|
hr = ResultFromScode(sc);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SetMultiValueStringValue(SLPSTRArray *pInArray, LPSTR szStr, DWORD dwIndex)
|
|
{
|
|
LPSTR *ppStrA;
|
|
SCODE sc;
|
|
HRESULT hr;
|
|
DWORD i, cb;
|
|
|
|
if (dwIndex >= pInArray->cValues)
|
|
return E_FAIL;
|
|
|
|
ppStrA = pInArray->lppszA;
|
|
|
|
cb = lstrlenA(szStr);
|
|
|
|
sc = MAPIAllocateMore(cb + 1, pInArray,
|
|
(LPVOID *)&(pInArray->lppszA[dwIndex]));
|
|
if (sc)
|
|
goto fail;
|
|
|
|
StrCpyNA(pInArray->lppszA[dwIndex], szStr, cb + 1);
|
|
return S_OK;
|
|
|
|
fail:
|
|
hr = ResultFromScode(sc);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT FreeMultiValueString(SLPSTRArray *pInArray)
|
|
{
|
|
if (pInArray)
|
|
MAPIFreeBuffer(pInArray);
|
|
|
|
return S_OK;
|
|
}
|