You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1749 lines
50 KiB
1749 lines
50 KiB
/*
|
|
* Messengr.C
|
|
*
|
|
* Migrate Communicator Messenger NAB <-> WAB
|
|
*
|
|
* Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* To Do:
|
|
* ObjectClass recognition
|
|
* Attribute mapping
|
|
* Groups
|
|
* Base64
|
|
* URLs
|
|
* Reject Change List MESS
|
|
*
|
|
*/
|
|
|
|
#include "_comctl.h"
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <mapix.h>
|
|
#include <wab.h>
|
|
#include <wabguid.h>
|
|
#include <wabdbg.h>
|
|
#include <wabmig.h>
|
|
#include <emsabtag.h>
|
|
#include "wabimp.h"
|
|
#include "..\..\wab32res\resrc2.h"
|
|
#include "dbgutil.h"
|
|
#include <shlwapi.h>
|
|
|
|
#define CR_CHAR 0x0d
|
|
#define LF_CHAR 0x0a
|
|
#define CCH_READ_BUFFER 1024
|
|
#define NUM_ITEM_SLOTS 32
|
|
|
|
/* Messenger address header
|
|
8-Display Name.
|
|
8-Nickname.
|
|
2-?
|
|
8-First Name.
|
|
8-?
|
|
8-last Name
|
|
8-Organization
|
|
8- City
|
|
8-State
|
|
8-e-mail
|
|
8- Notes
|
|
1- FF
|
|
8-Title
|
|
8-Address1
|
|
8-Zip
|
|
8-Work Phone
|
|
8-Fax
|
|
8- House phone.
|
|
18-?
|
|
8-Address
|
|
8-Country.
|
|
*/
|
|
|
|
typedef enum _MESS_ATTRIBUTES {
|
|
// PR_DISPLAY_NAME
|
|
m_DisplayName,
|
|
// PR_NICKNAME
|
|
m_Nickname, // Netscape nickname
|
|
//PR_GIVEN_NAME
|
|
m_FirstName,
|
|
//PR_SURNAME
|
|
m_LastName,
|
|
//PR_COMPANY_NAME
|
|
m_Organization,
|
|
// PR_LOCALITY
|
|
m_City, // locality (city)
|
|
// PR_STATE_OR_PROVINCE
|
|
m_State, // business address state
|
|
// PR_EMAIL_ADDRESS
|
|
m_Email, // email address
|
|
// PR_COMMENT
|
|
m_Notes,
|
|
//PR_TITLE,
|
|
m_Title,
|
|
// PR_STREET_ADDRESS
|
|
m_StreetAddress2,
|
|
// PR_POSTAL_CODE
|
|
m_Zip, // business address zip code
|
|
// PR_BUSINESS_TELEPHONE_NUMBER
|
|
m_WorkPhone,
|
|
// PR_BUSINESS_FAX_NUMBER
|
|
m_Fax,
|
|
// PR_HOME_TELEPHONE_NUMBER
|
|
m_HomePhone,
|
|
// PR_STREET_ADDRESS
|
|
m_StreetAddress1,
|
|
// PR_COUNTRY
|
|
m_Country, // country
|
|
m_Max,
|
|
} MESS_ATTRIBUTES, *LPMESS_ATTRIBUTES;
|
|
|
|
ULONG ulDefPropTags[] =
|
|
{
|
|
PR_DISPLAY_NAME,
|
|
PR_NICKNAME,
|
|
PR_GIVEN_NAME,
|
|
PR_SURNAME,
|
|
PR_COMPANY_NAME,
|
|
PR_LOCALITY,
|
|
PR_STATE_OR_PROVINCE,
|
|
PR_EMAIL_ADDRESS,
|
|
PR_COMMENT,
|
|
PR_TITLE,
|
|
PR_STREET_ADDRESS,
|
|
PR_POSTAL_CODE,
|
|
PR_BUSINESS_TELEPHONE_NUMBER,
|
|
PR_BUSINESS_FAX_NUMBER,
|
|
PR_HOME_TELEPHONE_NUMBER,
|
|
PR_STREET_ADDRESS,
|
|
PR_COUNTRY,
|
|
};
|
|
|
|
// All props are string props
|
|
typedef struct _MESS_RECORD {
|
|
LPTSTR lpData[m_Max];
|
|
ULONG ulObjectType;
|
|
} MESS_RECORD, *LPMESS_RECORD;
|
|
|
|
typedef struct _MESS_HEADER_ATTRIBUTES {
|
|
ULONG ulOffSet;
|
|
ULONG ulSize;
|
|
} MH_ATTR, * LPMH_ATTR;
|
|
|
|
typedef struct _MESS_BASIC_PROPS {
|
|
LPTSTR lpName;
|
|
LPTSTR lpEmail;
|
|
LPTSTR lpComment;
|
|
} MP_BASIC, * LPMP_BASIC;
|
|
|
|
typedef struct _MESS_STUFF {
|
|
ULONG ulOffSet;
|
|
ULONG ulNum;
|
|
MP_BASIC bp;
|
|
} MH_STUFF, * LPMH_STUFF;
|
|
|
|
typedef struct _MESS_ADDRESS_HEADER {
|
|
MH_ATTR prop[m_Max];
|
|
} MESS_HEADER, * LPMESS_HEADER;
|
|
|
|
// Must have
|
|
// PR_DISPLAY_NAME
|
|
#define NUM_MUST_HAVE_PROPS 1
|
|
|
|
const TCHAR szMESSFilter[] = "*.nab";
|
|
const TCHAR szMESSExt[] = "nab";
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
|
|
HrCreateAdrListFromMESSRecord
|
|
|
|
Scans an MESS record and turns all the "members" into an
|
|
unresolved AdrList
|
|
|
|
******************************************************************/
|
|
HRESULT HrCreateAdrListFromMESSRecord(ULONG nMembers,
|
|
LPMP_BASIC lpmp,
|
|
LPADRLIST * lppAdrList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG i;
|
|
LPADRLIST lpAdrList = NULL;
|
|
ULONG ulCount = 0;
|
|
|
|
*lppAdrList = NULL;
|
|
|
|
if(!nMembers)
|
|
goto exit;
|
|
|
|
// Now create a adrlist from these members
|
|
|
|
// Allocate prop value array
|
|
if (hr = ResultFromScode(WABAllocateBuffer(sizeof(ADRLIST) + nMembers * sizeof(ADRENTRY), &lpAdrList)))
|
|
goto exit;
|
|
|
|
ulCount = nMembers;
|
|
|
|
nMembers = 0;
|
|
|
|
for(i=0;i<ulCount;i++)
|
|
{
|
|
LPTSTR lpName = lpmp[i].lpName;
|
|
LPTSTR lpEmail = lpmp[i].lpEmail;
|
|
|
|
if(lpName)
|
|
{
|
|
LPSPropValue lpProp = NULL;
|
|
ULONG ulcProps = 2;
|
|
|
|
if (hr = ResultFromScode(WABAllocateBuffer(2 * sizeof(SPropValue), &lpProp)))
|
|
goto exit;
|
|
|
|
lpProp[0].ulPropTag = PR_DISPLAY_NAME;
|
|
|
|
if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpName)+1, lpProp, &(lpProp[0].Value.lpszA))))
|
|
goto exit;
|
|
|
|
StrCpyN(lpProp[0].Value.lpszA, lpName, lstrlen(lpName)+1);
|
|
|
|
if(lpEmail)
|
|
{
|
|
lpProp[1].ulPropTag = PR_EMAIL_ADDRESS;
|
|
|
|
if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpEmail)+1, lpProp, &(lpProp[1].Value.lpszA))))
|
|
goto exit;
|
|
|
|
StrCpyN(lpProp[1].Value.lpszA, lpEmail, lstrlen(lpEmail)+1);
|
|
}
|
|
lpAdrList->aEntries[nMembers].cValues = (lpEmail ? 2 : 1);
|
|
lpAdrList->aEntries[nMembers].rgPropVals = lpProp;
|
|
nMembers++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lpAdrList->cEntries = nMembers;
|
|
|
|
*lppAdrList = lpAdrList;
|
|
|
|
exit:
|
|
|
|
if(HR_FAILED(hr) && lpAdrList)
|
|
WABFreePadrlist(lpAdrList);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
|
|
HraddMESSDistList - adds a distlist and its members to the WAB
|
|
|
|
Sequence of events will be:
|
|
|
|
- Create a DistList object
|
|
- Set the properties on the DistList object
|
|
- Scan the list of members for the given dist list object
|
|
- Add each member to the wab .. if member already exists,
|
|
prompt to replace etc ...if it doesnt exist, create new
|
|
|
|
|
|
******************************************************************/
|
|
HRESULT HrAddMESSDistList(HWND hWnd,
|
|
LPABCONT lpContainer,
|
|
MH_STUFF HeadDL,
|
|
ULONG ulcNumDLMembers,
|
|
LPMP_BASIC lpmp,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
LPMAPIPROP lpDistListWAB = NULL;
|
|
LPDISTLIST lpDLWAB = NULL;
|
|
ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
|
|
REPLACE_INFO RI;
|
|
LPADRLIST lpAdrList = NULL;
|
|
LPFlagList lpfl = NULL;
|
|
ULONG ulcValues = 0;
|
|
LPSPropValue lpPropEID = NULL;
|
|
ULONG i, cbEIDNew;
|
|
LPENTRYID lpEIDNew;
|
|
ULONG ulObjectTypeOpen;
|
|
SPropValue Prop[3];
|
|
ULONG cProps = 0;
|
|
LPTSTR lpDisplayName = HeadDL.bp.lpName;
|
|
|
|
Prop[cProps].ulPropTag = PR_DISPLAY_NAME;
|
|
Prop[cProps].Value.LPSZ = HeadDL.bp.lpName;
|
|
|
|
if(!HeadDL.bp.lpName)
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
cProps++;
|
|
|
|
Prop[cProps].ulPropTag = PR_OBJECT_TYPE;
|
|
Prop[cProps].Value.l = MAPI_DISTLIST;
|
|
|
|
cProps++;
|
|
|
|
if(HeadDL.bp.lpComment)
|
|
{
|
|
Prop[cProps].ulPropTag = PR_COMMENT;
|
|
Prop[cProps].Value.LPSZ = HeadDL.bp.lpComment;
|
|
cProps++;
|
|
}
|
|
|
|
//if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
|
|
// Force a replace - collision will only be for groups and we dont care really
|
|
{
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
}
|
|
|
|
retry:
|
|
// Create a new wab distlist
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
|
|
lpContainer,
|
|
lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.cb,
|
|
(LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.lpb,
|
|
ulCreateFlags,
|
|
(LPMAPIPROP *) &lpDistListWAB)))
|
|
{
|
|
DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the properties on the new WAB entry
|
|
if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SetProps( lpDistListWAB,
|
|
cProps, // cValues
|
|
(LPSPropValue) &Prop, // property array
|
|
NULL))) // problems array
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SaveChanges(lpDistListWAB,
|
|
KEEP_OPEN_READWRITE | FORCE_SAVE)))
|
|
{
|
|
if (GetScode(hResult) == MAPI_E_COLLISION)
|
|
{
|
|
// Find the display name
|
|
Assert(lpDisplayName);
|
|
|
|
if (! lpDisplayName)
|
|
{
|
|
DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Do we need to prompt?
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
|
|
{
|
|
// Prompt user with dialog. If they say YES, we should try again
|
|
|
|
|
|
RI.lpszDisplayName = lpDisplayName;
|
|
RI.lpszEmailAddress = NULL; //lpEmailAddress;
|
|
RI.ConfirmResult = CONFIRM_ERROR;
|
|
RI.lpImportOptions = lpOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ImportReplace),
|
|
hWnd,
|
|
ReplaceDialogProc,
|
|
(LPARAM)&RI);
|
|
|
|
switch (RI.ConfirmResult)
|
|
{
|
|
case CONFIRM_YES:
|
|
case CONFIRM_YES_TO_ALL:
|
|
// YES
|
|
// NOTE: recursive Migrate will fill in the SeenList entry
|
|
// go try again!
|
|
lpDistListWAB->lpVtbl->Release(lpDistListWAB);
|
|
lpDistListWAB = NULL;
|
|
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
goto retry;
|
|
break;
|
|
|
|
case CONFIRM_ABORT:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
|
|
default:
|
|
// NO
|
|
break;
|
|
}
|
|
}
|
|
hResult = hrSuccess;
|
|
|
|
} else
|
|
{
|
|
DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
}
|
|
}
|
|
|
|
|
|
// Now we've created the Distribution List object .. we need to add members to it ..
|
|
//
|
|
// What is the ENTRYID of our new entry?
|
|
if ((hResult = lpDistListWAB->lpVtbl->GetProps(lpDistListWAB,
|
|
(LPSPropTagArray)&ptaEid,
|
|
0,
|
|
&ulcValues,
|
|
&lpPropEID)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
cbEIDNew = lpPropEID->Value.bin.cb;
|
|
lpEIDNew = (LPENTRYID) lpPropEID->Value.bin.lpb;
|
|
|
|
if(!cbEIDNew || !lpEIDNew)
|
|
goto exit;
|
|
|
|
// Open the new WAB DL as a DISTLIST object
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->OpenEntry(lpContainer,
|
|
cbEIDNew,
|
|
lpEIDNew,
|
|
(LPIID)&IID_IDistList,
|
|
MAPI_MODIFY,
|
|
&ulObjectTypeOpen,
|
|
(LPUNKNOWN*)&lpDLWAB)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if(!ulcNumDLMembers)
|
|
{
|
|
hResult = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
// First we create a lpAdrList with all the members of this dist list and try to resolve
|
|
// the members against the container .. entries that already exist in the WAB will come
|
|
// back as resolved .. entries that dont exist in the container will come back as unresolved
|
|
// We can then add the unresolved entries as fresh entries to the wab (since they are
|
|
// unresolved, there will be no collision) .. and then we can do another resolvenames to
|
|
// resolve everything and get a lpAdrList full of EntryIDs .. we can then take this list of
|
|
// entryids and call CreateEntry or CopyEntry on the DistList object to copy the entryid into
|
|
// the distlist ...
|
|
|
|
hResult = HrCreateAdrListFromMESSRecord(ulcNumDLMembers, lpmp, &lpAdrList);
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
if(!lpAdrList || !(lpAdrList->cEntries))
|
|
goto exit;
|
|
|
|
// Create a corresponding flaglist
|
|
lpfl = LocalAlloc(LMEM_ZEROINIT, sizeof(FlagList) + (lpAdrList->cEntries)*sizeof(ULONG));
|
|
if(!lpfl)
|
|
{
|
|
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
lpfl->cFlags = lpAdrList->cEntries;
|
|
|
|
// set all the flags to unresolved
|
|
for(i=0;i<lpAdrList->cEntries;i++)
|
|
lpfl->ulFlag[i] = MAPI_UNRESOLVED;
|
|
|
|
hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
// All the entries in the list that are resolved, already exist in the address book.
|
|
|
|
// The ones that are not resolved need to be added silently to the address book ..
|
|
for(i=0;i<lpAdrList->cEntries;i++)
|
|
{
|
|
if(lpfl->ulFlag[i] == MAPI_UNRESOLVED)
|
|
{
|
|
LPMAPIPROP lpMailUser = NULL;
|
|
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
|
|
lpContainer,
|
|
lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
|
|
(LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
|
|
0,
|
|
&lpMailUser)))
|
|
{
|
|
continue;
|
|
//goto exit;
|
|
}
|
|
|
|
if(lpMailUser)
|
|
{
|
|
// Set the properties on the new WAB entry
|
|
if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
|
|
lpAdrList->aEntries[i].cValues,
|
|
lpAdrList->aEntries[i].rgPropVals,
|
|
NULL)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpMailUser->lpVtbl->SaveChanges(lpMailUser,
|
|
KEEP_OPEN_READONLY | FORCE_SAVE)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
lpMailUser->lpVtbl->Release(lpMailUser);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// now that we've added all the unresolved members to the WAB, we call ResolveNames
|
|
// again .. as a result, every member in this list will be resolved and we will
|
|
// have entryids for all of them
|
|
// We will then take these entryids and add them to the DistList object
|
|
|
|
hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
|
|
|
|
if(hResult==MAPI_E_AMBIGUOUS_RECIP)
|
|
hResult = S_OK;
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
for(i=0;i<lpAdrList->cEntries;i++)
|
|
{
|
|
if(lpfl->ulFlag[i] == MAPI_RESOLVED)
|
|
{
|
|
ULONG j = 0;
|
|
LPSPropValue lpProp = lpAdrList->aEntries[i].rgPropVals;
|
|
|
|
for(j=0; j<lpAdrList->aEntries[i].cValues; j++)
|
|
{
|
|
if(lpProp[j].ulPropTag == PR_ENTRYID)
|
|
{
|
|
LPMAPIPROP lpMapiProp = NULL;
|
|
|
|
//ignore errors
|
|
lpDLWAB->lpVtbl->CreateEntry(lpDLWAB,
|
|
lpProp[j].Value.bin.cb,
|
|
(LPENTRYID) lpProp[j].Value.bin.lpb,
|
|
0,
|
|
&lpMapiProp);
|
|
|
|
if(lpMapiProp)
|
|
{
|
|
lpMapiProp->lpVtbl->SaveChanges(lpMapiProp, KEEP_OPEN_READWRITE | FORCE_SAVE);
|
|
lpMapiProp->lpVtbl->Release(lpMapiProp);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if (lpPropEID)
|
|
WABFreeBuffer(lpPropEID);
|
|
|
|
if (lpDLWAB)
|
|
lpDLWAB->lpVtbl->Release(lpDLWAB);
|
|
|
|
if(lpDistListWAB)
|
|
lpDistListWAB->lpVtbl->Release(lpDistListWAB);
|
|
|
|
if(lpAdrList)
|
|
WABFreePadrlist(lpAdrList);
|
|
|
|
if(lpfl)
|
|
LocalFree(lpfl);
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
|
|
HraddMESSMailUser - adds a mailuser to the WAB
|
|
|
|
**********************************************************/
|
|
HRESULT HrAddMESSMailUser(HWND hWnd,
|
|
LPABCONT lpContainer,
|
|
LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress,
|
|
ULONG cProps,
|
|
LPSPropValue lpspv,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
LPMAPIPROP lpMailUserWAB = NULL;
|
|
ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
|
|
REPLACE_INFO RI;
|
|
|
|
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
|
|
{
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
}
|
|
|
|
|
|
retry:
|
|
// Create a new wab mailuser
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
|
|
lpContainer,
|
|
lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
|
|
(LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
|
|
ulCreateFlags,
|
|
&lpMailUserWAB)))
|
|
{
|
|
DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the properties on the new WAB entry
|
|
if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SetProps( lpMailUserWAB,
|
|
cProps, // cValues
|
|
lpspv, // property array
|
|
NULL))) // problems array
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SaveChanges(lpMailUserWAB,
|
|
KEEP_OPEN_READONLY | FORCE_SAVE)))
|
|
{
|
|
if (GetScode(hResult) == MAPI_E_COLLISION)
|
|
{
|
|
// Find the display name
|
|
Assert(lpDisplayName);
|
|
|
|
if (! lpDisplayName)
|
|
{
|
|
DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Do we need to prompt?
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
|
|
{
|
|
// Prompt user with dialog. If they say YES, we should try again
|
|
|
|
|
|
RI.lpszDisplayName = lpDisplayName;
|
|
RI.lpszEmailAddress = lpEmailAddress;
|
|
RI.ConfirmResult = CONFIRM_ERROR;
|
|
RI.lpImportOptions = lpOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ImportReplace),
|
|
hWnd,
|
|
ReplaceDialogProc,
|
|
(LPARAM)&RI);
|
|
|
|
switch (RI.ConfirmResult)
|
|
{
|
|
case CONFIRM_YES:
|
|
case CONFIRM_YES_TO_ALL:
|
|
// YES
|
|
// NOTE: recursive Migrate will fill in the SeenList entry
|
|
// go try again!
|
|
lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
|
|
lpMailUserWAB = NULL;
|
|
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
goto retry;
|
|
break;
|
|
|
|
case CONFIRM_ABORT:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
|
|
default:
|
|
// NO
|
|
break;
|
|
}
|
|
}
|
|
hResult = hrSuccess;
|
|
|
|
} else
|
|
{
|
|
DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if(lpMailUserWAB)
|
|
lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
|
|
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : MapMESSRecordtoProps
|
|
|
|
Purpose : Map the MESS record attributes to WAB properties
|
|
|
|
Parameters: lpMESSRecord -> MESS record
|
|
lpspv -> prop value array (pre-allocated)
|
|
lpcProps -> returned number of properties
|
|
lppDisplayName -> returned display name
|
|
lppEmailAddress -> returned email address (or NULL)
|
|
|
|
Returns : HRESULT
|
|
|
|
***************************************************************************/
|
|
HRESULT MapMESSRecordtoProps( LPMESS_RECORD lpMESSRecord,
|
|
LPSPropValue * lppspv, LPULONG lpcProps,
|
|
LPTSTR * lppDisplayName, LPTSTR *lppEmailAddress)
|
|
{
|
|
HRESULT hResult = hrSuccess;
|
|
ULONG cPropVals = m_Max + 1; // PR_OBJECT_TYPE
|
|
ULONG iProp = 0;
|
|
ULONG i;
|
|
ULONG iTable;
|
|
ULONG cProps = cPropVals;
|
|
|
|
// Allocate prop value array
|
|
if (hResult = ResultFromScode(WABAllocateBuffer(cProps * sizeof(SPropValue), lppspv))) {
|
|
DebugTrace("WABAllocateBuffer -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Fill with PR_NULL
|
|
for (i = 0; i < cProps; i++) {
|
|
(*lppspv)[i].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
iProp = 0;
|
|
|
|
for(i=0; i<m_Max; i++)
|
|
{
|
|
if(lpMESSRecord->lpData[i] && lstrlen(lpMESSRecord->lpData[i]))
|
|
{
|
|
(*lppspv)[iProp].ulPropTag = ulDefPropTags[i];
|
|
(*lppspv)[iProp].Value.LPSZ = lpMESSRecord->lpData[i];
|
|
switch((*lppspv)[iProp].ulPropTag)
|
|
{
|
|
case PR_DISPLAY_NAME:
|
|
*lppDisplayName = (*lppspv)[iProp].Value.LPSZ;
|
|
break;
|
|
case PR_EMAIL_ADDRESS:
|
|
*lppEmailAddress = (*lppspv)[iProp].Value.LPSZ;
|
|
break;
|
|
}
|
|
iProp++;
|
|
}
|
|
}
|
|
(*lppspv)[iProp].ulPropTag = PR_OBJECT_TYPE;
|
|
(*lppspv)[iProp].Value.l = lpMESSRecord->ulObjectType;
|
|
|
|
*lpcProps = iProp;
|
|
|
|
exit:
|
|
return(hResult);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FreeMESSRecord
|
|
|
|
Purpose : Frees an MESS record structure
|
|
|
|
Parameters: lpMESSRecord -> record to clean up
|
|
ulAttributes = number of attributes in lpMESSRecord
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
void FreeMESSRecord(LPMESS_RECORD lpMESSRecord)
|
|
{
|
|
ULONG i;
|
|
|
|
if (lpMESSRecord)
|
|
{
|
|
for (i = 0; i < m_Max; i++)
|
|
{
|
|
if (lpMESSRecord->lpData[i])
|
|
LocalFree(lpMESSRecord->lpData[i]);
|
|
}
|
|
LocalFree(lpMESSRecord);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FunctionName: GetOffSet
|
|
Purpose : Gets 4 bytes from the offset specified.
|
|
Parameters : hFile -pointer to the file
|
|
Offset-Offset of the
|
|
OffSetValue -the returned 4 bytes.
|
|
Returns :
|
|
Note :
|
|
***************************************************************************/
|
|
BOOL GetOffSet(HANDLE hFile, DWORD Offset, ULONG* lpOffSetValue)
|
|
{
|
|
BYTE Value[4];
|
|
|
|
DWORD dwRead = 0;
|
|
|
|
SetFilePointer(hFile, Offset, NULL, FILE_BEGIN);
|
|
|
|
ReadFile(hFile, Value, 4, &dwRead, NULL);
|
|
|
|
*(lpOffSetValue)= (ULONG)Value[0]*16777216 + (ULONG)Value[1]*65536 + (ULONG)Value[2]*256 + (ULONG)Value[3];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* FUNCTION NAME:GetMESSFileName
|
|
*
|
|
* PURPOSE: Gets the Messenger Address book file name
|
|
*
|
|
* PARAMETERS: szFileName = buffer containing the installation path
|
|
// Messenger abook is generally abook.nab
|
|
// Location can be found under
|
|
// HKLM\Software\Netscape\Netscape Navigator\Users\defaultuser
|
|
// Look for "DirRoot"
|
|
*
|
|
* RETURNS: HRESULT
|
|
******************************************************************************/
|
|
HRESULT GetNABPath(LPTSTR szFileName, DWORD cbFileName)
|
|
{
|
|
HKEY phkResult = NULL;
|
|
LONG Registry;
|
|
BOOL bResult;
|
|
TCHAR *lpData = NULL, *RegPath = NULL, *path = NULL;
|
|
DWORD dwSize = cbFileName;
|
|
|
|
LPTSTR lpRegMess = TEXT("Software\\Netscape\\Netscape Navigator\\Users");
|
|
LPTSTR lpRegUser = TEXT("CurrentUser");
|
|
LPTSTR lpRegKey = TEXT("DirRoot");
|
|
LPTSTR lpNABFile = TEXT("\\abook.nab");
|
|
|
|
HRESULT hResult = S_OK;
|
|
TCHAR szUser[MAX_PATH];
|
|
TCHAR szUserPath[2*MAX_PATH];
|
|
|
|
*szFileName = '\0';
|
|
*szUser ='\0';
|
|
|
|
// Open the Netscape..Users key
|
|
Registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegMess, 0, KEY_QUERY_VALUE, &phkResult);
|
|
if (Registry != ERROR_SUCCESS)
|
|
{
|
|
hResult = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
// Look for the CurrentUser
|
|
dwSize = sizeof(szUser);
|
|
Registry = RegQueryValueEx(phkResult, lpRegUser, NULL, NULL, (LPBYTE)szUser, &dwSize);
|
|
if (Registry != ERROR_SUCCESS)
|
|
{
|
|
hResult = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
if(!lstrlen(szUser))
|
|
{
|
|
hResult = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
if (phkResult) {
|
|
RegCloseKey(phkResult);
|
|
}
|
|
|
|
//Now concatenate the currentuser to the end of the Netscape key and reopen
|
|
StrCpyN(szUserPath, lpRegMess, ARRAYSIZE(szUserPath));
|
|
StrCatBuff(szUserPath, TEXT("\\"), ARRAYSIZE(szUserPath));
|
|
StrCatBuff(szUserPath, szUser, ARRAYSIZE(szUserPath));
|
|
|
|
// Open the Netscape..Users key
|
|
Registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szUserPath, 0, KEY_QUERY_VALUE, &phkResult);
|
|
if (Registry != ERROR_SUCCESS)
|
|
{
|
|
hResult = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
dwSize = cbFileName;
|
|
Registry = RegQueryValueEx(phkResult, lpRegKey, NULL, NULL, (LPBYTE)szFileName, &dwSize);
|
|
if (Registry != ERROR_SUCCESS)
|
|
{
|
|
hResult = E_FAIL;
|
|
goto error;
|
|
}
|
|
|
|
// concatenate the file name to this directory path
|
|
StrCatBuff(szFileName,lpNABFile, cbFileName/sizeof(szFileName[0]));
|
|
|
|
error:
|
|
|
|
if (phkResult) {
|
|
RegCloseKey(phkResult);
|
|
}
|
|
|
|
return(hResult);
|
|
|
|
}
|
|
|
|
HRESULT ReadMESSHeader(HANDLE hFile, LPMESS_HEADER lpmh, ULONG ulOffSet)
|
|
{
|
|
ULONG ulMagicNumber = 0;
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwRead;
|
|
ULONG i = 0;
|
|
|
|
// Skip 2 bytes
|
|
SetFilePointer(hFile, 2, NULL, FILE_CURRENT);
|
|
ulOffSet += 2;
|
|
|
|
GetOffSet(hFile, ulOffSet, &ulMagicNumber);
|
|
|
|
if(ulMagicNumber != 0x00000001 )
|
|
goto exit;
|
|
|
|
ulOffSet += 4;
|
|
|
|
for(i=0;i<m_Max;i++)
|
|
{
|
|
switch(i)
|
|
{
|
|
case m_FirstName:
|
|
ulOffSet += 2;
|
|
break;
|
|
case m_LastName:
|
|
ulOffSet += 8;
|
|
break;
|
|
case m_Title:
|
|
ulOffSet += 1;
|
|
break;
|
|
case m_StreetAddress1:
|
|
ulOffSet += 18;
|
|
break;
|
|
}
|
|
|
|
GetOffSet(hFile, ulOffSet, &(lpmh->prop[i].ulOffSet));
|
|
ulOffSet += 4;
|
|
GetOffSet(hFile, ulOffSet, &(lpmh->prop[i].ulSize));
|
|
ulOffSet += 4;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FunctionName: GetHeaders
|
|
|
|
Purpose :Reads the binary trees ( address binary tree or Dls binary tree) into an array.
|
|
|
|
Parameters : nLayer= Number of layers in the binary tree.
|
|
Offset= Primary offset of the binary tree.
|
|
pHeaders= Array in which the Address entry header offsets and their numbers are to be stored.
|
|
bflag = 1 should be passed when this recursive function is called for the first time.
|
|
Returns :
|
|
|
|
Note : //This function is a recursive function which reads the binary tree and stores the Offset values
|
|
and the address numbers in a Array.
|
|
|
|
***************************************************************************/
|
|
BOOL GetHeaders(HANDLE pFile, int nLayer, ULONG Offset, LPMH_STUFF pHeaders, BOOL bflag)
|
|
{
|
|
static ULONG ulCount =0; //keeps trecat of the number of element
|
|
ULONG nLoops =0;
|
|
ULONG ulNewOffset =0;
|
|
ULONG ulElement = 0;
|
|
|
|
if(bflag==1)
|
|
ulCount =0;
|
|
|
|
//get the number of elements in this header
|
|
if(Offset==0)
|
|
nLoops=32;
|
|
else
|
|
{
|
|
GetOffSet( pFile, Offset+4,&nLoops);
|
|
nLoops &= 0x0000FFFF;
|
|
}
|
|
|
|
|
|
for(ulElement = 0; ulElement < nLoops; ulElement++)
|
|
{
|
|
if(nLayer > 0)
|
|
{
|
|
ulNewOffset=0;
|
|
if(Offset!=0)
|
|
{
|
|
GetOffSet(pFile, Offset+8+(ulElement*4), &ulNewOffset);
|
|
{
|
|
ULONG ulMagicNumber=0;
|
|
GetOffSet(pFile,ulNewOffset+2,&ulMagicNumber);
|
|
if(ulMagicNumber != 1)
|
|
ulNewOffset = 0;
|
|
}
|
|
}
|
|
|
|
//call this function recursively
|
|
GetHeaders( pFile, nLayer-1, ulNewOffset, pHeaders, 0);
|
|
|
|
}
|
|
else
|
|
{
|
|
//fill the array here (offset)
|
|
pHeaders[ulCount].ulOffSet=pHeaders[ulCount].ulNum=0;
|
|
|
|
if(Offset!=0)
|
|
{
|
|
GetOffSet(pFile, Offset+8+(ulElement*8),& (pHeaders[ulCount].ulOffSet));
|
|
|
|
//fill the array element here (address number in case of addresses and size in case of messages)
|
|
if(!GetOffSet(pFile, Offset+12+(ulElement*8), &(pHeaders[ulCount].ulNum)))
|
|
{
|
|
pHeaders[ulCount].ulNum=0;
|
|
}
|
|
}
|
|
|
|
ulCount++; //increment the count
|
|
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ReadMESSRecord
|
|
|
|
Purpose : Reads a record from an MESS file with fixups for special characters
|
|
|
|
Parameters: hFile = file handle
|
|
|
|
Returns : HRESULT
|
|
|
|
***************************************************************************/
|
|
HRESULT ReadMESSRecord(HANDLE hFile, LPMESS_RECORD * lppMESSRecord, ULONG ulContactOffset)
|
|
{
|
|
HRESULT hResult = hrSuccess;
|
|
PUCHAR lpBuffer = NULL;
|
|
ULONG cbBuffer = 0;
|
|
ULONG cbReadFile = 1;
|
|
ULONG iItem = 0;
|
|
ULONG cAttributes = 0;
|
|
BOOL fEOR = FALSE;
|
|
LPMESS_RECORD lpMESSRecord = NULL;
|
|
LPBYTE lpData = NULL;
|
|
LPTSTR lpName = NULL;
|
|
ULONG cbData;
|
|
TCHAR szTemp[2048]; // 2k limit
|
|
ULONG i = 0;
|
|
DWORD dwRead = 0;
|
|
ULONG cchSize = 0;
|
|
|
|
MESS_HEADER mh = {0};
|
|
|
|
// The Contact Offset gives us the offset of the header for this record - the
|
|
// header contains the offset and the size of each property for that address
|
|
if(hResult = ReadMESSHeader(hFile, &mh, ulContactOffset))
|
|
goto exit;
|
|
|
|
lpMESSRecord = LocalAlloc(LMEM_ZEROINIT, sizeof(MESS_RECORD));
|
|
if(!lpMESSRecord)
|
|
{
|
|
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
lpMESSRecord->ulObjectType = MAPI_MAILUSER;
|
|
|
|
for(i=0;i<m_Max;i++)
|
|
{
|
|
if(mh.prop[i].ulSize)
|
|
{
|
|
if(i == m_StreetAddress1)
|
|
{
|
|
cchSize = mh.prop[i].ulSize + mh.prop[m_StreetAddress2].ulSize + 8;
|
|
|
|
lpMESSRecord->lpData[i] = LocalAlloc(LMEM_ZEROINIT, cchSize);
|
|
}
|
|
else
|
|
lpMESSRecord->lpData[i] = LocalAlloc(LMEM_ZEROINIT, mh.prop[i].ulSize);
|
|
if(lpMESSRecord->lpData[i])
|
|
{
|
|
SetFilePointer(hFile, mh.prop[i].ulOffSet, NULL, FILE_BEGIN);
|
|
ReadFile(hFile, (LPVOID) lpMESSRecord->lpData[i], mh.prop[i].ulSize, &dwRead, NULL);
|
|
lpMESSRecord->lpData[i][mh.prop[i].ulSize-1] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
//Fix the fact that the street address is split into street1 and street2
|
|
if(lpMESSRecord->lpData[m_StreetAddress1] && lpMESSRecord->lpData[m_StreetAddress2] &&
|
|
lstrlen(lpMESSRecord->lpData[m_StreetAddress1]) && lstrlen(lpMESSRecord->lpData[m_StreetAddress2]))
|
|
{
|
|
StrCatBuff(lpMESSRecord->lpData[m_StreetAddress1], TEXT("\r\n"), cchSize);
|
|
StrCatBuff(lpMESSRecord->lpData[m_StreetAddress1], lpMESSRecord->lpData[m_StreetAddress2], cchSize);
|
|
LocalFree(lpMESSRecord->lpData[m_StreetAddress2]);
|
|
lpMESSRecord->lpData[m_StreetAddress2] = NULL;
|
|
}
|
|
|
|
*lppMESSRecord = lpMESSRecord;
|
|
exit:
|
|
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
GetAllDLNames
|
|
|
|
Purpose : Gets the Names of all the DLs.
|
|
|
|
Note :
|
|
|
|
***************************************************************************/
|
|
BOOL GetAllDLNames(HANDLE pFile, ULONG nDLs, LPMH_STUFF pHeadersDL)
|
|
{
|
|
|
|
ULONG i = 0;
|
|
|
|
for(i=0;i<nDLs;i++)
|
|
{
|
|
ULONG ulDLDispNameOffset=0;
|
|
ULONG ulDLDispNameSize=0;
|
|
ULONG ulDLCommentOffSet = 0;
|
|
ULONG ulDLCommentSize = 0;
|
|
|
|
DWORD dwRead = 0;
|
|
LPTSTR szComment = 0;
|
|
LPTSTR szSubject = NULL;
|
|
|
|
ULONG ulDLOffset = pHeadersDL[i].ulOffSet;
|
|
|
|
//get the diplay name of the DL.
|
|
if(FALSE==GetOffSet(pFile, ulDLOffset+6,&ulDLDispNameOffset))
|
|
return FALSE;
|
|
|
|
if(FALSE==GetOffSet(pFile,ulDLOffset+10,&ulDLDispNameSize))
|
|
return FALSE;
|
|
|
|
if(ulDLDispNameSize)
|
|
{
|
|
if((szSubject= LocalAlloc(LMEM_ZEROINIT, ulDLDispNameSize))==NULL)
|
|
return FALSE;
|
|
|
|
SetFilePointer(pFile, ulDLDispNameOffset, NULL, FILE_BEGIN);
|
|
|
|
ReadFile(pFile, (LPVOID) szSubject, ulDLDispNameSize, &dwRead, NULL);
|
|
|
|
szSubject[ulDLDispNameSize-1] = '\0';
|
|
|
|
pHeadersDL[i].bp.lpName = szSubject;
|
|
}
|
|
|
|
// Get the Comment for the DL
|
|
if(FALSE==GetOffSet(pFile,ulDLOffset+44,&ulDLCommentOffSet))
|
|
return FALSE;
|
|
if(FALSE==GetOffSet(pFile,ulDLOffset+48,&ulDLCommentSize))
|
|
return FALSE;
|
|
|
|
if(ulDLCommentSize)
|
|
{
|
|
if((szComment= LocalAlloc(LMEM_ZEROINIT, ulDLCommentSize))==NULL)
|
|
return FALSE;
|
|
|
|
SetFilePointer(pFile, ulDLCommentOffSet, NULL, FILE_BEGIN);
|
|
|
|
ReadFile(pFile, (LPVOID) szComment, ulDLCommentSize, &dwRead, NULL);
|
|
|
|
szComment[ulDLCommentSize-1] = '\0';
|
|
|
|
pHeadersDL[i].bp.lpComment = szComment;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
GetDLEntryNumbers - reads the DL member numbers (ids) from the binary tree
|
|
in the NAB file
|
|
|
|
/***************************************************************************/
|
|
BOOL GetDLEntryNumbers(HANDLE pFile, int nLayer, ULONG POffset,ULONG* ulNumOfEntries,ULONG *pEntryNumbers,BOOL bflag)
|
|
{
|
|
static ULONG ulCount =0; //keeps trecat of the number of element
|
|
ULONG nLoops =0;
|
|
ULONG ulNewOffset =0;
|
|
ULONG ulElement = 0;
|
|
|
|
if(bflag==1)
|
|
ulCount =0;
|
|
|
|
if(POffset==0)
|
|
nLoops=32;
|
|
else
|
|
{
|
|
GetOffSet(pFile,POffset+4,&nLoops);
|
|
nLoops &= 0x0000FFFF;
|
|
}
|
|
|
|
|
|
for(ulElement = 0; ulElement < nLoops; ulElement++)
|
|
{
|
|
if(nLayer > 0)
|
|
{
|
|
ulNewOffset=0;
|
|
if(POffset!=0)
|
|
GetOffSet(pFile, POffset+8+(ulElement*4), &ulNewOffset);
|
|
|
|
//call this function recursively
|
|
GetDLEntryNumbers(pFile,nLayer-1, ulNewOffset,ulNumOfEntries,pEntryNumbers,0);
|
|
}
|
|
else
|
|
{
|
|
//fill the array here (offset)
|
|
pEntryNumbers[ulCount]=0;
|
|
|
|
if(POffset!=0)
|
|
GetOffSet(pFile, POffset+8+(ulElement*4),&(pEntryNumbers[ulCount]));
|
|
|
|
ulCount++; //increment the count
|
|
if(ulCount>(*ulNumOfEntries))
|
|
{
|
|
*ulNumOfEntries=ulCount;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FunctionName: GetDLEntries
|
|
|
|
Purpose : Gets the entries of a DL.
|
|
|
|
Note :
|
|
|
|
***************************************************************************/
|
|
BOOL GetDLEntries(HANDLE pFile,
|
|
LPMH_STUFF pHeadAdd, ULONG ulAddCount,
|
|
LPMH_STUFF pHeadDL, ULONG ulDLCount,
|
|
ULONG ulDLOffset, ULONG nIndex,
|
|
ULONG * lpulDLNum, LPMP_BASIC * lppmp)
|
|
{
|
|
ULONG ulDLEntHeaderOffSet=0;//offset of the header of DL entries(Header which has the entry numbers
|
|
ULONG ulDLEntriesCount=0;
|
|
|
|
ULONG ulDLEntryOffSet=0; //offset of the Dl entry
|
|
ULONG ulDLEntryNumber=0; //Number of DL entry
|
|
ULONG ulDLEntryNameOffSet=0;
|
|
ULONG ulDLEntryNameSize=0;
|
|
|
|
ULONG * lpulDLEntryNumbers = NULL;
|
|
int nLevelCount=0;
|
|
int utemp=32;
|
|
|
|
DWORD dwRead = 0;
|
|
ULONG i, j;
|
|
|
|
LPMP_BASIC lpmp = NULL;
|
|
|
|
if(FALSE==GetOffSet(pFile,ulDLOffset+24,&ulDLEntriesCount))
|
|
return FALSE;
|
|
|
|
if(!ulDLEntriesCount) // no members
|
|
return TRUE;
|
|
|
|
*lpulDLNum = ulDLEntriesCount;
|
|
|
|
//alocate the array of string pointers which hold the names of the DL entries.
|
|
lpmp = LocalAlloc(LMEM_ZEROINIT, sizeof(MP_BASIC) * ulDLEntriesCount);
|
|
|
|
//get the entries here
|
|
//first get the offset of the header which has the DL entry numbers.
|
|
|
|
if(FALSE==GetOffSet(pFile,ulDLOffset+28,&ulDLEntHeaderOffSet))
|
|
return FALSE;
|
|
|
|
lpulDLEntryNumbers = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG) * ulDLEntriesCount);
|
|
if(!lpulDLEntryNumbers)
|
|
return FALSE;
|
|
|
|
nLevelCount=0;
|
|
utemp=32;
|
|
|
|
while(utemp <(int) ulDLEntriesCount)
|
|
{
|
|
utemp *= 32;
|
|
nLevelCount++;
|
|
}
|
|
|
|
if(!(GetDLEntryNumbers(pFile, nLevelCount, ulDLEntHeaderOffSet, &ulDLEntriesCount, lpulDLEntryNumbers, 1)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for(i=0;i<ulDLEntriesCount;i++)
|
|
{
|
|
ULONG j=0;
|
|
LPTSTR lp = NULL;
|
|
LPTSTR lpE = NULL;
|
|
|
|
ulDLEntryOffSet=0;
|
|
lpmp[i].lpName=NULL;
|
|
lpmp[i].lpEmail=NULL;
|
|
lpmp[i].lpComment=NULL;
|
|
|
|
//get the entry number ulDLentryNumber
|
|
ulDLEntryNumber = lpulDLEntryNumbers[i];
|
|
|
|
//search out address array to get the display name....
|
|
for(j=0;j<ulAddCount;j++)
|
|
{
|
|
if(pHeadAdd[j].ulNum == ulDLEntryNumber)
|
|
{
|
|
lpmp[i].lpName = pHeadAdd[j].bp.lpName;
|
|
lpmp[i].lpEmail = pHeadAdd[j].bp.lpEmail;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//search the DL array now...
|
|
if(!lpmp[i].lpName)
|
|
{
|
|
ULONG k;
|
|
for(k=0;k<ulDLCount;k++)
|
|
{
|
|
if(pHeadDL[k].ulNum == ulDLEntryNumber)
|
|
{
|
|
lpmp[i].lpName = pHeadDL[k].bp.lpName;
|
|
lpmp[i].lpEmail = NULL; // DLs dont have emails
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*lppmp = lpmp;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
*
|
|
*
|
|
*
|
|
*****************************************************************/
|
|
HRESULT MessengerImport( HWND hWnd,
|
|
LPADRBOOK lpAdrBook,
|
|
LPWABOBJECT lpWABObject,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions)
|
|
{
|
|
HRESULT hResult = hrSuccess;
|
|
TCHAR szFileName[MAX_PATH + 1];
|
|
register ULONG i;
|
|
ULONG ulObjType, j;
|
|
ULONG index;
|
|
ULONG ulLastChosenProp = 0;
|
|
ULONG ulcFields = 0;
|
|
ULONG cAttributes = 0;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
WAB_PROGRESS Progress;
|
|
LPABCONT lpContainer = NULL;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
LPMESS_RECORD lpMESSRecord = NULL;
|
|
LPSPropValue lpspv = NULL;
|
|
ULONG cProps;
|
|
BOOL fSkipSetProps;
|
|
LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
|
|
BOOL fDoDistLists = FALSE;
|
|
|
|
ULONG nEntries = 0;
|
|
ULONG nDLs = 0;
|
|
ULONG nContactOffset = 0;
|
|
ULONG nDLOffset = 0;
|
|
|
|
int utemp=32;
|
|
LPMH_STUFF pHeadersAdd = NULL;
|
|
LPMH_STUFF pHeadersDL = NULL;
|
|
|
|
int nLevelCountAdd=0;
|
|
|
|
SetGlobalBufferFunctions(lpWABObject);
|
|
|
|
*szFileName = '\0';
|
|
|
|
hResult = GetNABPath(szFileName, sizeof(szFileName));
|
|
|
|
if( hResult != S_OK || !lstrlen(szFileName) ||
|
|
GetFileAttributes(szFileName) == 0xFFFFFFFF)
|
|
{
|
|
// The file was not correctly detected
|
|
// Prompt to find it manually ...
|
|
StrCpyN(szFileName, LoadStringToGlobalBuffer(IDS_STRING_SELECTPATH), ARRAYSIZE(szFileName));
|
|
if (IDNO == MessageBox( hWnd,
|
|
szFileName, //temporarily overloaded
|
|
LoadStringToGlobalBuffer(IDS_MESSAGE),
|
|
MB_YESNO))
|
|
{
|
|
return(ResultFromScode(MAPI_E_USER_CANCEL));
|
|
}
|
|
else
|
|
{
|
|
*szFileName = '\0';
|
|
// Get MESS file name
|
|
OpenFileDialog(hWnd,
|
|
szFileName,
|
|
szMESSFilter,
|
|
IDS_MESS_FILE_SPEC,
|
|
szAllFilter,
|
|
IDS_ALL_FILE_SPEC,
|
|
NULL,
|
|
0,
|
|
szMESSExt,
|
|
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
|
|
hInst,
|
|
0, //idsTitle
|
|
0); // idsSaveButton
|
|
if(!lstrlen(szFileName))
|
|
return(ResultFromScode(E_FAIL));
|
|
}
|
|
}
|
|
|
|
|
|
// Open the file
|
|
if ((hFile = CreateFile(szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD err = GetLastError();
|
|
DebugTrace("Couldn't open file %s -> %u\n", szFileName, err);
|
|
// BEGIN DELTA for BUG 1804
|
|
// if the file is locked (e.g. netscape AB in use)
|
|
if( err == ERROR_SHARING_VIOLATION )
|
|
return(ResultFromScode(MAPI_E_BUSY));
|
|
// else return a generic error for generic msg
|
|
return(ResultFromScode(MAPI_E_NOT_FOUND));
|
|
// END DELTA for BUG 1804
|
|
}
|
|
|
|
Assert(hFile != INVALID_HANDLE_VALUE);
|
|
|
|
//
|
|
// Open the WAB's PAB container: fills global lpCreateEIDsWAB
|
|
//
|
|
if (hResult = LoadWABEIDs(lpAdrBook, &lpContainer)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// All set... now loop through the records, adding each to the WAB
|
|
//
|
|
|
|
GetOffSet(hFile,0x185,&nEntries);
|
|
GetOffSet(hFile,0x1d8,&nDLs);
|
|
GetOffSet(hFile,0x195,&nContactOffset);
|
|
GetOffSet(hFile,0x1e8,&nDLOffset);
|
|
|
|
ulcEntries = nEntries + nDLs;
|
|
|
|
if(!ulcEntries)
|
|
{
|
|
hResult = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the Progress Bar
|
|
Progress.denominator = max(ulcEntries, 1);
|
|
Progress.numerator = 0;
|
|
|
|
if (LoadString(hInst, IDS_STATE_IMPORT_MU, szBuffer, sizeof(szBuffer))) {
|
|
DebugTrace("Status Message: %s\n", szBuffer);
|
|
Progress.lpText = szBuffer;
|
|
} else {
|
|
DebugTrace("Cannot load resource string %u\n", IDS_STATE_IMPORT_MU);
|
|
Progress.lpText = NULL;
|
|
}
|
|
lpProgressCB(hWnd, &Progress);
|
|
|
|
|
|
// We will make 2 passes over the file - in the first pass we will import all the
|
|
// contacts. In the second pass we will import all the distribution lists .. the
|
|
// advantage of doing 2 passes is that when importing contacts, we will prompt on
|
|
// conflict and then when importing distlists, we will assume all contacts in the
|
|
// WAB are correct and just point to the relevant ones
|
|
|
|
|
|
if(nEntries)
|
|
{
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
pHeadersAdd = LocalAlloc(LMEM_ZEROINIT, nEntries * sizeof(MH_STUFF));
|
|
if(!pHeadersAdd)
|
|
{
|
|
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
utemp = 32;
|
|
nLevelCountAdd = 0;
|
|
while(utemp <(int) nEntries)
|
|
{
|
|
utemp *= 32;
|
|
nLevelCountAdd++;
|
|
}
|
|
|
|
if(!GetHeaders(hFile ,nLevelCountAdd, nContactOffset, pHeadersAdd, 1))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
for(i=0;i<nEntries;i++)
|
|
{
|
|
if (hResult = ReadMESSRecord(hFile, &lpMESSRecord, pHeadersAdd[i].ulOffSet))
|
|
{
|
|
DebugTrace("ReadMESSRecord -> %x\n", GetScode(hResult));
|
|
continue;
|
|
}
|
|
|
|
if (hResult = MapMESSRecordtoProps( lpMESSRecord,
|
|
&lpspv, &cProps,
|
|
&lpDisplayName, &lpEmailAddress))
|
|
{
|
|
DebugTrace("MapMESSRecordtoProps -> %x\n", GetScode(hResult));
|
|
continue;
|
|
}
|
|
|
|
hResult = HrAddMESSMailUser(hWnd,
|
|
lpContainer,
|
|
lpDisplayName,
|
|
lpEmailAddress,
|
|
cProps, lpspv,
|
|
lpProgressCB, lpOptions);
|
|
//if(HR_FAILED(hResult))
|
|
if(hResult == MAPI_E_USER_CANCEL)
|
|
goto exit;
|
|
|
|
// Update progress bar
|
|
Progress.numerator++;
|
|
|
|
Assert(Progress.numerator <= Progress.denominator);
|
|
|
|
if(lpDisplayName && lstrlen(lpDisplayName))
|
|
{
|
|
pHeadersAdd[i].bp.lpName = LocalAlloc(LMEM_ZEROINIT, lstrlen(lpDisplayName)+1);
|
|
if(pHeadersAdd[i].bp.lpName)
|
|
StrCpyN(pHeadersAdd[i].bp.lpName, lpDisplayName, lstrlen(lpDisplayName)+1);
|
|
}
|
|
|
|
if(lpEmailAddress && lstrlen(lpEmailAddress))
|
|
{
|
|
pHeadersAdd[i].bp.lpEmail = LocalAlloc(LMEM_ZEROINIT, lstrlen(lpEmailAddress)+1);
|
|
if(pHeadersAdd[i].bp.lpEmail)
|
|
StrCpyN(pHeadersAdd[i].bp.lpEmail, lpEmailAddress, lstrlen(lpEmailAddress)+1);
|
|
}
|
|
|
|
if (lpMESSRecord)
|
|
{
|
|
FreeMESSRecord(lpMESSRecord);
|
|
lpMESSRecord = NULL;
|
|
}
|
|
|
|
if (lpspv)
|
|
{
|
|
int j;
|
|
for(j=0;j<m_Max;j++)
|
|
{
|
|
lpspv[j].ulPropTag = PR_NULL;
|
|
lpspv[j].Value.LPSZ = NULL;
|
|
}
|
|
WABFreeBuffer(lpspv);
|
|
lpspv = NULL;
|
|
}
|
|
|
|
lpProgressCB(hWnd, &Progress);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// NOW do the DISTLISTS
|
|
|
|
if(nDLs)
|
|
{
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
pHeadersDL = LocalAlloc(LMEM_ZEROINIT, nDLs * sizeof(MH_STUFF));
|
|
if(!pHeadersDL)
|
|
{
|
|
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
utemp = 32;
|
|
nLevelCountAdd = 0;
|
|
while(utemp <(int) nDLs)
|
|
{
|
|
utemp *= 32;
|
|
nLevelCountAdd++;
|
|
}
|
|
|
|
if(!GetHeaders(hFile ,nLevelCountAdd, nDLOffset, pHeadersDL, 1))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// read all the names of the DLs upfront ... this makes it easier to
|
|
// associate member DLs with the DL
|
|
if(!GetAllDLNames(hFile, nDLs, pHeadersDL))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// 54263: Theres some kind of bug in the NAB file where we get nDLs == 1 even when there are no DLs
|
|
// Need to skip over that case
|
|
if(nDLs == 1 && !pHeadersDL[0].bp.lpName)
|
|
{
|
|
hResult = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
for(i=0;i<nDLs;i++)
|
|
{
|
|
ULONG ulcNumDLEntries = 0;
|
|
LPMP_BASIC lpmp = NULL;
|
|
|
|
GetDLEntries(hFile,
|
|
pHeadersAdd, nEntries,
|
|
pHeadersDL, nDLs,
|
|
pHeadersDL[i].ulOffSet, i,
|
|
&ulcNumDLEntries, &lpmp);
|
|
|
|
hResult = HrAddMESSDistList(hWnd, lpContainer,
|
|
pHeadersDL[i],
|
|
ulcNumDLEntries, lpmp,
|
|
lpProgressCB, lpOptions);
|
|
|
|
//if(HR_FAILED(hResult))
|
|
// goto exit;
|
|
|
|
// Update progress bar
|
|
Progress.numerator++;
|
|
|
|
Assert(Progress.numerator <= Progress.denominator);
|
|
|
|
lpProgressCB(hWnd, &Progress);
|
|
|
|
// Dont need to free lpmp since it only contains pointers and not allocated memory
|
|
if(lpmp)
|
|
LocalFree(lpmp);
|
|
}
|
|
}
|
|
|
|
|
|
if (! HR_FAILED(hResult))
|
|
hResult = hrSuccess;
|
|
|
|
exit:
|
|
|
|
if(pHeadersAdd)
|
|
{
|
|
for(i=0;i<nEntries;i++)
|
|
{
|
|
if(pHeadersAdd[i].bp.lpName)
|
|
LocalFree(pHeadersAdd[i].bp.lpName);
|
|
if(pHeadersAdd[i].bp.lpEmail)
|
|
LocalFree(pHeadersAdd[i].bp.lpEmail);
|
|
}
|
|
LocalFree(pHeadersAdd);
|
|
}
|
|
|
|
|
|
if(pHeadersDL)
|
|
{
|
|
for(i=0;i<nDLs;i++)
|
|
{
|
|
if(pHeadersDL[i].bp.lpName)
|
|
LocalFree(pHeadersDL[i].bp.lpName);
|
|
if(pHeadersDL[i].bp.lpComment)
|
|
LocalFree(pHeadersDL[i].bp.lpComment);
|
|
}
|
|
LocalFree(pHeadersDL);
|
|
}
|
|
|
|
if (hFile) {
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (lpspv) {
|
|
WABFreeBuffer(lpspv);
|
|
lpspv = NULL;
|
|
}
|
|
|
|
if (lpMESSRecord) {
|
|
FreeMESSRecord(lpMESSRecord);
|
|
lpMESSRecord = NULL;
|
|
}
|
|
|
|
if (lpContainer) {
|
|
lpContainer->lpVtbl->Release(lpContainer);
|
|
lpContainer = NULL;
|
|
}
|
|
|
|
if (lpCreateEIDsWAB) {
|
|
WABFreeBuffer(lpCreateEIDsWAB);
|
|
lpCreateEIDsWAB = NULL;
|
|
}
|
|
|
|
|
|
return(hResult);
|
|
}
|
|
|