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.
4439 lines
152 KiB
4439 lines
152 KiB
/*
|
|
* PAB.C
|
|
*
|
|
* Migrate PAB <-> WAB
|
|
*
|
|
* Copyright 1996-1997 Microsoft Corporation. All Rights Reserved.
|
|
*/
|
|
|
|
#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 "..\..\wab32res\resrc2.h"
|
|
#include "dbgutil.h"
|
|
#include "wabimp.h"
|
|
#include <shlwapi.h>
|
|
|
|
|
|
void StateImportNextMU(HWND hwnd);
|
|
void StateImportDL(HWND hwnd);
|
|
void StateImportNextDL(HWND hwnd);
|
|
void StateImportFinish(HWND hwnd);
|
|
//void StateImportMU(HWND hwnd);
|
|
void StateImportMU(HWND hwnd);
|
|
void StateImportError(HWND hwnd);
|
|
void StateImportCancel(HWND hwnd);
|
|
BOOL HandleImportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress, LPWAB_IMPORT_OPTIONS lpImportOptions);
|
|
|
|
HRESULT ImportEntry(HWND hwnd,
|
|
LPADRBOOK lpAdrBookMAPI,
|
|
LPABCONT lpContainerWAB,
|
|
LPSPropValue lpCreateEIDsWAB,
|
|
ULONG ulObjectType,
|
|
LPENTRYID lpEID,
|
|
ULONG cbEID,
|
|
LPENTRYID * lppEIDWAB,
|
|
LPULONG lpcbEIDWAB,
|
|
BOOL fInDL,
|
|
BOOL fForceReplace);
|
|
|
|
const UCHAR szQuote[] = "\"";
|
|
LPPROP_NAME lpImportMapping = NULL;
|
|
|
|
BOOL fError = FALSE;
|
|
LPWABOBJECT lpWABObject = NULL;
|
|
LPMAPISESSION lpMAPISession = NULL;
|
|
LPADRBOOK lpAdrBookWAB = NULL, lpAdrBookMAPI = NULL;
|
|
LPSPropValue lpCreateEIDsWAB = NULL, lpCreateEIDsMAPI = NULL;
|
|
LPABCONT lpContainerWAB = NULL, lpContainerMAPI = NULL;
|
|
LPMAPITABLE lpContentsTableWAB = NULL, lpContentsTableMAPI = NULL;
|
|
ULONG ulcEntries = 0, ulcDone = 0;
|
|
|
|
|
|
PAB_STATE State = STATE_IMPORT_FINISH;
|
|
LPTSTR lpszWABFileName = NULL;
|
|
LPWAB_PROGRESS_CALLBACK lpfnProgressCB = NULL;
|
|
LPWAB_IMPORT_OPTIONS lpImportOptions = NULL;
|
|
LPWAB_EXPORT_OPTIONS lpExportOptions = NULL;
|
|
|
|
|
|
|
|
/*
|
|
- The following IDs and tags are for the conferencing named properties
|
|
-
|
|
- The GUID for these props is PS_Conferencing
|
|
*/
|
|
|
|
DEFINE_OLEGUID(PS_Conferencing, 0x00062004, 0, 0);
|
|
|
|
#define CONF_SERVERS 0x8056
|
|
|
|
#define OLK_NAMEDPROPS_START CONF_SERVERS
|
|
|
|
ULONG PR_SERVERS;
|
|
|
|
enum _ConferencingTags
|
|
{
|
|
prWABConfServers = 0,
|
|
prWABConfMax
|
|
};
|
|
SizedSPropTagArray(prWABConfMax, ptaUIDetlsPropsConferencing);
|
|
|
|
HRESULT HrLoadPrivateWABPropsForCSV(LPADRBOOK );
|
|
// end conferencing duplication
|
|
|
|
/***************************************************************************
|
|
|
|
Name : NewState
|
|
|
|
Purpose :
|
|
|
|
Parameters: hwnd = window handle of Dialog (currently unused)
|
|
NewState = new state to set
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
__inline void NewState(HWND hwnd, PAB_STATE NewState) {
|
|
// Old version
|
|
// PostMessage(hwnd, WM_COMMAND, NewState, 0);
|
|
State = NewState;
|
|
UNREFERENCED_PARAMETER(hwnd);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : SetDialogMessage
|
|
|
|
Purpose : Sets the message text for the dialog box item IDC_Message
|
|
|
|
Parameters: hwnd = window handle of dialog
|
|
ids = stringid of message resource
|
|
|
|
Returns : none
|
|
|
|
***************************************************************************/
|
|
void SetDialogMessage(HWND hwnd, int ids) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
WAB_PROGRESS Progress = {0};
|
|
|
|
Assert(lpfnProgressCB);
|
|
|
|
if (lpfnProgressCB && LoadString(hInst, ids, szBuffer, ARRAYSIZE(szBuffer))) {
|
|
DebugTrace("Status Message: %s\n", szBuffer);
|
|
|
|
Progress.lpText = szBuffer;
|
|
lpfnProgressCB(hwnd, &Progress);
|
|
} else {
|
|
DebugTrace("Cannot load resource string %u\n", ids);
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : SetDialogProgress
|
|
|
|
Purpose : Sets progress bar
|
|
|
|
Parameters: hwnd = window handle of dialog
|
|
ulTotal = total entries
|
|
ulDone = finished entries
|
|
|
|
Returns : none
|
|
|
|
***************************************************************************/
|
|
void SetDialogProgress(HWND hwnd, ULONG ulTotal, ULONG ulDone) {
|
|
WAB_PROGRESS Progress = {0};
|
|
|
|
Assert(lpfnProgressCB);
|
|
|
|
if (lpfnProgressCB) {
|
|
Progress.denominator = ulTotal;
|
|
Progress.numerator = ulDone;
|
|
lpfnProgressCB(hwnd, &Progress);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : AddEntryToImportList
|
|
|
|
Purpose : Checks this entry against our "seen" list and adds it.
|
|
|
|
Parameters: cbEID = size of lpEID
|
|
lpEID -> EntryID of entry
|
|
lplIndex -> returned list index (or -1 on error)
|
|
|
|
Returns : TRUE if entry already exists
|
|
|
|
Comment : Caller must mark the WAB entry!
|
|
|
|
***************************************************************************/
|
|
#define GROW_SIZE 10
|
|
BOOL AddEntryToImportList(ULONG cbEID, LPENTRYID lpEID, LPLONG lplIndex) {
|
|
ULONG i;
|
|
LPENTRY_SEEN lpEntrySeen;
|
|
|
|
if (cbEID && lpEID) {
|
|
for (i = 0; i < ulEntriesSeen; i++) {
|
|
if (cbEID == lpEntriesSeen[i].sbinPAB.cb && (! memcmp(lpEID, lpEntriesSeen[i].sbinPAB.lpb, cbEID))) {
|
|
// This one's in the list
|
|
*lplIndex = i;
|
|
// If cb 0, we must have recursed and are replacing, so this one is not a dup.
|
|
return(lpEntriesSeen[i].sbinWAB.cb != 0);
|
|
}
|
|
}
|
|
|
|
// Add to the end of the list
|
|
if (++ulEntriesSeen > ulMaxEntries) {
|
|
// Grow the array.
|
|
|
|
ulMaxEntries += GROW_SIZE;
|
|
|
|
if (lpEntriesSeen) {
|
|
if (! (lpEntrySeen = LocalReAlloc(lpEntriesSeen, ulMaxEntries * sizeof(ENTRY_SEEN), LMEM_MOVEABLE | LMEM_ZEROINIT))) {
|
|
DebugTrace("LocalReAlloc(%u) -> %u\n", ulMaxEntries * sizeof(ENTRY_SEEN), GetLastError());
|
|
goto error;
|
|
}
|
|
lpEntriesSeen = lpEntrySeen;
|
|
} else {
|
|
if (! (lpEntriesSeen = LocalAlloc(LPTR, ulMaxEntries * sizeof(ENTRY_SEEN)))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", ulMaxEntries * sizeof(ENTRY_SEEN), GetLastError());
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
lpEntrySeen = &lpEntriesSeen[ulEntriesSeen - 1];
|
|
|
|
// Allocate space for data
|
|
lpEntrySeen->sbinPAB.cb = cbEID;
|
|
if (! (lpEntrySeen->sbinPAB.lpb = LocalAlloc(LPTR, cbEID))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cbEID, GetLastError());
|
|
goto error;
|
|
}
|
|
|
|
// Mark as unknown WAB entry
|
|
lpEntrySeen->sbinWAB.cb = 0;
|
|
lpEntrySeen->sbinWAB.lpb = 0;
|
|
|
|
// Copy in the data
|
|
CopyMemory(lpEntrySeen->sbinPAB.lpb, lpEID, cbEID);
|
|
*lplIndex = i;
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
error:
|
|
// undo the damage...
|
|
--ulEntriesSeen;
|
|
ulMaxEntries -= GROW_SIZE;
|
|
*lplIndex = -1; // error
|
|
if (! lpEntriesSeen) {
|
|
ulEntriesSeen = 0; // pointer is null now, back to square one.
|
|
ulMaxEntries = 0;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : MarkWABEntryInList
|
|
|
|
Purpose : Marks the WAB entry fields in the list node
|
|
|
|
Parameters: cbEID = size of lpEID
|
|
lpEID -> EntryID of entry
|
|
lIndex = list index (or -1 on error)
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
void MarkWABEntryInList(ULONG cbEID, LPENTRYID lpEID, LONG lIndex) {
|
|
if (lIndex != -1 && cbEID) {
|
|
if (! (lpEntriesSeen[lIndex].sbinWAB.lpb = LocalAlloc(LPTR, cbEID))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cbEID, GetLastError());
|
|
// leave it null
|
|
} else {
|
|
lpEntriesSeen[lIndex].sbinWAB.cb = cbEID;
|
|
|
|
// Copy in the data
|
|
CopyMemory(lpEntriesSeen[lIndex].sbinWAB.lpb, lpEID, cbEID);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportMU
|
|
|
|
Purpose : Start the migration of MailUsers
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
lpszFileName - FileName of WAB File to open
|
|
|
|
Returns : none
|
|
|
|
Comment : Login to MAPI
|
|
Open the WAB
|
|
Open the MAPI AB
|
|
Open the WAB container
|
|
Get the MAPI PAB contents table
|
|
Restrict it to PR_OBJECTTYPE == MAPI_MAILUSER
|
|
Post new state(STATE_NEXT_MU)
|
|
|
|
***************************************************************************/
|
|
void StateImportMU(HWND hwnd) {
|
|
HRESULT hResult;
|
|
ULONG ulFlags;
|
|
ULONG cbPABEID, cbWABEID;
|
|
LPENTRYID lpPABEID = NULL;
|
|
ULONG ulObjType;
|
|
ULONG_PTR ulUIParam = (ULONG_PTR)(void *)hwnd;
|
|
SRestriction restrictObjectType;
|
|
SPropValue spvObjectType;
|
|
ULONG cProps;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
|
|
WAB_PARAM wp = {0};
|
|
LPWAB_PARAM lpwp = NULL;
|
|
|
|
|
|
//
|
|
// Logon to MAPI and open the MAPI Address book, if one exists
|
|
//
|
|
DebugTrace(">>> STATE_IMPORT_MU\n");
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_LOGGING_IN);
|
|
|
|
if (FAILED(hResult = MAPIInitialize(NULL))) {
|
|
DebugTrace("MAPIInitialize -> %x\n", GetScode(hResult));
|
|
switch (GetScode(hResult)) {
|
|
case MAPI_E_NOT_ENOUGH_MEMORY:
|
|
SetDialogMessage(hwnd, IDS_ERROR_NOT_ENOUGH_MEMORY);
|
|
break;
|
|
case MAPI_E_NOT_ENOUGH_DISK:
|
|
SetDialogMessage(hwnd, IDS_ERROR_NOT_ENOUGH_DISK);
|
|
break;
|
|
|
|
default:
|
|
case MAPI_E_NOT_FOUND:
|
|
case MAPI_E_NOT_INITIALIZED:
|
|
SetDialogMessage(hwnd, IDS_ERROR_MAPI_DLL_NOT_FOUND);
|
|
break;
|
|
}
|
|
#ifdef OLD_STUFF
|
|
ShowWindow(GetDlgItem(hwnd, IDC_Progress), SW_HIDE); // hide progress bar
|
|
#endif // OLD_STUFF
|
|
fError = TRUE;
|
|
hResult = hrSuccess;
|
|
goto exit;
|
|
}
|
|
|
|
ulFlags = MAPI_LOGON_UI | MAPI_NO_MAIL | MAPI_EXTENDED;
|
|
|
|
if (FAILED(hResult = MAPILogonEx(ulUIParam,
|
|
NULL,
|
|
NULL,
|
|
ulFlags,
|
|
(LPMAPISESSION FAR *)&lpMAPISession))) {
|
|
DebugTrace("MAPILogonEx -> %x\n", GetScode(hResult));
|
|
switch (GetScode(hResult)) {
|
|
case MAPI_E_USER_CANCEL:
|
|
SetDialogMessage(hwnd, IDS_STATE_IMPORT_IDLE);
|
|
break;
|
|
case MAPI_E_NOT_INITIALIZED:
|
|
SetDialogMessage(hwnd, IDS_ERROR_MAPI_DLL_NOT_FOUND);
|
|
break;
|
|
default:
|
|
SetDialogMessage(hwnd, IDS_ERROR_MAPI_LOGON);
|
|
break;
|
|
}
|
|
#ifdef OLD_STUFF
|
|
ShowWindow(GetDlgItem(hwnd, IDC_Progress), SW_HIDE); // hide progress bar
|
|
#endif // OLD_STUFF
|
|
fError = TRUE;
|
|
hResult = hrSuccess;
|
|
goto exit;
|
|
}
|
|
|
|
if (hResult = lpMAPISession->lpVtbl->OpenAddressBook(lpMAPISession, (ULONG_PTR)(void *)hwnd,
|
|
NULL,
|
|
0,
|
|
&lpAdrBookMAPI)) {
|
|
DebugTrace("OpenAddressBook(MAPI) -> %x", GetScode(hResult));
|
|
if(FAILED(hResult)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (! lpAdrBookMAPI) {
|
|
DebugTrace("MAPILogonEx didn't return a valid AdrBook object\n");
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open the MAPI PAB container
|
|
//
|
|
// [PaulHi] Raid #63578 1/7/98
|
|
// Correctly check return code and provide user error message if
|
|
// Exchange PAB cannot be opened.
|
|
//
|
|
hResult = lpAdrBookMAPI->lpVtbl->GetPAB(lpAdrBookMAPI,
|
|
&cbPABEID,
|
|
&lpPABEID);
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
DebugTrace("MAPI GetPAB -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
hResult = lpAdrBookMAPI->lpVtbl->OpenEntry(lpAdrBookMAPI,
|
|
cbPABEID, // size of EntryID to open
|
|
lpPABEID, // EntryID to open
|
|
NULL, // interface
|
|
0, // flags
|
|
&ulObjType,
|
|
(LPUNKNOWN *)&lpContainerMAPI);
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
DebugTrace("MAPI OpenEntry(PAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
Assert(lpAdrBookWAB);
|
|
|
|
//
|
|
// Open the WAB's PAB container: fills global lpCreateEIDsWAB
|
|
//
|
|
if (hResult = LoadWABEIDs(lpAdrBookWAB, &lpContainerWAB)) {
|
|
goto exit;
|
|
}
|
|
HrLoadPrivateWABPropsForCSV(lpAdrBookWAB);
|
|
|
|
//
|
|
// All set... now loop through the PAB's entries, copying them to WAB
|
|
//
|
|
if (HR_FAILED(hResult = lpContainerMAPI->lpVtbl->GetContentsTable(lpContainerMAPI,
|
|
0, // ulFlags
|
|
&lpContentsTableMAPI))) {
|
|
DebugTrace("MAPI GetContentsTable(PAB Table) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the columns to those we're interested in
|
|
if (hResult = lpContentsTableMAPI->lpVtbl->SetColumns(lpContentsTableMAPI,
|
|
(LPSPropTagArray)&ptaColumns,
|
|
0)) {
|
|
DebugTrace("MAPI SetColumns(PAB Table) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Restrict the table to MAPI_MAILUSERs
|
|
// If the convenient depth flag was not specified we restrict on
|
|
// PR_DEPTH == 1.
|
|
spvObjectType.ulPropTag = PR_OBJECT_TYPE;
|
|
spvObjectType.Value.l = MAPI_MAILUSER;
|
|
|
|
restrictObjectType.rt = RES_PROPERTY;
|
|
restrictObjectType.res.resProperty.relop = RELOP_EQ;
|
|
restrictObjectType.res.resProperty.ulPropTag = PR_OBJECT_TYPE;
|
|
restrictObjectType.res.resProperty.lpProp = &spvObjectType;
|
|
|
|
if (HR_FAILED(hResult = lpContentsTableMAPI->lpVtbl->Restrict(lpContentsTableMAPI,
|
|
&restrictObjectType,
|
|
0))) {
|
|
DebugTrace("MAPI Restrict (MAPI_MAILUSER) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
SetDialogMessage(hwnd, IDS_STATE_IMPORT_MU);
|
|
|
|
|
|
// Initialize the Progress Bar
|
|
// How many MailUser entries are there?
|
|
ulcEntries = CountRows(lpContentsTableMAPI, TRUE);
|
|
ulcDone = 0;
|
|
|
|
DebugTrace("PAB contains %u MailUser entries\n", ulcEntries);
|
|
|
|
SetDialogProgress(hwnd, ulcEntries, 0);
|
|
|
|
exit:
|
|
if (lpPABEID) {
|
|
MAPIFreeBuffer(lpPABEID);
|
|
}
|
|
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL)
|
|
{
|
|
NewState(hwnd, STATE_IMPORT_CANCEL);
|
|
}
|
|
else
|
|
{
|
|
// [PaulHi] 1/7/98 Error reporting is hosed
|
|
// Display error message here to the user to ensure they
|
|
// get it.
|
|
{
|
|
TCHAR tszBuffer[MAX_RESOURCE_STRING];
|
|
TCHAR tszBufferTitle[MAX_RESOURCE_STRING];
|
|
|
|
if ( !LoadString(hInst, IDS_STATE_IMPORT_ERROR_NOPAB, tszBuffer, MAX_RESOURCE_STRING-1) )
|
|
{
|
|
Assert(0);
|
|
tszBuffer[0] = '\0';
|
|
}
|
|
|
|
if ( !LoadString(hInst, IDS_APP_TITLE, tszBufferTitle, MAX_RESOURCE_STRING-1) )
|
|
{
|
|
Assert(0);
|
|
tszBufferTitle[0] = '\0';
|
|
}
|
|
MessageBox(hwnd, tszBuffer, tszBufferTitle, MB_ICONEXCLAMATION | MB_OK);
|
|
}
|
|
|
|
NewState(hwnd, STATE_IMPORT_ERROR);
|
|
}
|
|
}
|
|
else if (fError)
|
|
{
|
|
NewState(hwnd, STATE_IMPORT_FINISH); // must be logon error
|
|
}
|
|
else
|
|
{
|
|
NewState(hwnd, STATE_IMPORT_NEXT_MU);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportNextMU
|
|
|
|
Purpose : Migrate the next MailUser object
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : QueryRows on the global MAPI contents table
|
|
if there was a row
|
|
Migrate the entry to the WAB
|
|
Re-post STATE_NEXT_MU
|
|
else
|
|
Post STATE_IMPORT_DL
|
|
|
|
***************************************************************************/
|
|
void StateImportNextMU(HWND hwnd) {
|
|
ULONG cRows = 0;
|
|
HRESULT hResult;
|
|
LPSRowSet lpRow = NULL;
|
|
|
|
|
|
DebugTrace(">>> STATE_NEXT_MU\n");
|
|
|
|
// Get the next PAB entry
|
|
if (hResult = lpContentsTableMAPI->lpVtbl->QueryRows(lpContentsTableMAPI,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow) {
|
|
if (cRows = lpRow->cRows) { // Yes, single '='
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
if (cRows = lpRow->cRows) { // yes, single '='
|
|
hResult = ImportEntry(hwnd,
|
|
lpAdrBookMAPI,
|
|
lpContainerWAB,
|
|
lpCreateEIDsWAB,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].Value.l,
|
|
(LPENTRYID)lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.lpb,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.cb,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
FALSE);
|
|
// Update Progress Bar
|
|
// ignore errors!
|
|
|
|
SetDialogProgress(hwnd, ulcEntries, ++ulcDone);
|
|
|
|
if (hResult) {
|
|
if (HandleImportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_DISPLAY_NAME].Value.LPSZ,
|
|
PropStringOrNULL(&lpRow->aRow[0].lpProps[iptaColumnsPR_EMAIL_ADDRESS]),
|
|
lpImportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
} // else, drop out of loop, we're done.
|
|
}
|
|
FreeProws(lpRow);
|
|
}
|
|
|
|
exit:
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult)) {
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL) {
|
|
NewState(hwnd, STATE_IMPORT_CANCEL);
|
|
} else {
|
|
NewState(hwnd, STATE_IMPORT_ERROR);
|
|
}
|
|
} else {
|
|
if (cRows) {
|
|
NewState(hwnd, STATE_IMPORT_NEXT_MU);
|
|
} else {
|
|
NewState(hwnd, STATE_IMPORT_DL);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportDL
|
|
|
|
Purpose : Start migration of DISTLIST objects
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Set a new restriction on the contents table, selecting
|
|
DISTLIST objects only.
|
|
Post STATE_NEXT_DL
|
|
|
|
***************************************************************************/
|
|
void StateImportDL(HWND hwnd) {
|
|
HRESULT hResult;
|
|
SRestriction restrictObjectType;
|
|
SPropValue spvObjectType;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
|
|
|
|
DebugTrace(">>> STATE_IMPORT_DL\n");
|
|
|
|
// Restrict the table to MAPI_MAILUSERs
|
|
// If the convenient depth flag was not specified we restrict on
|
|
// PR_DEPTH == 1.
|
|
spvObjectType.ulPropTag = PR_OBJECT_TYPE;
|
|
spvObjectType.Value.l = MAPI_DISTLIST;
|
|
|
|
restrictObjectType.rt = RES_PROPERTY;
|
|
restrictObjectType.res.resProperty.relop = RELOP_EQ;
|
|
restrictObjectType.res.resProperty.ulPropTag = PR_OBJECT_TYPE;
|
|
restrictObjectType.res.resProperty.lpProp = &spvObjectType;
|
|
|
|
if (HR_FAILED(hResult = lpContentsTableMAPI->lpVtbl->Restrict(lpContentsTableMAPI,
|
|
&restrictObjectType,
|
|
0))) {
|
|
DebugTrace("MAPI Restrict (MAPI_DISTLIST) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
// Restrict resets the current position to the beginning of the table, by definition.
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_IMPORT_DL);
|
|
|
|
// Initialize the Progress Bar
|
|
// How many entries are there?
|
|
|
|
ulcEntries = CountRows(lpContentsTableMAPI, TRUE);
|
|
ulcDone = 0;
|
|
|
|
DebugTrace("PAB contains %u Distribution List entries\n", ulcEntries);
|
|
if (ulcEntries) {
|
|
SetDialogProgress(hwnd, ulcEntries, 0);
|
|
}
|
|
exit:
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult)) {
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL) {
|
|
NewState(hwnd, STATE_IMPORT_CANCEL);
|
|
} else {
|
|
NewState(hwnd, STATE_IMPORT_ERROR);
|
|
}
|
|
} else {
|
|
NewState(hwnd, STATE_IMPORT_NEXT_DL);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportNextDL
|
|
|
|
Purpose : Migrate the next DISTLIST object
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : QueryRows on the global MAPI contents table
|
|
if there was a row
|
|
Migrate the DistList to the WAB
|
|
Re-post STATE_NEXT_DL
|
|
else
|
|
Post STATE_FINISH
|
|
|
|
***************************************************************************/
|
|
void StateImportNextDL(HWND hwnd) {
|
|
ULONG cRows = 0;
|
|
HRESULT hResult;
|
|
LPSRowSet lpRow = NULL;
|
|
|
|
|
|
DebugTrace(">>> STATE_NEXT_DL\n");
|
|
|
|
// Get the next PAB entry
|
|
if (hResult = lpContentsTableMAPI->lpVtbl->QueryRows(lpContentsTableMAPI,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow) {
|
|
if (cRows = lpRow->cRows) { // Yes, single '='
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
if (cRows = lpRow->cRows) { // yes, single '='
|
|
hResult = ImportEntry(hwnd,
|
|
lpAdrBookMAPI,
|
|
lpContainerWAB,
|
|
lpCreateEIDsWAB,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].Value.l,
|
|
(LPENTRYID)lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.lpb,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.cb,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
FALSE);
|
|
|
|
// Update Progress Bar
|
|
SetDialogProgress(hwnd, ulcEntries, ++ulcDone);
|
|
|
|
if (hResult) {
|
|
if (HandleImportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_DISPLAY_NAME].Value.LPSZ,
|
|
PropStringOrNULL(&lpRow->aRow[0].lpProps[iptaColumnsPR_EMAIL_ADDRESS]),
|
|
lpImportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
} // else, drop out of loop, we're done.
|
|
}
|
|
FreeProws(lpRow);
|
|
}
|
|
|
|
exit:
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult)) {
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL) {
|
|
NewState(hwnd, STATE_IMPORT_CANCEL);
|
|
} else {
|
|
NewState(hwnd, STATE_IMPORT_ERROR);
|
|
}
|
|
} else {
|
|
if (cRows) {
|
|
NewState(hwnd, STATE_IMPORT_NEXT_DL);
|
|
} else {
|
|
// Update Progress Bar to indicate completion
|
|
SetDialogProgress(hwnd, ulcEntries, ulcEntries);
|
|
NewState(hwnd, STATE_IMPORT_FINISH);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportFinish
|
|
|
|
Purpose : Clean up after the migration process
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Clean up the global MAPI objects and buffers
|
|
Clean up the global WAB objects and buffers.
|
|
Re-enable the Import button on the UI.
|
|
|
|
***************************************************************************/
|
|
void StateImportFinish(HWND hwnd) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
TCHAR szBufferTitle[MAX_RESOURCE_STRING + 1];
|
|
|
|
|
|
DebugTrace(">>> STATE_FINISH\n");
|
|
|
|
//
|
|
// Cleanup MAPI
|
|
//
|
|
if (lpContentsTableMAPI) {
|
|
lpContentsTableMAPI->lpVtbl->Release(lpContentsTableMAPI);
|
|
lpContentsTableMAPI = NULL;
|
|
}
|
|
|
|
if (lpContainerMAPI) {
|
|
lpContainerMAPI->lpVtbl->Release(lpContainerMAPI);
|
|
lpContainerMAPI = NULL;
|
|
}
|
|
|
|
if (lpAdrBookMAPI) {
|
|
lpAdrBookMAPI->lpVtbl->Release(lpAdrBookMAPI);
|
|
lpAdrBookMAPI = NULL;
|
|
}
|
|
|
|
if(lpMAPISession){
|
|
lpMAPISession->lpVtbl->Logoff(lpMAPISession, (ULONG_PTR)(void *)hwnd,
|
|
MAPI_LOGOFF_UI,
|
|
0);
|
|
|
|
lpMAPISession->lpVtbl->Release(lpMAPISession);
|
|
lpMAPISession = NULL;
|
|
}
|
|
|
|
//
|
|
// Cleanup the WAB
|
|
//
|
|
if (lpCreateEIDsWAB) {
|
|
WABFreeBuffer(lpCreateEIDsWAB);
|
|
lpCreateEIDsWAB = NULL;
|
|
}
|
|
|
|
if (lpContainerWAB) {
|
|
lpContainerWAB->lpVtbl->Release(lpContainerWAB);
|
|
lpContainerWAB = NULL;
|
|
}
|
|
|
|
#ifdef OLD_STUFF // Don't release the WABObject or AdrBook object. They
|
|
// were passed in.
|
|
if (lpAdrBookWAB) {
|
|
lpAdrBookWAB->lpVtbl->Release(lpAdrBookWAB);
|
|
lpAdrBookWAB = NULL;
|
|
}
|
|
|
|
if (lpWABObject) {
|
|
lpWABObject->lpVtbl->Release(lpWABObject);
|
|
lpWABObject = NULL;
|
|
}
|
|
#endif // OLD_STUFF
|
|
|
|
// Cleanup the cache
|
|
FreeSeenList();
|
|
|
|
if (! fError) { // Leave error state displayed
|
|
if (LoadString(hInst, IDS_STATE_IMPORT_COMPLETE, szBuffer, ARRAYSIZE(szBuffer))) {
|
|
DebugTrace("Status Message: %s\n", szBuffer);
|
|
SetDlgItemText(hwnd, IDC_Message, szBuffer);
|
|
|
|
if (! LoadString(hInst, IDS_APP_TITLE, szBufferTitle, ARRAYSIZE(szBufferTitle))) {
|
|
StrCpyN(szBufferTitle, "", ARRAYSIZE(szBufferTitle));
|
|
}
|
|
|
|
#ifdef OLD_STUFF
|
|
// Display a dialog telling user it's over
|
|
MessageBox(hwnd, szBuffer,
|
|
szBufferTitle, MB_ICONINFORMATION | MB_OK);
|
|
#endif // OLD_STUFF
|
|
}
|
|
#ifdef OLD_STUFF
|
|
ShowWindow(GetDlgItem(hwnd, IDC_Progress), SW_HIDE);
|
|
#endif // OLD_STUFF
|
|
}
|
|
fError = FALSE;
|
|
|
|
// Re-enable the Import button here.
|
|
EnableWindow(GetDlgItem(hwnd, IDC_Import), TRUE);
|
|
// Change the Cancel button to Close
|
|
if (LoadString(hInst, IDS_BUTTON_CLOSE, szBuffer, ARRAYSIZE(szBuffer))) {
|
|
SetDlgItemText(hwnd, IDCANCEL, szBuffer);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportError
|
|
|
|
Purpose : Report fatal error and cleanup.
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Report error and post STATE_FINISH.
|
|
|
|
***************************************************************************/
|
|
void StateImportError(HWND hwnd) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
// Set some global flag and set state to finish
|
|
|
|
DebugTrace(">>> STATE_ERROR\n");
|
|
fError = TRUE;
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_IMPORT_ERROR);
|
|
|
|
NewState(hwnd, STATE_IMPORT_FINISH);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateImportCancel
|
|
|
|
Purpose : Report cancel error and cleanup.
|
|
|
|
Parameters: hwnd = window handle of Import Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Report error and post STATE_FINISH.
|
|
|
|
***************************************************************************/
|
|
void StateImportCancel(HWND hwnd) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
// Set some global flag and set state to finish
|
|
|
|
DebugTrace(">>> STATE_CANCEL\n");
|
|
fError = TRUE;
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_IMPORT_CANCEL);
|
|
|
|
NewState(hwnd, STATE_IMPORT_FINISH);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : HrFilterImportMailUserProps
|
|
|
|
Purpose : Filters out undesirable properties from the property array.
|
|
Converts known email address types to SMTP.
|
|
Moves FAX address to PR_BUSINESS_FAX_NUMBER.
|
|
|
|
Parameters: lpcProps -> IN: Input number of properties
|
|
OUT: Output number of properties
|
|
lppProps -> IN: Input property array (MAPI allocation)
|
|
OUT: Output property array (WAB allocation)
|
|
lpObjectMAPI -> MAPI object (used to get extra props)
|
|
lpfDL -> flag to set FALSE if we change a DL to a MAILUSER
|
|
(ie, for an EXchange DL)
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : Setting the property tag in the array to PR_NULL effectively
|
|
nulls this property out. We can re-use these in the second
|
|
pass.
|
|
|
|
Caller should use WABFreeBuffer to free *lppProps.
|
|
This routine will free the input value of *lppProps.
|
|
|
|
***************************************************************************/
|
|
HRESULT HrFilterImportMailUserProps(LPULONG lpcProps, LPSPropValue * lppProps,
|
|
LPMAPIPROP lpObjectMAPI, LPBOOL lpfDL) {
|
|
HRESULT hResult = hrSuccess;
|
|
ULONG i;
|
|
LPSPropValue lpPropsMAPI = *lppProps, lpPropsWAB = NULL;
|
|
ULONG cbProps;
|
|
SCODE sc;
|
|
ULONG cProps = *lpcProps;
|
|
ULONG iPR_ADDRTYPE = NOT_FOUND;
|
|
ULONG iPR_EMAIL_ADDRESS = NOT_FOUND;
|
|
ULONG iPR_PRIMARY_FAX_NUMBER = NOT_FOUND;
|
|
ULONG iPR_BUSINESS_FAX_NUMBER = NOT_FOUND;
|
|
ULONG iPR_MSNINET_DOMAIN = NOT_FOUND;
|
|
ULONG iPR_MSNINET_ADDRESS = NOT_FOUND;
|
|
ULONG iPR_DISPLAY_NAME = NOT_FOUND;
|
|
ULONG iPR_OBJECT_TYPE = NOT_FOUND;
|
|
LPSBinary lpEntryID = NULL;
|
|
LPTSTR lpTemp;
|
|
BOOL fBadAddress = FALSE;
|
|
ULONG cbDisplayName;
|
|
LPTSTR lpDisplayName = NULL;
|
|
|
|
|
|
// MAPIDebugProperties(lpPropsMAPI, *lpcProps, "MailUser BEFORE");
|
|
|
|
// First pass: Remove the junk
|
|
for (i = 0; i < cProps; i++) {
|
|
// Error value
|
|
if (PROP_ERROR(lpPropsMAPI[i])) {
|
|
lpPropsMAPI[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
|
|
// Named property
|
|
if (PROP_ID(lpPropsMAPI[i].ulPropTag) >= MIN_NAMED_PROPID) {
|
|
lpPropsMAPI[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
|
|
// Object property
|
|
if (PROP_TYPE(lpPropsMAPI[i].ulPropTag) == PT_OBJECT) {
|
|
lpPropsMAPI[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
switch (lpPropsMAPI[i].ulPropTag) {
|
|
case PR_ENTRYID:
|
|
lpEntryID = &lpPropsMAPI[i].Value.bin;
|
|
// fall through
|
|
|
|
case PR_PRIMARY_CAPABILITY:
|
|
case PR_TEMPLATEID:
|
|
case PR_SEARCH_KEY:
|
|
case PR_INITIAL_DETAILS_PANE:
|
|
case PR_RECORD_KEY:
|
|
case PR_MAPPING_SIGNATURE:
|
|
lpPropsMAPI[i].ulPropTag = PR_NULL;
|
|
break;
|
|
|
|
case PR_COMMENT:
|
|
// Don't save PR_COMMENT if it is empty
|
|
if (lstrlen(lpPropsMAPI[i].Value.LPSZ) == 0) {
|
|
lpPropsMAPI[i].ulPropTag = PR_NULL;
|
|
}
|
|
break;
|
|
|
|
// Keep track of the position of these for later
|
|
case PR_ADDRTYPE:
|
|
iPR_ADDRTYPE = i;
|
|
break;
|
|
case PR_OBJECT_TYPE:
|
|
iPR_OBJECT_TYPE = i;
|
|
break;
|
|
case PR_EMAIL_ADDRESS:
|
|
iPR_EMAIL_ADDRESS = i;
|
|
break;
|
|
case PR_PRIMARY_FAX_NUMBER:
|
|
iPR_PRIMARY_FAX_NUMBER = i;
|
|
break;
|
|
case PR_BUSINESS_FAX_NUMBER:
|
|
iPR_BUSINESS_FAX_NUMBER = i;
|
|
break;
|
|
case PR_MSNINET_ADDRESS:
|
|
iPR_MSNINET_ADDRESS = i;
|
|
break;
|
|
case PR_MSNINET_DOMAIN:
|
|
iPR_MSNINET_DOMAIN = i;
|
|
break;
|
|
case PR_DISPLAY_NAME:
|
|
iPR_DISPLAY_NAME = i;
|
|
|
|
// Make sure it isn't quoted.
|
|
lpDisplayName = lpPropsMAPI[i].Value.LPSZ;
|
|
if (lpDisplayName[0] == '\'') {
|
|
cbDisplayName = lstrlen(lpDisplayName);
|
|
if ((cbDisplayName > 1) && lpDisplayName[cbDisplayName - 1] == '\'') {
|
|
// String is surrounded by apostrophes. Strip them.
|
|
lpDisplayName[cbDisplayName - 1] = '\0';
|
|
lpDisplayName++;
|
|
lpPropsMAPI[i].Value.LPSZ = lpDisplayName;
|
|
}
|
|
} else {
|
|
if (lpDisplayName[0] == '"') {
|
|
cbDisplayName = lstrlen(lpDisplayName);
|
|
if ((cbDisplayName > 1) && lpDisplayName[cbDisplayName - 1] == '"') {
|
|
// String is surrounded by quotes. Strip them.
|
|
lpDisplayName[cbDisplayName - 1] = '\0';
|
|
lpDisplayName++;
|
|
lpPropsMAPI[i].Value.LPSZ = lpDisplayName;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Put this after the switch since we do want to track a few props which fall in
|
|
// the 0x6000 range but don't want to transfer them to the wab.
|
|
if (PROP_ID(lpPropsMAPI[i].ulPropTag) >= MAX_SCHEMA_PROPID) {
|
|
lpPropsMAPI[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// Second pass: Fix up the addresses
|
|
if (iPR_ADDRTYPE != NOT_FOUND) {
|
|
if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szFAX)) {
|
|
DebugTrace("FAX address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
|
|
//
|
|
// Handle MS-FAX Address conversion
|
|
//
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
// Rename the PR_EMAIL_ADDRESS to PR_BUSINESS_FAX_NUMBER
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].ulPropTag = PR_BUSINESS_FAX_NUMBER;
|
|
|
|
// Get rid of any existing PR_BUSINESS_FAX_NUMBER
|
|
if (iPR_BUSINESS_FAX_NUMBER != NOT_FOUND) {
|
|
lpPropsMAPI[iPR_BUSINESS_FAX_NUMBER].ulPropTag = PR_NULL;
|
|
iPR_BUSINESS_FAX_NUMBER = NOT_FOUND;
|
|
}
|
|
}
|
|
// Nuke ADDRTYPE
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szMSN)) {
|
|
ULONG cchSize = lstrlen(lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ) + 1 + cbMSNpostfix ;
|
|
DebugTrace("MSN address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
//
|
|
// Handle MSN Address conversion
|
|
//
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
// Allocate a new, longer string
|
|
if (FAILED(sc = MAPIAllocateMore(
|
|
sizeof(TCHAR) * cchSize,
|
|
lpPropsMAPI,
|
|
&lpTemp))) {
|
|
|
|
DebugTrace("HrFilterImportMailUserProps:MAPIAllocateMore -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
// append the msn site
|
|
StrCpyN(lpTemp, lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ, cchSize);
|
|
StrCatBuff(lpTemp, szMSNpostfix, cchSize);
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ = lpTemp;
|
|
|
|
// Convert MSN addrtype to SMTP
|
|
lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szSMTP;
|
|
|
|
} else {
|
|
// No address, nuke ADDRTYPE
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szCOMPUSERVE)) {
|
|
ULONG cchSize = lstrlen(lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ) + 1 + cbCOMPUSERVEpostfix;
|
|
DebugTrace("COMPUSERVE address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
//
|
|
// Handle COMPUSERVE Address conversion
|
|
//
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
// Allocate a new, longer string
|
|
if (FAILED(sc = MAPIAllocateMore(
|
|
sizeof(TCHAR)*cchSize,
|
|
lpPropsMAPI,
|
|
&lpTemp))) {
|
|
|
|
DebugTrace("HrFilterImportMailUserProps:MAPIAllocateMore -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
// append the Compuserve site
|
|
StrCpyN(lpTemp, lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ, cchSize);
|
|
StrCatBuff(lpTemp, szCOMPUSERVEpostfix, cchSize);
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ = lpTemp;
|
|
|
|
// I need to convert the ',' to a '.'
|
|
while (*lpTemp) {
|
|
if (*lpTemp == ',') {
|
|
*lpTemp = '.';
|
|
break; // should only be one comma
|
|
}
|
|
lpTemp = CharNext(lpTemp);
|
|
}
|
|
|
|
// Convert COMPUSERVE addrtype to SMTP
|
|
lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szSMTP;
|
|
|
|
} else {
|
|
// No address, nuke ADDRTYPE
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szMSNINET)) {
|
|
ULONG cchSize =
|
|
lstrlen(lpPropsMAPI[iPR_MSNINET_ADDRESS].Value.LPSZ) + cbAtSign +
|
|
lstrlen(lpPropsMAPI[iPR_MSNINET_DOMAIN].Value.LPSZ) + 1;
|
|
DebugTrace("MSINET address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
//
|
|
// Handle MSN Internet address conversion. These are weird.
|
|
// They often don't fill in the PR_EMAIL_ADDRESS at all, but do fill
|
|
// in some private properties: 6001 and 6002 with the name and domain,
|
|
// respectively. We should take these and append them with the '@' to
|
|
// get our PR_EMAIL_ADDRESS. We will toss out any existing
|
|
// PR_EMAIL_ADDRESS in favor of these values.
|
|
//
|
|
// Allocate a new string
|
|
//
|
|
if ((iPR_MSNINET_ADDRESS != NOT_FOUND) && (iPR_MSNINET_DOMAIN != NOT_FOUND)) {
|
|
if (FAILED(sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize,
|
|
lpPropsMAPI,
|
|
&lpTemp))) {
|
|
DebugTrace("HrFilterImportMailUserProps:MAPIAllocateMore -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
// Build the address
|
|
StrCpyN(lpTemp, lpPropsMAPI[iPR_MSNINET_ADDRESS].Value.LPSZ, cchSize);
|
|
StrCatBuff(lpTemp, szAtSign, cchSize);
|
|
StrCatBuff(lpTemp, lpPropsMAPI[iPR_MSNINET_DOMAIN].Value.LPSZ, cchSize);
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ = lpTemp;
|
|
|
|
// Convert addrtype to SMTP
|
|
lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szSMTP;
|
|
} else if (iPR_EMAIL_ADDRESS && lstrlen(lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ)) {
|
|
// keep existing PR_EMAIL_ADDRES and assume it's ok
|
|
lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szSMTP;
|
|
} else {
|
|
// No address, nuke ADDRTYPE
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szMS)) {
|
|
DebugTrace("MS address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
// No SMTP form of a MSMail address. destroy it.
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].ulPropTag = PR_NULL;
|
|
fBadAddress = TRUE;
|
|
}
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szX400)) {
|
|
DebugTrace("X400 address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
// No SMTP form of a X400 address. destroy it.
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].ulPropTag = PR_NULL;
|
|
fBadAddress = TRUE;
|
|
}
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szMSA)) {
|
|
DebugTrace("MacMail address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
// No SMTP form of a MacMail address. destroy it.
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].ulPropTag = PR_NULL;
|
|
fBadAddress = TRUE;
|
|
}
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szEX)) {
|
|
DebugTrace("EX address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
|
|
if (lpTemp = GetEMSSMTPAddress(lpObjectMAPI, lpPropsMAPI)) {
|
|
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].Value.LPSZ = lpTemp;
|
|
|
|
// Convert addrtype to SMTP
|
|
lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szSMTP;
|
|
|
|
// Make sure that caller doesn't think this is a Personal DL.
|
|
*lpfDL = FALSE;
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
lpPropsMAPI[iPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
|
|
lpPropsMAPI[iPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
|
|
}
|
|
|
|
} else {
|
|
if (iPR_EMAIL_ADDRESS != NOT_FOUND) {
|
|
lpPropsMAPI[iPR_EMAIL_ADDRESS].ulPropTag = PR_NULL;
|
|
fBadAddress = TRUE;
|
|
}
|
|
lpPropsMAPI[iPR_ADDRTYPE].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szSMTP)) {
|
|
DebugTrace("SMTP address for %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
} else if (! lstrcmpi(lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ, szMAPIPDL)) {
|
|
DebugTrace("MAPIPDL %s\n", lpPropsMAPI[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
// Distribution list, ignore it.
|
|
} else {
|
|
MAPIDebugProperties(lpPropsMAPI, cProps, "Unknown address type");
|
|
DebugTrace("Found unknown PR_ADDRTYPE: %s\n", lpPropsMAPI[iPR_ADDRTYPE].Value.LPSZ);
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
// PR_BUSINESS_FAX_NUMBER?
|
|
// The PAB puts the Fax number in PR_PRIMARY_FAX_NUMBER, but the WAB UI splits it
|
|
// into PR_BUSINESS_FAX_NUMBER and PR_HOME_FAX_NUMBER. We always assume that the
|
|
// Primary fax number is business.
|
|
if ((iPR_PRIMARY_FAX_NUMBER != NOT_FOUND) && (iPR_BUSINESS_FAX_NUMBER == NOT_FOUND)) {
|
|
// We need to also have a PR_BUSINESS_FAX_NUMBER
|
|
// Find the next PR_NULL spot.
|
|
iPR_BUSINESS_FAX_NUMBER = iPR_PRIMARY_FAX_NUMBER; // overwrite this one if there isn't
|
|
// an available slot in the prop array.
|
|
for (i = 0; i < cProps; i++) {
|
|
if (lpPropsMAPI[i].ulPropTag == PR_NULL) {
|
|
iPR_BUSINESS_FAX_NUMBER = i;
|
|
lpPropsMAPI[iPR_BUSINESS_FAX_NUMBER].Value.LPSZ =
|
|
lpPropsMAPI[iPR_PRIMARY_FAX_NUMBER].Value.LPSZ;
|
|
break;
|
|
}
|
|
}
|
|
|
|
lpPropsMAPI[iPR_BUSINESS_FAX_NUMBER].ulPropTag = PR_BUSINESS_FAX_NUMBER;
|
|
}
|
|
|
|
|
|
// Get rid of PR_NULL props
|
|
for (i = 0; i < cProps; i++) {
|
|
if (lpPropsMAPI[i].ulPropTag == PR_NULL) {
|
|
// Slide the props down.
|
|
if (i + 1 < cProps) { // Are there any higher props to copy?
|
|
CopyMemory(&lpPropsMAPI[i], &lpPropsMAPI[i + 1], ((cProps - i) - 1) * sizeof(lpPropsMAPI[i]));
|
|
}
|
|
// decrement count
|
|
cProps--;
|
|
i--; // You overwrote the current propval. Look at it again.
|
|
}
|
|
}
|
|
|
|
|
|
// Reallocate as WAB memory.
|
|
if (sc = ScCountProps(cProps, lpPropsMAPI, &cbProps)) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("ScCountProps -> %x\n", sc);
|
|
goto exit;
|
|
}
|
|
|
|
if (sc = WABAllocateBuffer(cbProps, &lpPropsWAB)) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("WABAllocateBuffer -> %x\n", sc);
|
|
goto exit;
|
|
}
|
|
|
|
if (sc = ScCopyProps(cProps,
|
|
lpPropsMAPI,
|
|
lpPropsWAB,
|
|
NULL)) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("ScCopyProps -> %x\n", sc);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
if (lpPropsMAPI) {
|
|
MAPIFreeBuffer(lpPropsMAPI);
|
|
}
|
|
|
|
if (HR_FAILED(hResult)) {
|
|
if (lpPropsWAB) {
|
|
WABFreeBuffer(lpPropsWAB);
|
|
lpPropsWAB = NULL;
|
|
}
|
|
cProps = 0;
|
|
} else if (fBadAddress) {
|
|
hResult = ResultFromScode(WAB_W_BAD_EMAIL);
|
|
}
|
|
|
|
*lppProps = lpPropsWAB;
|
|
*lpcProps = cProps;
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : HandleImportError
|
|
|
|
Purpose : Decides if a dialog needs to be displayed to
|
|
indicate the failure and does so.
|
|
|
|
Parameters: hwnd = main dialog window
|
|
ids = String ID (optional: calculated from hResult if 0)
|
|
hResult = Result of action
|
|
lpDisplayName = display name of object that failed
|
|
lpEmailAddress = email address of object that failed or NULL
|
|
lpImportOptions -> import options structure
|
|
|
|
Returns : TRUE if user requests ABORT.
|
|
|
|
Comment : Abort is not yet implemented in the dialog, but if you
|
|
ever want to, just make this routine return TRUE;
|
|
|
|
***************************************************************************/
|
|
BOOL HandleImportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress, LPWAB_IMPORT_OPTIONS lpImportOptions) {
|
|
BOOL fAbort = FALSE;
|
|
ERROR_INFO EI;
|
|
|
|
if ((ids || hResult) && ! lpImportOptions->fNoErrors) {
|
|
if (ids == 0) {
|
|
switch (GetScode(hResult)) {
|
|
case WAB_W_BAD_EMAIL:
|
|
ids = lpEmailAddress ? IDS_ERROR_EMAIL_ADDRESS_2 : IDS_ERROR_EMAIL_ADDRESS_1;
|
|
break;
|
|
|
|
case MAPI_E_NO_SUPPORT:
|
|
// Propbably failed to open contents on a distribution list
|
|
ids = IDS_ERROR_NO_SUPPORT;
|
|
break;
|
|
|
|
case MAPI_E_USER_CANCEL:
|
|
return(TRUE);
|
|
|
|
default:
|
|
if (HR_FAILED(hResult)) {
|
|
DebugTrace("Error Box for Hresult: 0x%08x\n", GetScode(hResult));
|
|
Assert(FALSE); // want to know about it.
|
|
ids = IDS_ERROR_GENERAL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
EI.lpszDisplayName = lpDisplayName;
|
|
EI.lpszEmailAddress = lpEmailAddress;
|
|
EI.ErrorResult = ERROR_OK;
|
|
EI.ids = ids;
|
|
EI.fExport = FALSE;
|
|
EI.lpImportOptions = lpImportOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ErrorImport),
|
|
hwnd,
|
|
ErrorDialogProc,
|
|
(LPARAM)&EI);
|
|
|
|
fAbort = EI.ErrorResult == ERROR_ABORT;
|
|
}
|
|
|
|
return(fAbort);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FindExistingWABEntry
|
|
|
|
Purpose : Finds an existing entry in the WAB
|
|
|
|
Parameters: lpProps -> PropArray of MAPI entry
|
|
cProps = number of props in lpProps
|
|
lpContainerWAB -> WAB Container object
|
|
lppEIDWAB -> returned EntryID (caller must WABFreeBuffer)
|
|
lpcbEIDWAB -> returned size of lppEID
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : At this point, we expect to find a match since
|
|
SaveChanges said we had a duplicate.
|
|
|
|
***************************************************************************/
|
|
HRESULT FindExistingWABEntry(LPSPropValue lpProps,
|
|
ULONG cProps,
|
|
LPABCONT lpContainerWAB,
|
|
LPENTRYID * lppEIDWAB,
|
|
LPULONG lpcbEIDWAB) {
|
|
ULONG rgFlagList[2];
|
|
LPFlagList lpFlagList = (LPFlagList)rgFlagList;
|
|
LPADRLIST lpAdrListWAB = NULL;
|
|
SCODE sc;
|
|
HRESULT hResult = hrSuccess;
|
|
LPSBinary lpsbEntryID = NULL;
|
|
ULONG cbEID = 0;
|
|
|
|
|
|
*lpcbEIDWAB = 0;
|
|
*lppEIDWAB = NULL;
|
|
|
|
|
|
// find the existing WAB entry.
|
|
// Setup for ResolveNames on the WAB container.
|
|
if (sc = WABAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY), &lpAdrListWAB)) {
|
|
DebugTrace("WAB Allocation(ADRLIST) failed -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
lpAdrListWAB->cEntries = 1;
|
|
lpAdrListWAB->aEntries[0].ulReserved1 = 0;
|
|
lpAdrListWAB->aEntries[0].cValues = 1;
|
|
|
|
if (sc = WABAllocateBuffer(sizeof(SPropValue), &lpAdrListWAB->aEntries[0].rgPropVals)) {
|
|
DebugTrace("WAB Allocation(ADRENTRY propval) failed -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
lpAdrListWAB->aEntries[0].rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
|
|
if (! (lpAdrListWAB->aEntries[0].rgPropVals[0].Value.LPSZ =
|
|
FindStringInProps(lpProps, cProps, PR_DISPLAY_NAME))) {
|
|
DebugTrace("Can't find PR_DISPLAY_NAME in entry\n");
|
|
// pretty weird if this caused a collision...
|
|
goto exit;
|
|
}
|
|
|
|
lpFlagList->cFlags = 1;
|
|
lpFlagList->ulFlag[0] = MAPI_UNRESOLVED;
|
|
|
|
if (HR_FAILED(hResult = lpContainerWAB->lpVtbl->ResolveNames(lpContainerWAB,
|
|
NULL, // tag set
|
|
0, // ulFlags
|
|
lpAdrListWAB,
|
|
lpFlagList))) {
|
|
DebugTrace("WAB ResolveNames -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
switch (lpFlagList->ulFlag[0]) {
|
|
case MAPI_UNRESOLVED:
|
|
DebugTrace("WAB ResolveNames didn't find the entry\n");
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
goto exit;
|
|
case MAPI_AMBIGUOUS:
|
|
#ifdef NEW_STUFF
|
|
// Do it the hard way. Open a table, restrict, take the first match.
|
|
lpContainerWAB->lpVtbl->GetContentsTable(lpContainerWAB,
|
|
|
|
if (HR_FAILED(hResult = lpContainerWAB->lpVtbl->GetContentsTable(lpContainerWAB,
|
|
0, // ulFlags
|
|
&lpTableWAB))) {
|
|
DebugTrace("ImportEntry:GetContentsTable(WAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
lpTableWAB->lpVtbl->Restrict....... // just the ones that match our entry...
|
|
|
|
cRows = 1;
|
|
while (cRows) {
|
|
// Get the next DL entry
|
|
if (hResult = lpTableWAB->lpVtbl->QueryRows(lpTableWAB,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("DL: QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow && lpRow->cRows) {
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
} else {
|
|
break; // done
|
|
}
|
|
}
|
|
#endif // NEW_STUFF
|
|
break;
|
|
}
|
|
|
|
// Find the PR_ENTRYID
|
|
if (! (lpsbEntryID = FindAdrEntryID(lpAdrListWAB, 0))) {
|
|
DebugTrace("WAB ResolveNames didn't give us an EntryID\n");
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
*lpcbEIDWAB = lpsbEntryID->cb;
|
|
|
|
if (FAILED(sc = WABAllocateBuffer(*lpcbEIDWAB, lppEIDWAB))) {
|
|
DebugTrace("ImportEntry: WABAllocateBuffer(WAB ENTRYID) -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
*lpcbEIDWAB = 0;
|
|
goto exit;
|
|
}
|
|
|
|
// Copy the new EntryID into the buffer
|
|
CopyMemory(*lppEIDWAB, lpsbEntryID->lpb, *lpcbEIDWAB);
|
|
exit:
|
|
if (lpAdrListWAB) {
|
|
WABFreePadrlist(lpAdrListWAB);
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* CheckReversedDisplayName(lpDisplayName);
|
|
*
|
|
* PAB and outlook display names are "LastName, FirstName"
|
|
* We need to reverse this for the WAB to handle it correctly ...
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
void CheckReversedDisplayName(LPTSTR lpDisplayName)
|
|
{
|
|
TCHAR szTemp[MAX_PATH * 3];
|
|
LPTSTR lp1=NULL, lp2=NULL;
|
|
ULONG cchSize = lstrlen(lpDisplayName);
|
|
|
|
if(!lpDisplayName)
|
|
return;
|
|
|
|
lp1 = lp2 = lpDisplayName;
|
|
|
|
while(lp1 && *lp1)
|
|
{
|
|
if(*lp1 == ',')
|
|
{
|
|
// A comma means this is Last, First
|
|
// We will make an assumption here that "L, F" or "L,F" is longer than or equal to "F L" and so
|
|
// we can reverse the name in place without any problems
|
|
//
|
|
lp2 = CharNext(lp1);
|
|
//skip spaces
|
|
while (IsSpace(lp2)) {
|
|
lp2 = CharNext(lp2);
|
|
}
|
|
*lp1 = '\0';
|
|
StrCpyN(szTemp, lpDisplayName, ARRAYSIZE(szTemp));
|
|
StrCpyN(lpDisplayName, lp2, cchSize);
|
|
StrCatBuff(lpDisplayName, TEXT(" "), cchSize);
|
|
StrCatBuff(lpDisplayName, szTemp, cchSize);
|
|
break;
|
|
}
|
|
lp1 = CharNext(lp1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ImportEntry
|
|
|
|
Purpose : Migrates the entry from the PAB to the WAB
|
|
|
|
Parameters: hwnd = main dialog window
|
|
lpAdrBookMAPI -> MAPI AdrBook object
|
|
lpContainerWAB -> WAB PAB container
|
|
lpCreateEIDsWAB -> SPropValue of default object creation EIDs
|
|
ulObjectType = {MAPI_MAILUSER, MAPI_DISTLIST}
|
|
lpEID -> ENTYRID of the PAB entry
|
|
cbEID = sizeof lpEID
|
|
lppEIDWAB -> returned WAB ENTRYID: Caller must WABFreeBuffer.
|
|
May be NULL.
|
|
lpcbEIDWAB -> returned size of lppEIDWAB (ignored if lppEIDWAB
|
|
is NULL.
|
|
fInDL = TRUE if this entry is for creation in a Distribution List
|
|
fForceReplace = TRUE if this entry should replace any duplicate.
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : This routine is a MESS! Should break it up when we get time.
|
|
|
|
***************************************************************************/
|
|
HRESULT ImportEntry(HWND hwnd,
|
|
LPADRBOOK lpAdrBookMAPI,
|
|
LPABCONT lpContainerWAB,
|
|
LPSPropValue lpCreateEIDsWAB,
|
|
ULONG ulObjectType,
|
|
LPENTRYID lpEID,
|
|
ULONG cbEID,
|
|
LPENTRYID * lppEIDWAB,
|
|
LPULONG lpcbEIDWAB,
|
|
BOOL fInDL,
|
|
BOOL fForceReplace) {
|
|
HRESULT hResult = hrSuccess;
|
|
SCODE sc;
|
|
BOOL fDistList = FALSE;
|
|
BOOL fDuplicate = FALSE;
|
|
BOOL fDuplicateEID;
|
|
BOOL fReturnEID = FALSE;
|
|
ULONG ulObjectTypeOpen;
|
|
LPDISTLIST lpDistListMAPI = NULL, lpDistListWAB = NULL;
|
|
LPMAPIPROP lpMailUserMAPI = NULL, lpMailUserWAB = NULL;
|
|
LPSPropValue lpProps = NULL;
|
|
ULONG cProps, cEIDPropWAB;
|
|
LPMAPITABLE lpDLTableMAPI = NULL;
|
|
ULONG cRows;
|
|
LPSRowSet lpRow = NULL;
|
|
LPENTRYID lpeidDLWAB = NULL;
|
|
ULONG cbeidDLWAB;
|
|
LPSPropValue lpEIDPropWAB = NULL;
|
|
LPMAPIPROP lpEntryWAB = NULL;
|
|
ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
|
|
REPLACE_INFO RI;
|
|
LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
|
|
static TCHAR szBufferDLMessage[MAX_RESOURCE_STRING + 1] = "";
|
|
LPTSTR lpszMessage;
|
|
LONG lListIndex = -1;
|
|
LPENTRYID lpEIDNew = NULL;
|
|
DWORD cbEIDNew = 0;
|
|
LPIID lpIIDOpen;
|
|
ULONG iCreateTemplate = iconPR_DEF_CREATE_MAILUSER;
|
|
|
|
|
|
// Check the entry against our "seen" list
|
|
fDuplicateEID = AddEntryToImportList(cbEID, lpEID, &lListIndex);
|
|
|
|
if (! fDuplicateEID) {
|
|
if ((fForceReplace || (lpImportOptions->ReplaceOption == WAB_REPLACE_ALWAYS)) && ! fInDL) {
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
}
|
|
|
|
// Set up some object type specific variables
|
|
switch (ulObjectType) {
|
|
default:
|
|
DebugTrace("ImportEntry got unknown object type %u, assuming MailUser\n", ulObjectType);
|
|
Assert(FALSE);
|
|
|
|
case MAPI_MAILUSER:
|
|
iCreateTemplate = iconPR_DEF_CREATE_MAILUSER;
|
|
lpIIDOpen = NULL;
|
|
fDistList = FALSE;
|
|
break;
|
|
|
|
case MAPI_DISTLIST:
|
|
iCreateTemplate = iconPR_DEF_CREATE_DL;
|
|
lpIIDOpen = (LPIID)&IID_IDistList;
|
|
fDistList = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
// Open the entry
|
|
if (HR_FAILED(hResult = lpAdrBookMAPI->lpVtbl->OpenEntry(lpAdrBookMAPI,
|
|
cbEID,
|
|
lpEID,
|
|
lpIIDOpen,
|
|
0,
|
|
&ulObjectTypeOpen,
|
|
(LPUNKNOWN *)&lpMailUserMAPI))) {
|
|
DebugTrace("OpenEntry(MAPI MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
// If DISTLIST, assume we got lpMailUser until we need lpDistList.
|
|
|
|
Assert(lpMailUserMAPI);
|
|
Assert(ulObjectType == ulObjectTypeOpen);
|
|
|
|
// Get the properties from this entry
|
|
if (HR_FAILED(hResult = lpMailUserMAPI->lpVtbl->GetProps(lpMailUserMAPI,
|
|
NULL,
|
|
0,
|
|
&cProps,
|
|
&lpProps))) {
|
|
DebugTrace("ImportEntry:GetProps(MAPI) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// NOTE: Must not fail between here and HrFilterImportMailUserProps because
|
|
// we will end up freeing lpProps with WABFreeBuffer.
|
|
//
|
|
|
|
// Filter the property array here
|
|
if (hResult = HrFilterImportMailUserProps(&cProps, &lpProps, lpMailUserMAPI, &fDistList)) {
|
|
lpDisplayName = FindStringInProps(lpProps, cProps, PR_DISPLAY_NAME);
|
|
lpEmailAddress = FindStringInProps(lpProps, cProps, PR_EMAIL_ADDRESS);
|
|
|
|
if (HandleImportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpDisplayName,
|
|
lpEmailAddress,
|
|
lpImportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
}
|
|
}
|
|
lpDisplayName = FindStringInProps(lpProps, cProps, PR_DISPLAY_NAME);
|
|
lpEmailAddress = FindStringInProps(lpProps, cProps, PR_EMAIL_ADDRESS);
|
|
|
|
CheckReversedDisplayName(lpDisplayName);
|
|
|
|
if (ulObjectType == MAPI_DISTLIST && ! fDistList) {
|
|
// Filter must have changed this to a mailuser.
|
|
ulObjectType = MAPI_MAILUSER;
|
|
iCreateTemplate = iconPR_DEF_CREATE_MAILUSER;
|
|
lpIIDOpen = NULL;
|
|
}
|
|
|
|
//
|
|
// NOTE: lpProps after this point is WAB Allocated rather than MAPI allocated.
|
|
//
|
|
|
|
if (HR_FAILED(hResult = lpContainerWAB->lpVtbl->CreateEntry(lpContainerWAB,
|
|
lpCreateEIDsWAB[iCreateTemplate].Value.bin.cb,
|
|
(LPENTRYID)lpCreateEIDsWAB[iCreateTemplate].Value.bin.lpb,
|
|
ulCreateFlags,
|
|
&lpMailUserWAB))) {
|
|
DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (fDistList) {
|
|
// Update status message
|
|
if (*szBufferDLMessage == '\0') { // only load once, then keep it.
|
|
LoadString(hInst, IDS_MESSAGE_IMPORTING_DL, szBufferDLMessage, ARRAYSIZE(szBufferDLMessage));
|
|
}
|
|
if (lpDisplayName) {
|
|
ULONG cchSize = lstrlen(szBufferDLMessage) + 1 + lstrlen(lpDisplayName);
|
|
if (lpszMessage = LocalAlloc(LMEM_FIXED, sizeof(TCHAR)*cchSize)) {
|
|
wnsprintf(lpszMessage, cchSize, szBufferDLMessage, lpDisplayName);
|
|
DebugTrace("Status Message: %s\n", lpszMessage);
|
|
if (! SetDlgItemText(hwnd, IDC_Message, lpszMessage)) {
|
|
DebugTrace("SetDlgItemText -> %u\n", GetLastError());
|
|
}
|
|
LocalFree(lpszMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Set the properties on the WAB entry
|
|
if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SetProps(lpMailUserWAB,
|
|
cProps, // cValues
|
|
lpProps, // property array
|
|
NULL))) { // problems array
|
|
DebugTrace("ImportEntry:SetProps(WAB) -> %x\n", GetScode(hResult));
|
|
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
|
|
if (! lpDisplayName) {
|
|
DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Do we need to prompt?
|
|
// if (! fInDL && lpImportOptions->ReplaceOption == WAB_REPLACE_PROMPT) {
|
|
if (lpImportOptions->ReplaceOption == WAB_REPLACE_PROMPT) {
|
|
// Prompt user with dialog. If they say YES, we should
|
|
// recurse with the FORCE flag set.
|
|
|
|
RI.lpszDisplayName = lpDisplayName;
|
|
RI.lpszEmailAddress = lpEmailAddress;
|
|
RI.ConfirmResult = CONFIRM_ERROR;
|
|
RI.fExport = FALSE;
|
|
RI.lpImportOptions = lpImportOptions;
|
|
|
|
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
|
|
hResult = ImportEntry(hwnd,
|
|
lpAdrBookMAPI,
|
|
lpContainerWAB,
|
|
lpCreateEIDsWAB,
|
|
ulObjectType,
|
|
lpEID,
|
|
cbEID,
|
|
&lpEIDNew, // Need this for later
|
|
&cbEIDNew,
|
|
FALSE,
|
|
TRUE);
|
|
if (hResult) {
|
|
if (HandleImportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpDisplayName,
|
|
lpEmailAddress,
|
|
lpImportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CONFIRM_ABORT:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
|
|
default:
|
|
// NO
|
|
fDuplicate = TRUE;
|
|
break;
|
|
}
|
|
} else {
|
|
fDuplicate = TRUE;
|
|
}
|
|
|
|
hResult = hrSuccess;
|
|
|
|
} else {
|
|
DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
}
|
|
} else {
|
|
// What is the ENTRYID of our new entry?
|
|
if ((hResult = lpMailUserWAB->lpVtbl->GetProps(lpMailUserWAB,
|
|
(LPSPropTagArray)&ptaEid,
|
|
0,
|
|
&cEIDPropWAB,
|
|
&lpEIDPropWAB))) {
|
|
DebugTrace("ImportEntry: GetProps(WAB ENTRYID) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
Assert(cEIDPropWAB);
|
|
Assert(lpEIDPropWAB[ieidPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
|
|
cbEIDNew = lpEIDPropWAB[0].Value.bin.cb;
|
|
|
|
if (FAILED(sc = WABAllocateBuffer(cbEIDNew, &lpEIDNew))) {
|
|
DebugTrace("ImportEntry: WABAllocateBuffer(WAB ENTRYID) -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
// Copy the new EntryID into the buffer
|
|
CopyMemory(lpEIDNew, lpEIDPropWAB[0].Value.bin.lpb, cbEIDNew);
|
|
}
|
|
|
|
|
|
//
|
|
// If this is a DISTLIST, fill it in.
|
|
//
|
|
if (fDistList && ! fDuplicate && cbEIDNew) {
|
|
lpDistListMAPI = (LPDISTLIST)lpMailUserMAPI; // This is REALLY a DISTLIST object
|
|
// DO NOT Release this!
|
|
|
|
// Open the new WAB DL as a DISTLIST object
|
|
if (HR_FAILED(hResult = lpContainerWAB->lpVtbl->OpenEntry(lpContainerWAB,
|
|
cbEIDNew,
|
|
lpEIDNew,
|
|
(LPIID)&IID_IDistList,
|
|
MAPI_MODIFY,
|
|
&ulObjectTypeOpen,
|
|
(LPUNKNOWN*)&lpDistListWAB))) {
|
|
DebugTrace("ImportEntry: WAB OpenEntry(IID_DistList) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
Assert(lpDistListWAB);
|
|
|
|
|
|
// For each entry in the DL:
|
|
// Migrate the entry (MailUser or DL) recursively
|
|
// Add new entryid to DL contents
|
|
if (HR_FAILED(hResult = lpDistListMAPI->lpVtbl->GetContentsTable(lpDistListMAPI,
|
|
0, // ulFlags
|
|
&lpDLTableMAPI ))) {
|
|
DebugTrace("ImportEntry:GetContentsTable(MAPI) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// Set the columns to those we're interested in
|
|
if (hResult = lpDLTableMAPI->lpVtbl->SetColumns(lpDLTableMAPI,
|
|
(LPSPropTagArray)&ptaColumns,
|
|
0)) {
|
|
DebugTrace("MAPI SetColumns(DL Table) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
cRows = 1;
|
|
while (cRows) {
|
|
// Get the next DL entry
|
|
if (hResult = lpDLTableMAPI->lpVtbl->QueryRows(lpDLTableMAPI,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("DL: QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow && lpRow->cRows) {
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
if (lpRow) {
|
|
if (cRows = lpRow->cRows) { // yes, single '='
|
|
hResult = ImportEntry(hwnd,
|
|
lpAdrBookMAPI,
|
|
lpContainerWAB,
|
|
lpCreateEIDsWAB,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].Value.l,
|
|
(LPENTRYID)lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.lpb,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.cb,
|
|
&lpeidDLWAB, // returned new or existing entry
|
|
&cbeidDLWAB,
|
|
TRUE,
|
|
FALSE);
|
|
if (hResult) {
|
|
if (HandleImportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_DISPLAY_NAME].Value.LPSZ,
|
|
PropStringOrNULL(&lpRow->aRow[0].lpProps[iptaColumnsPR_EMAIL_ADDRESS]),
|
|
lpImportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
break; // out of loop
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
} // else, drop out of loop, we're done.
|
|
FreeProws(lpRow);
|
|
lpRow = NULL;
|
|
|
|
if (HR_FAILED(hResult)) {
|
|
// This entry couldn't be created. Ignore it.
|
|
DebugTrace("Coudln't create DL entry -> %x\n", GetScode(hResult));
|
|
hResult = hrSuccess;
|
|
continue;
|
|
}
|
|
|
|
// Add the Entry to the DL using the new entry's EntryID
|
|
if (cbeidDLWAB && lpeidDLWAB) {
|
|
// BUGBUG: Don't bother with this one if this is a duplicate entry.
|
|
if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->CreateEntry(lpDistListWAB,
|
|
cbeidDLWAB,
|
|
lpeidDLWAB,
|
|
0, // allow duplicates here
|
|
&lpEntryWAB))) {
|
|
DebugTrace("Couldn't create new entry in DL -> %x\n", GetScode(hResult));
|
|
break;
|
|
}
|
|
|
|
hResult = lpEntryWAB->lpVtbl->SaveChanges(lpEntryWAB, FORCE_SAVE);
|
|
|
|
if (lpEntryWAB) {
|
|
lpEntryWAB->lpVtbl->Release(lpEntryWAB);
|
|
lpEntryWAB = NULL;
|
|
}
|
|
}
|
|
|
|
if (lpeidDLWAB) {
|
|
WABFreeBuffer(lpeidDLWAB);
|
|
lpeidDLWAB = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
break; // done
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
DebugTrace("Found a duplicate EntryID\n");
|
|
}
|
|
|
|
//
|
|
// Save the entryid to the list and return a buffer with it
|
|
//
|
|
if (cbEIDNew && lpEIDNew) { // We created one?
|
|
// created one
|
|
} else if (fDuplicateEID && lListIndex != -1) { // Was it in the list?
|
|
cbEIDNew = lpEntriesSeen[lListIndex].sbinWAB.cb;
|
|
if (FAILED(sc = WABAllocateBuffer(cbEIDNew, &lpEIDNew))) {
|
|
DebugTrace("ImportEntry: WABAllocateBuffer(WAB ENTRYID) -> %x\n", sc);
|
|
// ignore
|
|
cbEIDNew = 0;
|
|
} else {
|
|
// Copy the EntryID from the list into the buffer
|
|
CopyMemory(lpEIDNew, lpEntriesSeen[lListIndex].sbinWAB.lpb, cbEIDNew);
|
|
}
|
|
|
|
} else if (fDuplicate) { // Was it a duplicate
|
|
FindExistingWABEntry(lpProps, cProps, lpContainerWAB, &lpEIDNew, &cbEIDNew);
|
|
// ignore errors since the lpEIDNew and cbEIDNew will be nulled out
|
|
}
|
|
|
|
// Update the seen list
|
|
if (! fDuplicateEID) {
|
|
MarkWABEntryInList(cbEIDNew, lpEIDNew, lListIndex);
|
|
}
|
|
|
|
// If caller requested the entryid's, return them
|
|
if (lpcbEIDWAB && lppEIDWAB) {
|
|
*lpcbEIDWAB = cbEIDNew;
|
|
*lppEIDWAB = lpEIDNew;
|
|
fReturnEID = TRUE; // don't free it
|
|
}
|
|
|
|
exit:
|
|
//
|
|
// Cleanup WAB stuff
|
|
//
|
|
if (lpProps) {
|
|
WABFreeBuffer(lpProps);
|
|
}
|
|
|
|
if (lpEIDPropWAB) {
|
|
WABFreeBuffer(lpEIDPropWAB);
|
|
}
|
|
|
|
if (lpEIDNew && ! fReturnEID) {
|
|
WABFreeBuffer(lpEIDNew);
|
|
}
|
|
|
|
if (lpeidDLWAB) {
|
|
WABFreeBuffer(lpeidDLWAB);
|
|
}
|
|
|
|
if (lpMailUserWAB) {
|
|
lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
|
|
}
|
|
|
|
if (lpDistListWAB) {
|
|
lpDistListWAB->lpVtbl->Release(lpDistListWAB);
|
|
}
|
|
|
|
//
|
|
// Cleanup MAPI stuff
|
|
//
|
|
if (lpRow) {
|
|
FreeProws(lpRow);
|
|
}
|
|
|
|
if (lpDLTableMAPI) {
|
|
lpDLTableMAPI->lpVtbl->Release(lpDLTableMAPI);
|
|
}
|
|
|
|
if (lpMailUserMAPI) {
|
|
lpMailUserMAPI->lpVtbl->Release(lpMailUserMAPI);
|
|
}
|
|
|
|
// Do not release this... It is the same object as lpMailUserMAPI!
|
|
// if (lpDistListMAPI) {
|
|
// lpDistListMAPI->lpVtbl->Release(lpDistListMAPI);
|
|
// }
|
|
|
|
if (! HR_FAILED(hResult)) {
|
|
hResult = hrSuccess;
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/*
|
|
* PAB EXPORT
|
|
*
|
|
* Migrate WAB to PAB
|
|
*/
|
|
|
|
BOOL HandleExportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress, LPWAB_EXPORT_OPTIONS lpExportOptions);
|
|
void StateExportNextMU(HWND hwnd);
|
|
void StateExportDL(HWND hwnd);
|
|
void StateExportNextDL(HWND hwnd);
|
|
void StateExportFinish(HWND hwnd);
|
|
void StateExportMU(HWND hwnd);
|
|
void StateExportError(HWND hwnd);
|
|
void StateExportCancel(HWND hwnd);
|
|
HRESULT ExportEntry(HWND hwnd,
|
|
LPADRBOOK lpAdrBookMAPI,
|
|
LPABCONT lpContainerWAB,
|
|
LPSPropValue lpCreateEIDsWAB,
|
|
ULONG ulObjectType,
|
|
LPENTRYID lpEID,
|
|
ULONG cbEID,
|
|
LPENTRYID * lppEIDWAB,
|
|
LPULONG lpcbEIDWAB,
|
|
BOOL fInDL,
|
|
BOOL fForceReplace);
|
|
|
|
LPSPropTagArray lpspta = NULL; // List of tags to export
|
|
LPTSTR * lppNames = NULL; // List of names of tags
|
|
|
|
|
|
//
|
|
// Map property tags to strings
|
|
//
|
|
|
|
PROP_NAME rgPropNames[NUM_MORE_EXPORT_PROPS] = {
|
|
// ulPropTag, fChosen, ids, lpszName lpszName
|
|
// Personal Pane
|
|
PR_GIVEN_NAME, FALSE, ids_ExportGivenName, NULL, NULL,
|
|
PR_SURNAME, FALSE, ids_ExportSurname, NULL, NULL,
|
|
PR_MIDDLE_NAME, FALSE, ids_ExportMiddleName, NULL, NULL,
|
|
PR_DISPLAY_NAME, TRUE, ids_ExportDisplayName, NULL, NULL,
|
|
PR_NICKNAME, FALSE, ids_ExportNickname, NULL, NULL,
|
|
PR_EMAIL_ADDRESS, TRUE, ids_ExportEmailAddress, NULL, NULL,
|
|
|
|
// Home Pane
|
|
PR_HOME_ADDRESS_STREET, TRUE, ids_ExportHomeAddressStreet, NULL, NULL,
|
|
PR_HOME_ADDRESS_CITY, TRUE, ids_ExportHomeAddressCity, NULL, NULL,
|
|
PR_HOME_ADDRESS_POSTAL_CODE, TRUE, ids_ExportHomeAddressPostalCode, NULL, NULL,
|
|
PR_HOME_ADDRESS_STATE_OR_PROVINCE, TRUE, ids_ExportHomeAddressState, NULL, NULL,
|
|
PR_HOME_ADDRESS_COUNTRY, TRUE, ids_ExportHomeAddressCountry, NULL, NULL,
|
|
PR_HOME_TELEPHONE_NUMBER, TRUE, ids_ExportHomeTelephoneNumber, NULL, NULL,
|
|
PR_HOME_FAX_NUMBER, FALSE, ids_ExportHomeFaxNumber, NULL, NULL,
|
|
PR_CELLULAR_TELEPHONE_NUMBER, FALSE, ids_ExportCellularTelephoneNumber, NULL, NULL,
|
|
PR_PERSONAL_HOME_PAGE, FALSE, ids_ExportPersonalHomePage, NULL, NULL,
|
|
|
|
// Business Pane
|
|
PR_BUSINESS_ADDRESS_STREET, TRUE, ids_ExportBusinessAddressStreet, NULL, NULL,
|
|
PR_BUSINESS_ADDRESS_CITY, TRUE, ids_ExportBusinessAddressCity, NULL, NULL,
|
|
PR_BUSINESS_ADDRESS_POSTAL_CODE, TRUE, ids_ExportBusinessAddressPostalCode, NULL, NULL,
|
|
PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE, TRUE, ids_ExportBusinessAddressStateOrProvince, NULL, NULL,
|
|
PR_BUSINESS_ADDRESS_COUNTRY, TRUE, ids_ExportBusinessAddressCountry, NULL, NULL,
|
|
PR_BUSINESS_HOME_PAGE, FALSE, ids_ExportBusinessHomePage, NULL, NULL,
|
|
PR_BUSINESS_TELEPHONE_NUMBER, TRUE, ids_ExportBusinessTelephoneNumber, NULL, NULL,
|
|
PR_BUSINESS_FAX_NUMBER, FALSE, ids_ExportBusinessFaxNumber, NULL, NULL,
|
|
PR_PAGER_TELEPHONE_NUMBER, FALSE, ids_ExportPagerTelephoneNumber, NULL, NULL,
|
|
PR_COMPANY_NAME, TRUE, ids_ExportCompanyName, NULL, NULL,
|
|
PR_TITLE, TRUE, ids_ExportTitle, NULL, NULL,
|
|
PR_DEPARTMENT_NAME, FALSE, ids_ExportDepartmentName, NULL, NULL,
|
|
PR_OFFICE_LOCATION, FALSE, ids_ExportOfficeLocation, NULL, NULL,
|
|
|
|
// Notes Pane
|
|
PR_COMMENT, FALSE, ids_ExportComment, NULL, NULL,
|
|
};
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportMU
|
|
|
|
Purpose : Start the migration of MailUsers
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Login to MAPI
|
|
Open the WAB
|
|
Open the MAPI AB
|
|
Open the WAB container
|
|
Get the WAB contents table
|
|
Restrict it to PR_OBJECTTYPE == MAPI_MAILUSER
|
|
Post new state(STATE_NEXT_MU)
|
|
|
|
***************************************************************************/
|
|
void StateExportMU(HWND hwnd) {
|
|
HRESULT hResult;
|
|
ULONG ulFlags;
|
|
ULONG cbPABEID, cbWABEID;
|
|
LPENTRYID lpPABEID = NULL, lpWABEID = NULL;
|
|
ULONG ulObjType;
|
|
ULONG_PTR ulUIParam = (ULONG_PTR)(void *)hwnd;
|
|
SRestriction restrictObjectType;
|
|
SPropValue spvObjectType;
|
|
ULONG cProps;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
WAB_PARAM wp = {0};
|
|
LPWAB_PARAM lpwp = NULL;
|
|
|
|
//
|
|
// Logon to MAPI and open the MAPI Address book, if one exists
|
|
//
|
|
DebugTrace(">>> STATE_EXPORT_MU\n");
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_LOGGING_IN);
|
|
|
|
if (FAILED(hResult = MAPIInitialize(NULL))) {
|
|
DebugTrace("MAPIInitialize -> %x\n", GetScode(hResult));
|
|
switch (GetScode(hResult)) {
|
|
case MAPI_E_NOT_ENOUGH_MEMORY:
|
|
SetDialogMessage(hwnd, IDS_ERROR_NOT_ENOUGH_MEMORY);
|
|
break;
|
|
case MAPI_E_NOT_ENOUGH_DISK:
|
|
SetDialogMessage(hwnd, IDS_ERROR_NOT_ENOUGH_DISK);
|
|
break;
|
|
|
|
default:
|
|
case MAPI_E_NOT_FOUND:
|
|
case MAPI_E_NOT_INITIALIZED:
|
|
SetDialogMessage(hwnd, IDS_ERROR_MAPI_DLL_NOT_FOUND);
|
|
break;
|
|
}
|
|
#ifdef OLD_STUFF
|
|
ShowWindow(GetDlgItem(hwnd, IDC_Progress), SW_HIDE); // hide progress bar
|
|
#endif // OLD_STUFF
|
|
fError = TRUE;
|
|
hResult = hrSuccess;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
ulFlags = MAPI_LOGON_UI | MAPI_NO_MAIL | MAPI_EXTENDED;
|
|
|
|
if (FAILED(hResult = MAPILogonEx(ulUIParam,
|
|
NULL,
|
|
NULL,
|
|
ulFlags,
|
|
(LPMAPISESSION FAR *)&lpMAPISession))) {
|
|
DebugTrace("MAPILogonEx -> %x\n", GetScode(hResult));
|
|
switch (GetScode(hResult)) {
|
|
case MAPI_E_USER_CANCEL:
|
|
SetDialogMessage(hwnd, IDS_STATE_EXPORT_IDLE);
|
|
break;
|
|
case MAPI_E_NOT_INITIALIZED:
|
|
SetDialogMessage(hwnd, IDS_ERROR_MAPI_DLL_NOT_FOUND);
|
|
break;
|
|
default:
|
|
SetDialogMessage(hwnd, IDS_ERROR_MAPI_LOGON);
|
|
break;
|
|
}
|
|
#ifdef OLD_STUFF
|
|
ShowWindow(GetDlgItem(hwnd, IDC_Progress), SW_HIDE); // hide progress bar
|
|
#endif // OLD_STUFF
|
|
fError = TRUE;
|
|
hResult = hrSuccess;
|
|
goto exit;
|
|
}
|
|
|
|
if (hResult = lpMAPISession->lpVtbl->OpenAddressBook(lpMAPISession, (ULONG_PTR)(void *)hwnd,
|
|
NULL,
|
|
0,
|
|
&lpAdrBookMAPI)) {
|
|
DebugTrace("OpenAddressBook(MAPI) -> %x", GetScode(hResult));
|
|
if(FAILED(hResult)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (! lpAdrBookMAPI) {
|
|
DebugTrace("MAPILogonEx didn't return a valid AdrBook object\n");
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open the MAPI PAB container
|
|
//
|
|
// [PaulHi] Raid #63578 1/7/98
|
|
// Correctly check return code and provide user error message if
|
|
// Exchange PAB cannot be opened.
|
|
//
|
|
hResult = lpAdrBookMAPI->lpVtbl->GetPAB(lpAdrBookMAPI,
|
|
&cbPABEID,
|
|
&lpPABEID);
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
DebugTrace("MAPI GetPAB -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
hResult = lpAdrBookMAPI->lpVtbl->OpenEntry(lpAdrBookMAPI,
|
|
cbPABEID, // size of EntryID to open
|
|
lpPABEID, // EntryID to open
|
|
NULL, // interface
|
|
MAPI_MODIFY, // flags
|
|
&ulObjType,
|
|
(LPUNKNOWN *)&lpContainerMAPI);
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
DebugTrace("MAPI OpenEntry(PAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
Assert(lpAdrBookWAB);
|
|
|
|
//
|
|
// Open the WAB's PAB container
|
|
//
|
|
if (hResult = lpAdrBookWAB->lpVtbl->GetPAB(lpAdrBookWAB,
|
|
&cbWABEID,
|
|
&lpWABEID)) {
|
|
DebugTrace("WAB GetPAB -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
} else {
|
|
if (hResult = lpAdrBookWAB->lpVtbl->OpenEntry(lpAdrBookWAB,
|
|
cbWABEID, // size of EntryID to open
|
|
lpWABEID, // EntryID to open
|
|
NULL, // interface
|
|
0, // flags
|
|
&ulObjType,
|
|
(LPUNKNOWN *)&lpContainerWAB)) {
|
|
DebugTrace("WAB OpenEntry(PAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
|
|
// Get the PAB's creation entryids
|
|
hResult = lpContainerMAPI->lpVtbl->GetProps(lpContainerMAPI,
|
|
(LPSPropTagArray)&ptaCon,
|
|
0,
|
|
&cProps,
|
|
&lpCreateEIDsMAPI);
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
DebugTrace("Can't get container properties for PAB\n");
|
|
// Bad stuff here!
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
// Validate the properites
|
|
if (lpCreateEIDsMAPI[iconPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
|
|
lpCreateEIDsMAPI[iconPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
|
|
{
|
|
DebugTrace("MAPI: Container property errors\n");
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
|
|
//
|
|
// All set... now loop through the WAB's entries, copying them to PAB
|
|
//
|
|
if (HR_FAILED(hResult = lpContainerWAB->lpVtbl->GetContentsTable(lpContainerWAB,
|
|
0, // ulFlags
|
|
&lpContentsTableWAB))) {
|
|
DebugTrace("WAB GetContentsTable(PAB Table) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the columns to those we're interested in
|
|
if (hResult = lpContentsTableWAB->lpVtbl->SetColumns(lpContentsTableWAB,
|
|
(LPSPropTagArray)&ptaColumns,
|
|
0)) {
|
|
DebugTrace("WAB SetColumns(PAB Table) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Restrict the table to MAPI_MAILUSERs
|
|
// If the convenient depth flag was not specified we restrict on
|
|
// PR_DEPTH == 1.
|
|
spvObjectType.ulPropTag = PR_OBJECT_TYPE;
|
|
spvObjectType.Value.l = MAPI_MAILUSER;
|
|
|
|
restrictObjectType.rt = RES_PROPERTY;
|
|
restrictObjectType.res.resProperty.relop = RELOP_EQ;
|
|
restrictObjectType.res.resProperty.ulPropTag = PR_OBJECT_TYPE;
|
|
restrictObjectType.res.resProperty.lpProp = &spvObjectType;
|
|
|
|
if (HR_FAILED(hResult = lpContentsTableWAB->lpVtbl->Restrict(lpContentsTableWAB,
|
|
&restrictObjectType,
|
|
0))) {
|
|
DebugTrace("WAB Restrict (MAPI_MAILUSER) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
SetDialogMessage(hwnd, IDS_STATE_EXPORT_MU);
|
|
|
|
|
|
// Initialize the Progress Bar
|
|
// How many MailUser entries are there?
|
|
ulcEntries = CountRows(lpContentsTableWAB, FALSE);
|
|
|
|
DebugTrace("WAB contains %u MailUser entries\n", ulcEntries);
|
|
|
|
SetDialogProgress(hwnd, ulcEntries, 0);
|
|
exit:
|
|
if (lpWABEID) {
|
|
WABFreeBuffer(lpWABEID);
|
|
}
|
|
|
|
if (lpPABEID) {
|
|
MAPIFreeBuffer(lpPABEID);
|
|
}
|
|
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL)
|
|
{
|
|
NewState(hwnd, STATE_EXPORT_CANCEL);
|
|
}
|
|
else
|
|
{
|
|
// [PaulHi] 1/7/98 Error reporting is hosed
|
|
// Display error message here to the user to ensure they
|
|
// get it.
|
|
{
|
|
TCHAR tszBuffer[MAX_RESOURCE_STRING];
|
|
TCHAR tszBufferTitle[MAX_RESOURCE_STRING];
|
|
|
|
if ( !LoadString(hInst, IDS_STATE_EXPORT_ERROR_NOPAB, tszBuffer, MAX_RESOURCE_STRING-1) )
|
|
{
|
|
Assert(0);
|
|
tszBuffer[0] = '\0';
|
|
}
|
|
|
|
if ( !LoadString(hInst, IDS_APP_TITLE, tszBufferTitle, MAX_RESOURCE_STRING-1) )
|
|
{
|
|
Assert(0);
|
|
tszBufferTitle[0] = '\0';
|
|
}
|
|
MessageBox(hwnd, tszBuffer, tszBufferTitle, MB_ICONEXCLAMATION | MB_OK);
|
|
}
|
|
|
|
NewState(hwnd, STATE_EXPORT_ERROR);
|
|
}
|
|
}
|
|
else if (fError)
|
|
{
|
|
NewState(hwnd, STATE_EXPORT_FINISH); // must be logon error
|
|
}
|
|
else
|
|
{
|
|
NewState(hwnd, STATE_EXPORT_NEXT_MU);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportNextMU
|
|
|
|
Purpose : Migrate the next MailUser object
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : QueryRows on the global WAB contents table
|
|
if there was a row
|
|
Migrate the entry to the PAB
|
|
Re-post STATE_EXPORT_NEXT_MU
|
|
else
|
|
Post STATE_EXPORT_DL
|
|
|
|
***************************************************************************/
|
|
void StateExportNextMU(HWND hwnd) {
|
|
ULONG cRows = 0;
|
|
HRESULT hResult;
|
|
LPSRowSet lpRow = NULL;
|
|
|
|
|
|
DebugTrace(">>> STATE_EXPORT_NEXT_MU\n");
|
|
Assert(lpContentsTableWAB);
|
|
|
|
// Get the next WAB entry
|
|
if (hResult = lpContentsTableWAB->lpVtbl->QueryRows(lpContentsTableWAB,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow) {
|
|
if (cRows = lpRow->cRows) { // Yes, single '='
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
if (cRows = lpRow->cRows) { // yes, single '='
|
|
hResult = ExportEntry(hwnd,
|
|
lpAdrBookWAB,
|
|
lpContainerMAPI,
|
|
lpCreateEIDsMAPI,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].Value.l,
|
|
(LPENTRYID)lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.lpb,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.cb,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
FALSE);
|
|
// Update Progress Bar
|
|
// ignore errors!
|
|
|
|
SetDialogProgress(hwnd, ulcEntries, ++ulcDone);
|
|
|
|
if (hResult) {
|
|
if (HandleExportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_DISPLAY_NAME].Value.LPSZ,
|
|
PropStringOrNULL(&lpRow->aRow[0].lpProps[iptaColumnsPR_EMAIL_ADDRESS]),
|
|
lpExportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
} // else, drop out of loop, we're done.
|
|
}
|
|
WABFreeProws(lpRow);
|
|
}
|
|
|
|
exit:
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult)) {
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL) {
|
|
NewState(hwnd, STATE_EXPORT_CANCEL);
|
|
} else {
|
|
NewState(hwnd, STATE_EXPORT_ERROR);
|
|
}
|
|
} else {
|
|
if (cRows) {
|
|
NewState(hwnd, STATE_EXPORT_NEXT_MU);
|
|
} else {
|
|
NewState(hwnd, STATE_EXPORT_DL);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportDL
|
|
|
|
Purpose : Start migration of DISTLIST objects
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Set a new restriction on the contents table, selecting
|
|
DISTLIST objects only.
|
|
Post STATE_EXPORT_NEXT_DL
|
|
|
|
***************************************************************************/
|
|
void StateExportDL(HWND hwnd) {
|
|
HRESULT hResult;
|
|
SRestriction restrictObjectType;
|
|
SPropValue spvObjectType;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
|
|
|
|
DebugTrace(">>> STATE_EXPORT_DL\n");
|
|
|
|
// Restrict the table to MAPI_MAILUSERs
|
|
// If the convenient depth flag was not specified we restrict on
|
|
// PR_DEPTH == 1.
|
|
spvObjectType.ulPropTag = PR_OBJECT_TYPE;
|
|
spvObjectType.Value.l = MAPI_DISTLIST;
|
|
|
|
restrictObjectType.rt = RES_PROPERTY;
|
|
restrictObjectType.res.resProperty.relop = RELOP_EQ;
|
|
restrictObjectType.res.resProperty.ulPropTag = PR_OBJECT_TYPE;
|
|
restrictObjectType.res.resProperty.lpProp = &spvObjectType;
|
|
|
|
if (HR_FAILED(hResult = lpContentsTableWAB->lpVtbl->Restrict(lpContentsTableWAB,
|
|
&restrictObjectType,
|
|
0))) {
|
|
DebugTrace("WAB Restrict (MAPI_DISTLIST) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
// Restrict resets the current position to the beginning of the table, by definition.
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_EXPORT_DL);
|
|
|
|
// Initialize the Progress Bar
|
|
// How many entries are there?
|
|
|
|
ulcEntries = CountRows(lpContentsTableWAB, FALSE);
|
|
|
|
DebugTrace("WAB contains %u Distribution List entries\n", ulcEntries);
|
|
if (ulcEntries) {
|
|
SetDialogProgress(hwnd, ulcEntries, 0);
|
|
}
|
|
exit:
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult)) {
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL) {
|
|
NewState(hwnd, STATE_EXPORT_CANCEL);
|
|
} else {
|
|
NewState(hwnd, STATE_EXPORT_ERROR);
|
|
}
|
|
} else {
|
|
NewState(hwnd, STATE_EXPORT_NEXT_DL);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportNextDL
|
|
|
|
Purpose : Migrate the next DISTLIST object
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : QueryRows on the global WAB contents table
|
|
if there was a row
|
|
Migrate the DistList to the PAB
|
|
Re-post STATE_EXPORT_NEXT_DL
|
|
else
|
|
Post STATE_EXPORT_FINISH
|
|
|
|
***************************************************************************/
|
|
void StateExportNextDL(HWND hwnd) {
|
|
ULONG cRows = 0;
|
|
HRESULT hResult;
|
|
LPSRowSet lpRow = NULL;
|
|
|
|
|
|
DebugTrace(">>> STATE_EXPORT_NEXT_DL\n");
|
|
|
|
// Get the next WAB entry
|
|
if (hResult = lpContentsTableWAB->lpVtbl->QueryRows(lpContentsTableWAB,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow) {
|
|
if (cRows = lpRow->cRows) { // Yes, single '='
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
if (cRows = lpRow->cRows) { // yes, single '='
|
|
hResult = ExportEntry(hwnd,
|
|
lpAdrBookWAB,
|
|
lpContainerMAPI,
|
|
lpCreateEIDsMAPI,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].Value.l,
|
|
(LPENTRYID)lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.lpb,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.cb,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
FALSE);
|
|
|
|
// Update Progress Bar
|
|
SetDialogProgress(hwnd, ulcEntries, ++ulcDone);
|
|
|
|
if (hResult) {
|
|
if (HandleExportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_DISPLAY_NAME].Value.LPSZ,
|
|
PropStringOrNULL(&lpRow->aRow[0].lpProps[iptaColumnsPR_EMAIL_ADDRESS]),
|
|
lpExportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
} // else, drop out of loop, we're done.
|
|
}
|
|
WABFreeProws(lpRow);
|
|
}
|
|
|
|
exit:
|
|
// On error, set the state to STATE_ERROR
|
|
if (HR_FAILED(hResult)) {
|
|
if (GetScode(hResult) == MAPI_E_USER_CANCEL) {
|
|
NewState(hwnd, STATE_EXPORT_CANCEL);
|
|
} else {
|
|
NewState(hwnd, STATE_EXPORT_ERROR);
|
|
}
|
|
} else {
|
|
if (cRows) {
|
|
NewState(hwnd, STATE_EXPORT_NEXT_DL);
|
|
} else {
|
|
// Update Progress Bar to indicate completion
|
|
SetDialogProgress(hwnd, ulcEntries, ulcEntries);
|
|
NewState(hwnd, STATE_EXPORT_FINISH);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportFinish
|
|
|
|
Purpose : Clean up after the migration process
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Clean up the global MAPI objects and buffers
|
|
Clean up the global WAB objects and buffers.
|
|
Re-enable the Export button on the UI.
|
|
|
|
***************************************************************************/
|
|
void StateExportFinish(HWND hwnd) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
TCHAR szBufferTitle[MAX_RESOURCE_STRING + 1];
|
|
|
|
|
|
DebugTrace(">>> STATE_EXPORT_FINISH\n");
|
|
|
|
//
|
|
// Cleanup MAPI
|
|
//
|
|
if (lpContainerMAPI) {
|
|
lpContainerMAPI->lpVtbl->Release(lpContainerMAPI);
|
|
lpContainerMAPI = NULL;
|
|
}
|
|
|
|
if (lpAdrBookMAPI) {
|
|
lpAdrBookMAPI->lpVtbl->Release(lpAdrBookMAPI);
|
|
lpAdrBookMAPI = NULL;
|
|
}
|
|
if(lpMAPISession){
|
|
lpMAPISession->lpVtbl->Logoff(lpMAPISession, (ULONG_PTR)(void *)hwnd,
|
|
MAPI_LOGOFF_UI,
|
|
0);
|
|
|
|
lpMAPISession->lpVtbl->Release(lpMAPISession);
|
|
lpMAPISession = NULL;
|
|
}
|
|
|
|
//
|
|
// Cleanup the WAB
|
|
//
|
|
if (lpContentsTableWAB) {
|
|
lpContentsTableWAB->lpVtbl->Release(lpContentsTableWAB);
|
|
lpContentsTableWAB = NULL;
|
|
}
|
|
|
|
if (lpCreateEIDsWAB) {
|
|
WABFreeBuffer(lpCreateEIDsWAB);
|
|
lpCreateEIDsWAB = NULL;
|
|
}
|
|
|
|
if (lpContainerWAB) {
|
|
lpContainerWAB->lpVtbl->Release(lpContainerWAB);
|
|
lpContainerWAB = NULL;
|
|
}
|
|
|
|
#ifdef OLD_STUFF // Don't release AdrBookWAB or WABObject
|
|
if (lpAdrBookWAB) {
|
|
lpAdrBookWAB->lpVtbl->Release(lpAdrBookWAB);
|
|
lpAdrBookWAB = NULL;
|
|
}
|
|
|
|
if (lpWABObject) {
|
|
lpWABObject->lpVtbl->Release(lpWABObject);
|
|
lpWABObject = NULL;
|
|
}
|
|
#endif // OLD_STUFF
|
|
|
|
// Cleanup the cache
|
|
FreeSeenList();
|
|
|
|
if (! fError) { // Leave error state displayed
|
|
if (LoadString(hInst, IDS_STATE_EXPORT_COMPLETE, szBuffer, ARRAYSIZE(szBuffer))) {
|
|
DebugTrace("Status Message: %s\n", szBuffer);
|
|
SetDlgItemText(hwnd, IDC_Message, szBuffer);
|
|
|
|
if (! LoadString(hInst, IDS_APP_TITLE, szBufferTitle, ARRAYSIZE(szBufferTitle))) {
|
|
StrCpyN(szBufferTitle, "", ARRAYSIZE(szBufferTitle));
|
|
}
|
|
|
|
#ifdef OLD_STUFF
|
|
// Display a dialog telling user it's over
|
|
MessageBox(hwnd, szBuffer,
|
|
szBufferTitle, MB_ICONINFORMATION | MB_OK);
|
|
#endif // OLD_STUFF
|
|
}
|
|
#ifdef OLD_STUFF
|
|
ShowWindow(GetDlgItem(hwnd, IDC_Progress), SW_HIDE);
|
|
#endif // OLD_STUFF
|
|
}
|
|
fError = FALSE;
|
|
|
|
// Re-enable the Export button here.
|
|
EnableWindow(GetDlgItem(hwnd, IDC_Export), TRUE);
|
|
// Change the Cancel button to Close
|
|
if (LoadString(hInst, IDS_BUTTON_CLOSE, szBuffer, ARRAYSIZE(szBuffer))) {
|
|
SetDlgItemText(hwnd, IDCANCEL, szBuffer);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportError
|
|
|
|
Purpose : Report fatal error and cleanup.
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Report error and post STATE_EXPORT_FINISH.
|
|
|
|
***************************************************************************/
|
|
void StateExportError(HWND hwnd) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
// Set some global flag and set state to finish
|
|
|
|
DebugTrace(">>> STATE_EXPORT_ERROR\n");
|
|
fError = TRUE;
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_EXPORT_ERROR);
|
|
|
|
NewState(hwnd, STATE_EXPORT_FINISH);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : StateExportCancel
|
|
|
|
Purpose : Report cancel error and cleanup.
|
|
|
|
Parameters: hwnd = window handle of Export Dialog
|
|
|
|
Returns : none
|
|
|
|
Comment : Report error and post STATE_EXPORT_FINISH.
|
|
|
|
***************************************************************************/
|
|
void StateExportCancel(HWND hwnd) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
// Set some global flag and set state to finish
|
|
|
|
DebugTrace(">>> STATE_EXPORT_CANCEL\n");
|
|
fError = TRUE;
|
|
|
|
SetDialogMessage(hwnd, IDS_STATE_EXPORT_CANCEL);
|
|
|
|
NewState(hwnd, STATE_EXPORT_FINISH);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : HrFilterExportMailUserProps
|
|
|
|
Purpose : Filters out undesirable properties from the property array.
|
|
Converts known email address types to SMTP.
|
|
Moves FAX address to PR_BUSINESS_FAX_NUMBER.
|
|
|
|
Parameters: lpcProps -> IN: Input number of properties
|
|
OUT: Output number of properties
|
|
lppProps -> IN: Input property array (MAPI allocation)
|
|
OUT: Output property array (WAB allocation)
|
|
lpObjectWAB -> WAB object (used to get extra props)
|
|
lpfDL -> flag to set FALSE if we change a DL to a MAILUSER
|
|
(ie, for an EXchange DL)
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : Setting the property tag in the array to PR_NULL effectively
|
|
nulls this property out. We can re-use these in the second
|
|
pass.
|
|
|
|
Caller should use MAPIFreeBuffer to free *lppProps.
|
|
This routine will free the input value of *lppProps.
|
|
|
|
WARNING: This routine will add dummy properties to the
|
|
input WAB object, so don't go doing SaveChanges on it!
|
|
|
|
***************************************************************************/
|
|
#define MAX_ADD_PROPS 2
|
|
#define PR_DUMMY_1 PROP_TAG(PT_LONG, 0xF000)
|
|
#define PR_DUMMY_2 PROP_TAG(PT_LONG, 0xF001)
|
|
|
|
HRESULT HrFilterExportMailUserProps(LPULONG lpcProps, LPSPropValue * lppProps,
|
|
LPMAPIPROP lpObjectWAB, LPBOOL lpfDL) {
|
|
HRESULT hResult = hrSuccess;
|
|
ULONG i;
|
|
LPSPropValue lpPropsWAB, lpPropsMAPI = NULL;
|
|
ULONG cbProps;
|
|
SCODE sc;
|
|
ULONG cProps;
|
|
ULONG iPR_ADDRTYPE = NOT_FOUND;
|
|
ULONG iPR_EMAIL_ADDRESS = NOT_FOUND;
|
|
ULONG iPR_PRIMARY_FAX_NUMBER = NOT_FOUND;
|
|
ULONG iPR_BUSINESS_FAX_NUMBER = NOT_FOUND;
|
|
ULONG iPR_MSNINET_DOMAIN = NOT_FOUND;
|
|
ULONG iPR_MSNINET_ADDRESS = NOT_FOUND;
|
|
ULONG iPR_DISPLAY_NAME = NOT_FOUND;
|
|
ULONG iPR_OBJECT_TYPE = NOT_FOUND;
|
|
ULONG iPR_SEND_RICH_INFO = NOT_FOUND;
|
|
LPSBinary lpEntryID = NULL;
|
|
LPTSTR lpTemp;
|
|
BOOL fBadAddress = FALSE;
|
|
SPropValue rgPropsDummy[MAX_ADD_PROPS] = {
|
|
PR_DUMMY_1, 0, 1,
|
|
PR_DUMMY_2, 0, 2,
|
|
};
|
|
|
|
|
|
// Set extra bogus props on the object in case we need to add more props
|
|
// to the array later. These will be PR_NULL'ed out by the first pass.
|
|
if (HR_FAILED(hResult = lpObjectWAB->lpVtbl->SetProps(lpObjectWAB,
|
|
MAX_ADD_PROPS,
|
|
rgPropsDummy,
|
|
NULL))) {
|
|
DebugTrace("HrFilterExportMailUserProps:SetProps dummy props -> %x\n", GetScode(hResult));
|
|
// ignore the error
|
|
}
|
|
|
|
|
|
// Get the properties from this entry
|
|
if (HR_FAILED(hResult = lpObjectWAB->lpVtbl->GetProps(lpObjectWAB,
|
|
NULL,
|
|
0,
|
|
&cProps,
|
|
&lpPropsWAB))) {
|
|
DebugTrace("HrFilterExportMailUserProps:GetProps(WAB) -> %x\n", GetScode(hResult));
|
|
return(hResult);
|
|
}
|
|
|
|
// WABDebugProperties(lpPropsWAB, *lpcProps, "MailUser BEFORE");
|
|
|
|
|
|
// First pass: Remove the junk
|
|
for (i = 0; i < cProps; i++) {
|
|
// Error value
|
|
if (PROP_ERROR(lpPropsWAB[i])) {
|
|
lpPropsWAB[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
|
|
// Named property
|
|
if (PROP_ID(lpPropsWAB[i].ulPropTag) >= MIN_NAMED_PROPID) {
|
|
lpPropsWAB[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
|
|
// Object property
|
|
if (PROP_TYPE(lpPropsWAB[i].ulPropTag) == PT_OBJECT) {
|
|
lpPropsWAB[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
switch (lpPropsWAB[i].ulPropTag) {
|
|
case PR_ENTRYID:
|
|
lpEntryID = &lpPropsWAB[i].Value.bin;
|
|
// fall through
|
|
|
|
case PR_PRIMARY_CAPABILITY:
|
|
case PR_TEMPLATEID:
|
|
case PR_SEARCH_KEY:
|
|
case PR_INITIAL_DETAILS_PANE:
|
|
case PR_RECORD_KEY:
|
|
case PR_MAPPING_SIGNATURE:
|
|
lpPropsWAB[i].ulPropTag = PR_NULL;
|
|
break;
|
|
|
|
case PR_COMMENT:
|
|
// Don't save PR_COMMENT if it is empty
|
|
if (lstrlen(lpPropsWAB[i].Value.LPSZ) == 0) {
|
|
lpPropsWAB[i].ulPropTag = PR_NULL;
|
|
}
|
|
break;
|
|
|
|
// Keep track of the position of these for later
|
|
case PR_ADDRTYPE:
|
|
iPR_ADDRTYPE = i;
|
|
break;
|
|
case PR_OBJECT_TYPE:
|
|
iPR_OBJECT_TYPE = i;
|
|
break;
|
|
case PR_EMAIL_ADDRESS:
|
|
iPR_EMAIL_ADDRESS = i;
|
|
break;
|
|
case PR_PRIMARY_FAX_NUMBER:
|
|
iPR_PRIMARY_FAX_NUMBER = i;
|
|
break;
|
|
case PR_BUSINESS_FAX_NUMBER:
|
|
iPR_BUSINESS_FAX_NUMBER = i;
|
|
break;
|
|
case PR_MSNINET_ADDRESS:
|
|
iPR_MSNINET_ADDRESS = i;
|
|
break;
|
|
case PR_MSNINET_DOMAIN:
|
|
iPR_MSNINET_DOMAIN = i;
|
|
break;
|
|
case PR_DISPLAY_NAME:
|
|
iPR_DISPLAY_NAME = i;
|
|
break;
|
|
case PR_SEND_RICH_INFO:
|
|
iPR_SEND_RICH_INFO = i;
|
|
break;
|
|
}
|
|
|
|
// Put this after the switch since we do want to track a few props which fall in
|
|
// the 0x6000 range but don't want to transfer them to the wab.
|
|
if (PROP_ID(lpPropsWAB[i].ulPropTag) >= MAX_SCHEMA_PROPID) {
|
|
lpPropsWAB[i].ulPropTag = PR_NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// Second pass: Fix up the addresses
|
|
if (iPR_ADDRTYPE != NOT_FOUND) {
|
|
if (! lstrcmpi(lpPropsWAB[iPR_ADDRTYPE].Value.LPSZ, szSMTP)) {
|
|
DebugTrace("SMTP address for %s\n", lpPropsWAB[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
} else if (! lstrcmpi(lpPropsWAB[iPR_ADDRTYPE].Value.LPSZ, szMAPIPDL)) {
|
|
DebugTrace("MAPIPDL %s\n", lpPropsWAB[iPR_DISPLAY_NAME].Value.LPSZ);
|
|
// Distribution list, ignore it.
|
|
} else {
|
|
WABDebugProperties(lpPropsWAB, cProps, "Unknown address type");
|
|
DebugTrace("Found unknown PR_ADDRTYPE: %s\n", lpPropsWAB[iPR_ADDRTYPE].Value.LPSZ);
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
|
|
// PR_BUSINESS_FAX_NUMBER?
|
|
// The PAB puts the Fax number in PR_PRIMARY_FAX_NUMBER, but the WAB UI splits it
|
|
// into PR_BUSINESS_FAX_NUMBER and PR_HOME_FAX_NUMBER. We always map business to
|
|
// Primary fax number and ignore home fax number.
|
|
if ((iPR_BUSINESS_FAX_NUMBER != NOT_FOUND) && (iPR_PRIMARY_FAX_NUMBER == NOT_FOUND)) {
|
|
// We need to also have a PR_PRIMARY_FAX_NUMBER
|
|
// Find the next PR_NULL spot.
|
|
iPR_PRIMARY_FAX_NUMBER = iPR_BUSINESS_FAX_NUMBER; // overwrite this one if there isn't
|
|
// an available slot in the prop array.
|
|
for (i = 0; i < cProps; i++) {
|
|
if (lpPropsWAB[i].ulPropTag == PR_NULL) {
|
|
iPR_PRIMARY_FAX_NUMBER = i;
|
|
lpPropsWAB[iPR_PRIMARY_FAX_NUMBER].Value.LPSZ =
|
|
lpPropsWAB[iPR_BUSINESS_FAX_NUMBER].Value.LPSZ;
|
|
break;
|
|
}
|
|
}
|
|
|
|
lpPropsWAB[iPR_PRIMARY_FAX_NUMBER].ulPropTag = PR_PRIMARY_FAX_NUMBER;
|
|
}
|
|
|
|
// If there is no PR_SEND_RICH_INFO, make one and set it FALSE
|
|
if (iPR_SEND_RICH_INFO == NOT_FOUND) {
|
|
// Find the next PR_NULL and put it there.
|
|
for (i = 0; i < cProps; i++) {
|
|
if (lpPropsWAB[i].ulPropTag == PR_NULL) {
|
|
iPR_SEND_RICH_INFO = i;
|
|
lpPropsWAB[iPR_SEND_RICH_INFO].Value.b = FALSE;
|
|
lpPropsWAB[iPR_SEND_RICH_INFO].ulPropTag = PR_SEND_RICH_INFO;
|
|
break;
|
|
}
|
|
}
|
|
Assert(iPR_SEND_RICH_INFO != NOT_FOUND);
|
|
}
|
|
|
|
// Get rid of PR_NULL props
|
|
for (i = 0; i < cProps; i++) {
|
|
if (lpPropsWAB[i].ulPropTag == PR_NULL) {
|
|
// Slide the props down.
|
|
if (i + 1 < cProps) { // Are there any higher props to copy?
|
|
CopyMemory(&lpPropsWAB[i], &lpPropsWAB[i + 1], ((cProps - i) - 1) * sizeof(lpPropsWAB[i]));
|
|
}
|
|
// decrement count
|
|
cProps--;
|
|
i--; // You overwrote the current propval. Look at it again.
|
|
}
|
|
}
|
|
|
|
// Reallocate as MAPI memory.
|
|
|
|
if (sc = ScCountProps(cProps, lpPropsWAB, &cbProps)) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("ScCountProps -> %x\n", sc);
|
|
goto exit;
|
|
}
|
|
|
|
if (sc = MAPIAllocateBuffer(cbProps, &lpPropsMAPI)) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("WABAllocateBuffer -> %x\n", sc);
|
|
goto exit;
|
|
}
|
|
|
|
if (sc = ScCopyProps(cProps,
|
|
lpPropsWAB,
|
|
lpPropsMAPI,
|
|
NULL)) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("ScCopyProps -> %x\n", sc);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
if (lpPropsWAB) {
|
|
WABFreeBuffer(lpPropsWAB);
|
|
}
|
|
|
|
if (HR_FAILED(hResult)) {
|
|
if (lpPropsMAPI) {
|
|
MAPIFreeBuffer(lpPropsMAPI);
|
|
lpPropsMAPI = NULL;
|
|
}
|
|
cProps = 0;
|
|
} else if (fBadAddress) {
|
|
hResult = ResultFromScode(WAB_W_BAD_EMAIL);
|
|
}
|
|
|
|
*lppProps = lpPropsMAPI;
|
|
*lpcProps = cProps;
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : HandleExportError
|
|
|
|
Purpose : Decides if a dialog needs to be displayed to
|
|
indicate the failure and does so.
|
|
|
|
Parameters: hwnd = main dialog window
|
|
ids = String ID (optional: calculated from hResult if 0)
|
|
hResult = Result of action
|
|
lpDisplayName = display name of object that failed
|
|
lpEmailAddress = email address of object that failed (or NULL)
|
|
|
|
Returns : TRUE if user requests ABORT.
|
|
|
|
Comment : Abort is not yet implemented in the dialog, but if you
|
|
ever want to, just make this routine return TRUE;
|
|
|
|
***************************************************************************/
|
|
BOOL HandleExportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress, LPWAB_EXPORT_OPTIONS lpExportOptions) {
|
|
BOOL fAbort = FALSE;
|
|
ERROR_INFO EI;
|
|
|
|
if ((ids || hResult) && ! lpExportOptions->fNoErrors) {
|
|
if (ids == 0) {
|
|
switch (GetScode(hResult)) {
|
|
case WAB_W_BAD_EMAIL:
|
|
ids = lpEmailAddress ? IDS_ERROR_EMAIL_ADDRESS_2 : IDS_ERROR_EMAIL_ADDRESS_1;
|
|
break;
|
|
|
|
case MAPI_E_NO_SUPPORT:
|
|
// Propbably failed to open contents on a distribution list
|
|
ids = IDS_ERROR_NO_SUPPORT;
|
|
break;
|
|
|
|
case MAPI_E_USER_CANCEL:
|
|
return(TRUE);
|
|
|
|
default:
|
|
if (HR_FAILED(hResult)) {
|
|
DebugTrace("Error Box for Hresult: 0x%08x\n", GetScode(hResult));
|
|
Assert(FALSE); // want to know about it.
|
|
ids = IDS_ERROR_GENERAL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
EI.lpszDisplayName = lpDisplayName;
|
|
EI.lpszEmailAddress = lpEmailAddress;
|
|
EI.ErrorResult = ERROR_OK;
|
|
EI.ids = ids;
|
|
EI.fExport = TRUE;
|
|
EI.lpImportOptions = lpExportOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ErrorExport),
|
|
hwnd,
|
|
ErrorDialogProc,
|
|
(LPARAM)&EI);
|
|
|
|
fAbort = EI.ErrorResult == ERROR_ABORT;
|
|
}
|
|
|
|
return(fAbort);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : AddEntryToExportList
|
|
|
|
Purpose : Checks this entry against our "seen" list and adds it.
|
|
|
|
Parameters: cbEID = size of lpEID
|
|
lpEID -> EntryID of entry
|
|
lplIndex -> returned list index (or -1 on error)
|
|
|
|
Returns : TRUE if entry already exists
|
|
|
|
Comment : Caller must mark the WAB entry!
|
|
|
|
***************************************************************************/
|
|
#define GROW_SIZE 10
|
|
BOOL AddEntryToExportList(ULONG cbEID, LPENTRYID lpEID, LPLONG lplIndex) {
|
|
ULONG i;
|
|
LPENTRY_SEEN lpEntrySeen;
|
|
|
|
if (cbEID && lpEID) {
|
|
for (i = 0; i < ulEntriesSeen; i++) {
|
|
if (cbEID == lpEntriesSeen[i].sbinPAB.cb && (! memcmp(lpEID, lpEntriesSeen[i].sbinPAB.lpb, cbEID))) {
|
|
// This one's in the list
|
|
*lplIndex = i;
|
|
// If cb 0, we must have recursed and are replacing, so this one is not a dup.
|
|
return(lpEntriesSeen[i].sbinWAB.cb != 0);
|
|
}
|
|
}
|
|
|
|
// Add to the end of the list
|
|
if (++ulEntriesSeen > ulMaxEntries) {
|
|
// Grow the array.
|
|
|
|
ulMaxEntries += GROW_SIZE;
|
|
|
|
if (lpEntriesSeen) {
|
|
if (! (lpEntrySeen = LocalReAlloc(lpEntriesSeen, ulMaxEntries * sizeof(ENTRY_SEEN), LMEM_MOVEABLE | LMEM_ZEROINIT))) {
|
|
DebugTrace("LocalReAlloc(%u) -> %u\n", ulMaxEntries * sizeof(ENTRY_SEEN), GetLastError());
|
|
goto error;
|
|
}
|
|
lpEntriesSeen = lpEntrySeen;
|
|
} else {
|
|
if (! (lpEntriesSeen = LocalAlloc(LPTR, ulMaxEntries * sizeof(ENTRY_SEEN)))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", ulMaxEntries * sizeof(ENTRY_SEEN), GetLastError());
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
lpEntrySeen = &lpEntriesSeen[ulEntriesSeen - 1];
|
|
|
|
// Allocate space for data
|
|
lpEntrySeen->sbinPAB.cb = cbEID;
|
|
if (! (lpEntrySeen->sbinPAB.lpb = LocalAlloc(LPTR, cbEID))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cbEID, GetLastError());
|
|
goto error;
|
|
}
|
|
|
|
// Mark as unknown WAB entry
|
|
lpEntrySeen->sbinWAB.cb = 0;
|
|
lpEntrySeen->sbinWAB.lpb = 0;
|
|
|
|
// Copy in the data
|
|
CopyMemory(lpEntrySeen->sbinPAB.lpb, lpEID, cbEID);
|
|
*lplIndex = i;
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
error:
|
|
// undo the damage...
|
|
--ulEntriesSeen;
|
|
ulMaxEntries -= GROW_SIZE;
|
|
*lplIndex = -1; // error
|
|
if (! lpEntriesSeen) {
|
|
ulEntriesSeen = 0; // pointer is null now, back to square one.
|
|
ulMaxEntries = 0;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : MarkPABEntryInList
|
|
|
|
Purpose : Marks the PAB entry fields in the list node
|
|
|
|
Parameters: cbEID = size of lpEID
|
|
lpEID -> EntryID of entry
|
|
lIndex = list index (or -1 on error)
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
void MarkPABEntryInList(ULONG cbEID, LPENTRYID lpEID, LONG lIndex) {
|
|
if (lIndex != -1 && cbEID) {
|
|
if (! (lpEntriesSeen[lIndex].sbinWAB.lpb = LocalAlloc(LPTR, cbEID))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cbEID, GetLastError());
|
|
// leave it null
|
|
} else {
|
|
lpEntriesSeen[lIndex].sbinWAB.cb = cbEID;
|
|
|
|
// Copy in the data
|
|
CopyMemory(lpEntriesSeen[lIndex].sbinWAB.lpb, lpEID, cbEID);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Properties to get from the PAB Entry
|
|
//
|
|
enum {
|
|
ifePR_OBJECT_TYPE = 0,
|
|
ifePR_ENTRYID,
|
|
ifePR_DISPLAY_NAME,
|
|
ifePR_EMAIL_ADDRESS,
|
|
ifeMax
|
|
};
|
|
static const SizedSPropTagArray(ifeMax, ptaFind) =
|
|
{
|
|
ifeMax,
|
|
{
|
|
PR_OBJECT_TYPE,
|
|
PR_ENTRYID,
|
|
PR_DISPLAY_NAME,
|
|
PR_EMAIL_ADDRESS
|
|
}
|
|
};
|
|
/***************************************************************************
|
|
|
|
Name : FindPABEntry
|
|
|
|
Purpose : Finds the named entry in the PAB
|
|
|
|
Parameters: lpContainerPAB -> MAPI PAB container
|
|
ulObjectType = {MAPI_MAILUSER, MAPI_DISTLIST}
|
|
lpDisplayName = name of entry
|
|
lpEmailAddress = email address or NULL if none
|
|
lppEIDMAPI -> returned MAPI ENTRYID: Caller must MAPIFreeBuffer.
|
|
lpcbEIDMAPI -> returned size of lppEIDMAPI
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : At this point, we expect to find a match since
|
|
SaveChanges said we had a duplicate.
|
|
|
|
***************************************************************************/
|
|
HRESULT FindPABEntry(LPABCONT lpContainerPAB,
|
|
ULONG ulObjectType,
|
|
LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress,
|
|
LPULONG lpcbEIDDup,
|
|
LPENTRYID * lppEIDDup) {
|
|
HRESULT hResult = hrSuccess;
|
|
SCODE sc;
|
|
SRestriction resAnd[3]; // 0 = object type, 1 = displayname, 2 = emailaddress
|
|
SRestriction resFind;
|
|
SPropValue spvObjectType, spvDisplayName, spvEmailAddress;
|
|
LPSRowSet lpRow = NULL;
|
|
LPMAPITABLE lpTable = NULL;
|
|
ULONG rgFlagList[2];
|
|
LPFlagList lpFlagList = (LPFlagList)rgFlagList;
|
|
LPADRLIST lpAdrListMAPI = NULL;
|
|
LPSBinary lpsbEntryID;
|
|
ULONG i;
|
|
|
|
|
|
// init return values
|
|
*lppEIDDup = NULL;
|
|
*lpcbEIDDup = 0;
|
|
|
|
|
|
// find the existing PAB entry.
|
|
// Setup for ResolveNames on the PAB container.
|
|
if (sc = MAPIAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY), &lpAdrListMAPI)) {
|
|
DebugTrace("MAPI Allocation(ADRLIST) failed -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto restrict;
|
|
}
|
|
lpAdrListMAPI->cEntries = 1;
|
|
lpAdrListMAPI->aEntries[0].ulReserved1 = 0;
|
|
lpAdrListMAPI->aEntries[0].cValues = 1;
|
|
|
|
if (sc = MAPIAllocateBuffer(sizeof(SPropValue), &lpAdrListMAPI->aEntries[0].rgPropVals)) {
|
|
DebugTrace("MAPI Allocation(ADRENTRY propval) failed -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto restrict;
|
|
}
|
|
|
|
lpFlagList->cFlags = 1;
|
|
|
|
for (i = 0; i <= 1; i++) {
|
|
switch (i) {
|
|
case 0: // pass 0
|
|
lpAdrListMAPI->aEntries[0].rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
|
|
lpAdrListMAPI->aEntries[0].rgPropVals[0].Value.LPSZ = lpDisplayName;
|
|
break;
|
|
case 1:
|
|
if (lpEmailAddress) {
|
|
lpAdrListMAPI->aEntries[0].rgPropVals[0].ulPropTag = PR_EMAIL_ADDRESS;
|
|
lpAdrListMAPI->aEntries[0].rgPropVals[0].Value.LPSZ = lpEmailAddress;
|
|
} else {
|
|
continue; // no email address, don't bother with second pass
|
|
}
|
|
break;
|
|
default:
|
|
Assert(FALSE);
|
|
}
|
|
lpFlagList->ulFlag[0] = MAPI_UNRESOLVED;
|
|
|
|
if (HR_FAILED(hResult = lpContainerPAB->lpVtbl->ResolveNames(lpContainerPAB,
|
|
NULL, // tag set
|
|
0, // ulFlags
|
|
lpAdrListMAPI,
|
|
lpFlagList))) {
|
|
DebugTrace("MAPI ResolveNames -> %x\n", GetScode(hResult));
|
|
continue;
|
|
}
|
|
|
|
switch (lpFlagList->ulFlag[0]) {
|
|
case MAPI_UNRESOLVED:
|
|
DebugTrace("WAB ResolveNames didn't find the entry %s\n", lpDisplayName);
|
|
continue;
|
|
case MAPI_AMBIGUOUS:
|
|
DebugTrace("WAB ResolveNames find ambiguous entry %s\n", lpDisplayName);
|
|
continue;
|
|
case MAPI_RESOLVED:
|
|
i = 2; // Found it, exit the loop
|
|
}
|
|
}
|
|
|
|
if (lpFlagList->ulFlag[0] == MAPI_RESOLVED) {
|
|
// Found one, find its PR_ENTRYID
|
|
if (! (lpsbEntryID = FindAdrEntryID(lpAdrListMAPI, 0))) {
|
|
DebugTrace("MAPI ResolveNames didn't give us an EntryID\n");
|
|
Assert(lpsbEntryID);
|
|
goto restrict;
|
|
}
|
|
|
|
*lpcbEIDDup = lpsbEntryID->cb;
|
|
if (FAILED(sc = MAPIAllocateBuffer(*lpcbEIDDup, lppEIDDup))) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("FindPABEntry couldn't allocate duplicate entryid %x\n", sc);
|
|
goto exit;
|
|
}
|
|
memcpy(*lppEIDDup, lpsbEntryID->lpb, *lpcbEIDDup);
|
|
}
|
|
|
|
|
|
restrict:
|
|
if (! *lppEIDDup) {
|
|
//
|
|
// Last ditch effort... use a table restriction to try to find this entry.
|
|
//
|
|
|
|
// Get the contents table
|
|
if (HR_FAILED(hResult = lpContainerPAB->lpVtbl->GetContentsTable(lpContainerPAB,
|
|
0, // ulFlags
|
|
&lpTable))) {
|
|
DebugTrace("PAB GetContentsTable -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the columns
|
|
if (HR_FAILED(hResult = lpTable->lpVtbl->SetColumns(lpTable,
|
|
(LPSPropTagArray)&ptaFind,
|
|
0))) {
|
|
DebugTrace("PAB SetColumns-> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Restrict to the object we care about
|
|
resAnd[0].rt = RES_PROPERTY; // Restriction type Property
|
|
resAnd[0].res.resProperty.relop = RELOP_EQ;
|
|
resAnd[0].res.resProperty.ulPropTag = PR_OBJECT_TYPE;
|
|
resAnd[0].res.resProperty.lpProp = &spvObjectType;
|
|
spvObjectType.ulPropTag = PR_OBJECT_TYPE;
|
|
spvObjectType.Value.ul = ulObjectType;
|
|
|
|
// Restrict to get correct display name
|
|
resAnd[1].rt = RES_PROPERTY; // Restriction type Property
|
|
resAnd[1].res.resProperty.relop = RELOP_EQ;
|
|
resAnd[1].res.resProperty.ulPropTag = PR_DISPLAY_NAME;
|
|
resAnd[1].res.resProperty.lpProp = &spvDisplayName;
|
|
spvDisplayName.ulPropTag = PR_DISPLAY_NAME;
|
|
spvDisplayName.Value.LPSZ = lpDisplayName;
|
|
|
|
if (lpEmailAddress) {
|
|
// Restrict to get correct email address
|
|
resAnd[2].rt = RES_PROPERTY; // Restriction type Property
|
|
resAnd[2].res.resProperty.relop = RELOP_EQ;
|
|
resAnd[2].res.resProperty.ulPropTag = PR_EMAIL_ADDRESS;
|
|
resAnd[2].res.resProperty.lpProp = &spvEmailAddress;
|
|
spvEmailAddress.ulPropTag = PR_EMAIL_ADDRESS;
|
|
spvEmailAddress.Value.LPSZ = lpEmailAddress;
|
|
}
|
|
|
|
resFind.rt = RES_AND;
|
|
resFind.res.resAnd.cRes = lpEmailAddress ? 3 : 2;
|
|
resFind.res.resAnd.lpRes = resAnd;
|
|
|
|
if (HR_FAILED(hResult = lpTable->lpVtbl->Restrict(lpTable,
|
|
&resFind,
|
|
0))) {
|
|
DebugTrace("FindPABEntry: Restrict -> %x", hResult);
|
|
goto exit;
|
|
}
|
|
|
|
if (hResult = lpTable->lpVtbl->QueryRows(lpTable,
|
|
1, // First row only
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("FindPABEntry: QueryRows -> %x\n", GetScode(hResult));
|
|
} else {
|
|
// Found it, copy entryid to new allocation
|
|
if (lpRow->cRows) {
|
|
*lpcbEIDDup = lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.cb;
|
|
if (FAILED(sc = MAPIAllocateBuffer(*lpcbEIDDup, lppEIDDup))) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("FindPABEntry couldn't allocate duplicate entryid %x\n", sc);
|
|
goto exit;
|
|
}
|
|
memcpy(*lppEIDDup, lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.lpb, *lpcbEIDDup);
|
|
} else {
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
// Still not found?!! Maybe the PAB has a different idea of what the Display name is.
|
|
// Search just by email address.
|
|
if (hResult && lpEmailAddress) {
|
|
resAnd[1] = resAnd[2]; // copy the email address res over the display name res.
|
|
resFind.res.resAnd.cRes = 2;
|
|
|
|
if (HR_FAILED(hResult = lpTable->lpVtbl->Restrict(lpTable,
|
|
&resFind,
|
|
0))) {
|
|
DebugTrace("FindPABEntry: Restrict -> %x", hResult);
|
|
goto exit;
|
|
}
|
|
|
|
if (hResult = lpTable->lpVtbl->QueryRows(lpTable,
|
|
1, // First row only
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("FindPABEntry: QueryRows -> %x\n", GetScode(hResult));
|
|
} else {
|
|
// Found it, copy entryid to new allocation
|
|
if (lpRow->cRows) {
|
|
*lpcbEIDDup = lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.cb;
|
|
if (FAILED(sc = MAPIAllocateBuffer(*lpcbEIDDup, lppEIDDup))) {
|
|
hResult = ResultFromScode(sc);
|
|
DebugTrace("FindPABEntry couldn't allocate duplicate entryid %x\n", sc);
|
|
goto exit;
|
|
}
|
|
memcpy(*lppEIDDup, lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.lpb, *lpcbEIDDup);
|
|
} else {
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
DebugTrace("FindPABEntry coudln't find %s %s <%s>\n",
|
|
ulObjectType == MAPI_MAILUSER ? "Mail User" : "Distribution List",
|
|
lpDisplayName,
|
|
lpEmailAddress ? lpEmailAddress : "");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if (lpAdrListMAPI) {
|
|
FreePadrlist(lpAdrListMAPI);
|
|
}
|
|
if (lpRow) {
|
|
FreeProws(lpRow);
|
|
}
|
|
if (lpTable) {
|
|
lpTable->lpVtbl->Release(lpTable);
|
|
}
|
|
if (HR_FAILED(hResult) && *lppEIDDup) {
|
|
MAPIFreeBuffer(*lppEIDDup);
|
|
*lpcbEIDDup = 0;
|
|
*lppEIDDup = NULL;
|
|
}
|
|
if (hResult) {
|
|
DebugTrace("FindPABEntry coudln't find %s %s <%s>\n",
|
|
ulObjectType == MAPI_MAILUSER ? "Mail User" : "Distribution List",
|
|
lpDisplayName,
|
|
lpEmailAddress ? lpEmailAddress : "");
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
// enum for setting the created properties
|
|
enum {
|
|
irnPR_DISPLAY_NAME = 0,
|
|
irnPR_RECIPIENT_TYPE,
|
|
irnPR_ENTRYID,
|
|
irnPR_EMAIL_ADDRESS,
|
|
irnMax
|
|
};
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ExportEntry
|
|
|
|
Purpose : Migrates the entry from the WAB to the PAB
|
|
|
|
Parameters: hwnd = main dialog window
|
|
lpAdrBookWAB -> WAB AdrBook object
|
|
lpContainerMAPI -> MAPI PAB container
|
|
lpCreateEIDsMAPI -> SPropValue of default object creation EIDs
|
|
ulObjectType = {MAPI_MAILUSER, MAPI_DISTLIST}
|
|
lpEID -> ENTYRID of the WAB entry
|
|
cbEID = sizeof lpEID
|
|
lppEIDMAPI -> returned MAPI ENTRYID: Caller must MAPIFreeBuffer.
|
|
May be NULL.
|
|
lpcbEIDMAPI -> returned size of lppEIDMAPI (ignored if lppEIDMAPI
|
|
is NULL.
|
|
fInDL = TRUE if this entry is for creation in a Distribution List
|
|
fForceReplace = TRUE if this entry should replace any duplicate.
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : This routine is a MESS! Should break it up when we get time.
|
|
|
|
***************************************************************************/
|
|
HRESULT ExportEntry(HWND hwnd,
|
|
LPADRBOOK lpAdrBookWAB,
|
|
LPABCONT lpContainerMAPI,
|
|
LPSPropValue lpCreateEIDsMAPI,
|
|
ULONG ulObjectType,
|
|
LPENTRYID lpEID,
|
|
ULONG cbEID,
|
|
LPENTRYID * lppEIDMAPI,
|
|
LPULONG lpcbEIDMAPI,
|
|
BOOL fInDL,
|
|
BOOL fForceReplace) {
|
|
HRESULT hResult = hrSuccess;
|
|
SCODE sc;
|
|
BOOL fDistList = FALSE;
|
|
BOOL fDuplicate = FALSE;
|
|
BOOL fDuplicateEID;
|
|
BOOL fReturnEID = FALSE;
|
|
ULONG ulObjectTypeOpen;
|
|
LPDISTLIST lpDistListMAPI = NULL, lpDistListWAB = NULL;
|
|
LPMAPIPROP lpMailUserMAPI = NULL, lpMailUserWAB = NULL;
|
|
LPSPropValue lpProps = NULL;
|
|
ULONG cProps, cEIDPropMAPI;
|
|
LPMAPITABLE lpDLTableWAB = NULL;
|
|
ULONG cRows;
|
|
LPSRowSet lpRow = NULL;
|
|
LPENTRYID lpeidDLMAPI = NULL;
|
|
ULONG cbeidDLMAPI;
|
|
LPSPropValue lpEIDPropMAPI = NULL;
|
|
LPMAPIPROP lpEntryMAPI = NULL;
|
|
ULONG ulCreateFlags;
|
|
REPLACE_INFO RI;
|
|
LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
|
|
static TCHAR szBufferDLMessage[MAX_RESOURCE_STRING + 1] = "";
|
|
LPTSTR lpszMessage;
|
|
LONG lListIndex = -1;
|
|
LPENTRYID lpEIDNew = NULL;
|
|
DWORD cbEIDNew = 0;
|
|
LPIID lpIIDOpen;
|
|
ULONG iCreateTemplate = iconPR_DEF_CREATE_MAILUSER;
|
|
BOOL fCreatedNew = FALSE;
|
|
LPENTRYID lpEIDDup = NULL;
|
|
ULONG cbEIDDup;
|
|
|
|
|
|
// Check the entry against our "seen" list
|
|
fDuplicateEID = AddEntryToExportList(cbEID, lpEID, &lListIndex);
|
|
|
|
if (! fDuplicateEID) {
|
|
// Set up some object type specific variables
|
|
switch (ulObjectType) {
|
|
default:
|
|
DebugTrace("ExportEntry got unknown object type %u, assuming MailUser\n", ulObjectType);
|
|
Assert(FALSE);
|
|
|
|
case MAPI_MAILUSER:
|
|
iCreateTemplate = iconPR_DEF_CREATE_MAILUSER;
|
|
lpIIDOpen = NULL;
|
|
fDistList = FALSE;
|
|
break;
|
|
|
|
case MAPI_DISTLIST:
|
|
iCreateTemplate = iconPR_DEF_CREATE_DL;
|
|
lpIIDOpen = (LPIID)&IID_IDistList;
|
|
fDistList = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
// Open the entry
|
|
if (HR_FAILED(hResult = lpAdrBookWAB->lpVtbl->OpenEntry(lpAdrBookWAB,
|
|
cbEID,
|
|
lpEID,
|
|
lpIIDOpen,
|
|
MAPI_MODIFY, // need to do SetProps inside Filter routine, but won't save them.
|
|
&ulObjectTypeOpen,
|
|
(LPUNKNOWN *)&lpMailUserWAB))) {
|
|
DebugTrace("OpenEntry(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
// If DISTLIST, assume we got lpMailUser until we need lpDistList.
|
|
|
|
Assert(lpMailUserWAB);
|
|
Assert(ulObjectType == ulObjectTypeOpen);
|
|
|
|
//
|
|
// NOTE: Must not fail between here and HrFilterExportMailUserProps because
|
|
// we will end up freeing lpProps with MAPIFreeBuffer.
|
|
//
|
|
// Get and filter the property array here
|
|
if (hResult = HrFilterExportMailUserProps(&cProps, &lpProps, lpMailUserWAB, &fDistList)) {
|
|
lpDisplayName = FindStringInProps(lpProps, cProps, PR_DISPLAY_NAME);
|
|
lpEmailAddress = FindStringInProps(lpProps, cProps, PR_EMAIL_ADDRESS);
|
|
|
|
if (HandleExportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpDisplayName,
|
|
lpEmailAddress,
|
|
lpExportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Find some interesting property values here
|
|
lpDisplayName = FindStringInProps(lpProps, cProps, PR_DISPLAY_NAME);
|
|
lpEmailAddress = FindStringInProps(lpProps, cProps, PR_EMAIL_ADDRESS);
|
|
|
|
|
|
if (ulObjectType == MAPI_DISTLIST && ! fDistList) {
|
|
// Filter must have changed this to a mailuser.
|
|
ulObjectType = MAPI_MAILUSER;
|
|
iCreateTemplate = iconPR_DEF_CREATE_MAILUSER;
|
|
lpIIDOpen = NULL;
|
|
}
|
|
|
|
if (fDistList) {
|
|
ulCreateFlags = CREATE_CHECK_DUP_LOOSE;
|
|
|
|
// PAB can't detect collisions on DL SaveChanges.
|
|
// See if this is a duplicate:
|
|
if (! HR_FAILED(hResult = FindPABEntry(lpContainerMAPI,
|
|
MAPI_DISTLIST,
|
|
lpDisplayName,
|
|
NULL,
|
|
&cbEIDDup,
|
|
&lpEIDDup))) {
|
|
|
|
// Found a duplicate. Keep track of it!
|
|
}
|
|
} else {
|
|
ulCreateFlags = CREATE_CHECK_DUP_STRICT;
|
|
}
|
|
|
|
//
|
|
// NOTE: lpProps after this point is MAPI Allocated rather than WAB allocated.
|
|
//
|
|
|
|
if (HR_FAILED(hResult = lpContainerMAPI->lpVtbl->CreateEntry(lpContainerMAPI,
|
|
lpCreateEIDsMAPI[iCreateTemplate].Value.bin.cb,
|
|
(LPENTRYID)lpCreateEIDsMAPI[iCreateTemplate].Value.bin.lpb,
|
|
ulCreateFlags,
|
|
&lpMailUserMAPI))) {
|
|
DebugTrace("CreateEntry(MAPI MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (fDistList) {
|
|
// Update status message
|
|
if (*szBufferDLMessage == '\0') { // only load once, then keep it.
|
|
LoadString(hInst, IDS_MESSAGE_EXPORTING_DL, szBufferDLMessage, ARRAYSIZE(szBufferDLMessage));
|
|
}
|
|
if (lpDisplayName) {
|
|
ULONG cchSize =lstrlen(szBufferDLMessage) + 1 + lstrlen(lpDisplayName);
|
|
if (lpszMessage = LocalAlloc(LMEM_FIXED, sizeof(TCHAR)*cchSize)) {
|
|
wnsprintf(lpszMessage, cchSize, szBufferDLMessage, lpDisplayName);
|
|
DebugTrace("Status Message: %s\n", lpszMessage);
|
|
if (! SetDlgItemText(hwnd, IDC_Message, lpszMessage)) {
|
|
DebugTrace("SetDlgItemText -> %u\n", GetLastError());
|
|
}
|
|
LocalFree(lpszMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (! lpEIDDup) {
|
|
// If this was a DL which we know already exists, don't even bother writing it,
|
|
// just fall through to the collision pass. Otherwise, try to set the props
|
|
// and save it... if it fails, we'll get an hResult=MAPI_E_COLLISION.
|
|
|
|
// Set the properties on the PAB entry
|
|
if (HR_FAILED(hResult = lpMailUserMAPI->lpVtbl->SetProps(lpMailUserMAPI,
|
|
cProps, // cValues
|
|
lpProps, // property array
|
|
NULL))) { // problems array
|
|
DebugTrace("ExportEntry:SetProps(MAPI) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpMailUserMAPI->lpVtbl->SaveChanges(lpMailUserMAPI,
|
|
KEEP_OPEN_READONLY | FORCE_SAVE))) {
|
|
DebugTrace("SaveChanges -> %x\n", GetScode(hResult));
|
|
} else {
|
|
fCreatedNew = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Collisions
|
|
//
|
|
if (lpEIDDup || GetScode(hResult) == MAPI_E_COLLISION) {
|
|
// Find the display name
|
|
if (! lpDisplayName) {
|
|
DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Do we need to prompt?
|
|
switch (lpExportOptions->ReplaceOption) {
|
|
case WAB_REPLACE_PROMPT:
|
|
// Prompt user with dialog. If they say YES, we should
|
|
// recurse with the FORCE flag set.
|
|
|
|
RI.lpszDisplayName = lpDisplayName;
|
|
RI.lpszEmailAddress = lpEmailAddress;
|
|
RI.ConfirmResult = CONFIRM_ERROR;
|
|
RI.fExport = TRUE;
|
|
RI.lpImportOptions = lpExportOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ExportReplace),
|
|
hwnd,
|
|
ReplaceDialogProc,
|
|
(LPARAM)&RI);
|
|
|
|
switch (RI.ConfirmResult) {
|
|
case CONFIRM_YES:
|
|
case CONFIRM_YES_TO_ALL:
|
|
fForceReplace = TRUE;
|
|
break;
|
|
|
|
case CONFIRM_ABORT:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
|
|
default:
|
|
// NO
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WAB_REPLACE_ALWAYS:
|
|
fForceReplace = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fForceReplace) {
|
|
SBinary sbEntry;
|
|
ENTRYLIST EntryList = {1, &sbEntry};
|
|
|
|
// Find the existing PAB entry and delete it.
|
|
if (! lpDisplayName) {
|
|
lpDisplayName = (LPTSTR)szEmpty;
|
|
}
|
|
|
|
if (! lpEIDDup) {
|
|
if (HR_FAILED(hResult = FindPABEntry(lpContainerMAPI,
|
|
ulObjectType,
|
|
lpDisplayName,
|
|
lpEmailAddress,
|
|
&cbEIDDup,
|
|
&lpEIDDup))) {
|
|
// Hey, couldn't find it. Just pretend it isn't there,
|
|
// go on and create the new one anyway.
|
|
}
|
|
}
|
|
if (lpEIDDup) {
|
|
// Delete this entry.
|
|
sbEntry.cb = cbEIDDup;
|
|
sbEntry.lpb = (LPBYTE)lpEIDDup;
|
|
|
|
if (HR_FAILED(hResult = lpContainerMAPI->lpVtbl->DeleteEntries(lpContainerMAPI,
|
|
&EntryList,
|
|
0))) {
|
|
DebugTrace("PAB DeleteEntries(%s) -> %x\n", lpDisplayName);
|
|
}
|
|
|
|
if (lpEIDDup) {
|
|
MAPIFreeBuffer(lpEIDDup);
|
|
}
|
|
}
|
|
|
|
lpMailUserMAPI->lpVtbl->Release(lpMailUserMAPI);
|
|
lpMailUserMAPI = NULL;
|
|
|
|
// Create a new entry without the collision flags
|
|
if (HR_FAILED(hResult = lpContainerMAPI->lpVtbl->CreateEntry(lpContainerMAPI,
|
|
lpCreateEIDsMAPI[iCreateTemplate].Value.bin.cb,
|
|
(LPENTRYID)lpCreateEIDsMAPI[iCreateTemplate].Value.bin.lpb,
|
|
0,
|
|
&lpMailUserMAPI))) {
|
|
DebugTrace("CreateEntry(MAPI MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the properties on the PAB entry
|
|
if (HR_FAILED(hResult = lpMailUserMAPI->lpVtbl->SetProps(lpMailUserMAPI,
|
|
cProps, // cValues
|
|
lpProps, // property array
|
|
NULL))) { // problems array
|
|
DebugTrace("ExportEntry:SetProps(MAPI) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpMailUserMAPI->lpVtbl->SaveChanges(lpMailUserMAPI,
|
|
KEEP_OPEN_READONLY | FORCE_SAVE))) {
|
|
DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
} else {
|
|
fCreatedNew = TRUE;
|
|
}
|
|
} else {
|
|
fDuplicate = TRUE;
|
|
}
|
|
|
|
hResult = hrSuccess;
|
|
}
|
|
|
|
if (fCreatedNew) {
|
|
// What is the ENTRYID of our new entry?
|
|
if ((hResult = lpMailUserMAPI->lpVtbl->GetProps(lpMailUserMAPI,
|
|
(LPSPropTagArray)&ptaEid,
|
|
0,
|
|
&cEIDPropMAPI,
|
|
&lpEIDPropMAPI))) {
|
|
DebugTrace("ExportEntry: GetProps(MAPI ENTRYID) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
Assert(cEIDPropMAPI);
|
|
Assert(lpEIDPropMAPI[ieidPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
|
|
cbEIDNew = lpEIDPropMAPI[0].Value.bin.cb;
|
|
|
|
if (FAILED(sc = MAPIAllocateBuffer(cbEIDNew, &lpEIDNew))) {
|
|
DebugTrace("ExportEntry: MAPIAllocateBuffer(MAPI ENTRYID) -> %x\n", sc);
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
// Copy the new EntryID into the buffer
|
|
CopyMemory(lpEIDNew, lpEIDPropMAPI[0].Value.bin.lpb, cbEIDNew);
|
|
}
|
|
|
|
|
|
//
|
|
// If this is a DISTLIST, fill it in.
|
|
//
|
|
if (fDistList && ! fDuplicate && cbEIDNew) {
|
|
lpDistListWAB = (LPDISTLIST)lpMailUserWAB; // This is REALLY a DISTLIST object
|
|
// DO NOT Release this!
|
|
|
|
// Open the new WAB DL as a DISTLIST object
|
|
if (HR_FAILED(hResult = lpContainerMAPI->lpVtbl->OpenEntry(lpContainerMAPI,
|
|
cbEIDNew,
|
|
lpEIDNew,
|
|
(LPIID)&IID_IDistList,
|
|
MAPI_MODIFY,
|
|
&ulObjectTypeOpen,
|
|
(LPUNKNOWN*)&lpDistListMAPI))) {
|
|
DebugTrace("ExportEntry: MAPI OpenEntry(IID_DistList) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
Assert(lpDistListMAPI);
|
|
|
|
|
|
// For each entry in the DL:
|
|
// Migrate the entry (MailUser or DL) recursively
|
|
// Add new entryid to DL contents
|
|
if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->GetContentsTable(lpDistListWAB,
|
|
0, // ulFlags
|
|
&lpDLTableWAB))) {
|
|
DebugTrace("ExportEntry:GetContentsTable(WAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// Set the columns to those we're interested in
|
|
if (hResult = lpDLTableWAB->lpVtbl->SetColumns(lpDLTableWAB,
|
|
(LPSPropTagArray)&ptaColumns,
|
|
0)) {
|
|
DebugTrace("WAB SetColumns(DL Table) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
cRows = 1;
|
|
while (cRows) {
|
|
// Get the next DL entry
|
|
if (hResult = lpDLTableWAB->lpVtbl->QueryRows(lpDLTableWAB,
|
|
1, // one row at a time
|
|
0, // ulFlags
|
|
&lpRow)) {
|
|
DebugTrace("DL: QueryRows -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
if (lpRow && lpRow->cRows) {
|
|
Assert(lpRow->cRows == 1);
|
|
Assert(lpRow->aRow[0].cValues == iptaColumnsMax);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].ulPropTag == PR_ENTRYID);
|
|
Assert(lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].ulPropTag == PR_OBJECT_TYPE);
|
|
|
|
if (lpRow) {
|
|
if (cRows = lpRow->cRows) { // yes, single '='
|
|
hResult = ExportEntry(hwnd,
|
|
lpAdrBookWAB,
|
|
lpContainerMAPI,
|
|
lpCreateEIDsMAPI,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_OBJECT_TYPE].Value.l,
|
|
(LPENTRYID)lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.lpb,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_ENTRYID].Value.bin.cb,
|
|
&lpeidDLMAPI, // returned new or existing entry
|
|
&cbeidDLMAPI,
|
|
TRUE,
|
|
FALSE);
|
|
if (hResult) {
|
|
if (HandleExportError(hwnd,
|
|
0,
|
|
hResult,
|
|
lpRow->aRow[0].lpProps[iptaColumnsPR_DISPLAY_NAME].Value.LPSZ,
|
|
PropStringOrNULL(&lpRow->aRow[0].lpProps[iptaColumnsPR_EMAIL_ADDRESS]),
|
|
lpExportOptions)) {
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
break; // out of loop
|
|
} else {
|
|
hResult = hrSuccess;
|
|
}
|
|
}
|
|
} // else, drop out of loop, we're done.
|
|
WABFreeProws(lpRow);
|
|
lpRow = NULL;
|
|
|
|
if (HR_FAILED(hResult)) {
|
|
// This entry couldn't be created. Ignore it.
|
|
DebugTrace("Coudln't create DL entry -> %x\n", GetScode(hResult));
|
|
hResult = hrSuccess;
|
|
continue;
|
|
}
|
|
|
|
// Add the Entry to the DL using the new entry's EntryID
|
|
if (cbeidDLMAPI && lpeidDLMAPI) {
|
|
// BUGBUG: Don't bother with this one if this is a duplicate entry.
|
|
if (HR_FAILED(hResult = lpDistListMAPI->lpVtbl->CreateEntry(lpDistListMAPI,
|
|
cbeidDLMAPI,
|
|
lpeidDLMAPI,
|
|
0, // allow duplicates here
|
|
&lpEntryMAPI))) {
|
|
DebugTrace("Couldn't create new entry in DL -> %x\n", GetScode(hResult));
|
|
break;
|
|
}
|
|
|
|
hResult = lpEntryMAPI->lpVtbl->SaveChanges(lpEntryMAPI, FORCE_SAVE);
|
|
|
|
if (lpEntryMAPI) {
|
|
lpEntryMAPI->lpVtbl->Release(lpEntryMAPI);
|
|
lpEntryMAPI = NULL;
|
|
}
|
|
}
|
|
|
|
if (lpeidDLMAPI) {
|
|
MAPIFreeBuffer(lpeidDLMAPI);
|
|
lpeidDLMAPI = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
break; // done
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
DebugTrace("Found a duplicate EntryID\n");
|
|
}
|
|
|
|
//
|
|
// Save the entryid to the list and return a buffer with it
|
|
//
|
|
if (cbEIDNew && lpEIDNew) { // We created one?
|
|
// created one
|
|
} else if (fDuplicateEID && lListIndex != -1) { // Was it in the list?
|
|
cbEIDNew = lpEntriesSeen[lListIndex].sbinWAB.cb;
|
|
if (FAILED(sc = MAPIAllocateBuffer(cbEIDNew, &lpEIDNew))) {
|
|
DebugTrace("ExportEntry: WABAllocateBuffer(WAB ENTRYID) -> %x\n", sc);
|
|
// ignore
|
|
cbEIDNew = 0;
|
|
} else {
|
|
// Copy the EntryID from the list into the buffer
|
|
CopyMemory(lpEIDNew, lpEntriesSeen[lListIndex].sbinWAB.lpb, cbEIDNew);
|
|
}
|
|
|
|
} else if (fDuplicate) { // Was it a duplicate
|
|
FindPABEntry(lpContainerMAPI,
|
|
ulObjectType,
|
|
lpDisplayName,
|
|
lpEmailAddress,
|
|
&cbEIDNew,
|
|
&lpEIDNew);
|
|
|
|
#ifdef OLD_STUFF
|
|
FindExistingPABEntry(lpProps, cProps, lpContainerMAPI, &lpEIDNew, &cbEIDNew);
|
|
#endif // OLD_STUFF
|
|
// ignore errors since the lpEIDNew and cbEIDNew will be nulled out
|
|
}
|
|
|
|
// Update the seen list
|
|
if (! fDuplicateEID) {
|
|
MarkPABEntryInList(cbEIDNew, lpEIDNew, lListIndex);
|
|
}
|
|
|
|
// If caller requested the entryid's, return them
|
|
if (lpcbEIDMAPI && lppEIDMAPI) {
|
|
*lpcbEIDMAPI = cbEIDNew;
|
|
*lppEIDMAPI = lpEIDNew;
|
|
fReturnEID = TRUE; // don't free it
|
|
}
|
|
|
|
exit:
|
|
//
|
|
// Cleanup MAPI stuff
|
|
//
|
|
if (lpProps) {
|
|
MAPIFreeBuffer(lpProps);
|
|
}
|
|
|
|
if (lpEIDPropMAPI) {
|
|
MAPIFreeBuffer(lpEIDPropMAPI);
|
|
}
|
|
|
|
if (lpEIDNew && ! fReturnEID) {
|
|
MAPIFreeBuffer(lpEIDNew);
|
|
}
|
|
|
|
if (lpeidDLMAPI) {
|
|
MAPIFreeBuffer(lpeidDLMAPI);
|
|
}
|
|
|
|
if (lpMailUserMAPI) {
|
|
lpMailUserMAPI->lpVtbl->Release(lpMailUserMAPI);
|
|
}
|
|
|
|
if (lpDistListMAPI) {
|
|
lpDistListMAPI->lpVtbl->Release(lpDistListMAPI);
|
|
}
|
|
|
|
//
|
|
// Cleanup WAB stuff
|
|
//
|
|
if (lpRow) {
|
|
WABFreeProws(lpRow);
|
|
}
|
|
|
|
if (lpDLTableWAB) {
|
|
lpDLTableWAB->lpVtbl->Release(lpDLTableWAB);
|
|
}
|
|
|
|
if (lpMailUserWAB) {
|
|
lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
|
|
}
|
|
|
|
// Do not release this... It is the same object as lpMailUserWAB!
|
|
// if (lpDistListWAB) {
|
|
// lpDistListWAB->lpVtbl->Release(lpDistListWAB);
|
|
// }
|
|
|
|
if (! HR_FAILED(hResult)) {
|
|
hResult = hrSuccess;
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
HRESULT PABExport(HWND hWnd,
|
|
LPADRBOOK lpAdrBook,
|
|
LPWABOBJECT lpWABObject,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions) {
|
|
BOOL fDone = FALSE;
|
|
HRESULT hResult = hrSuccess;
|
|
|
|
lpAdrBookWAB = lpAdrBook;
|
|
lpfnProgressCB = lpProgressCB;
|
|
lpExportOptions = lpOptions;
|
|
|
|
// Setup memory allocators
|
|
SetGlobalBufferFunctions(lpWABObject);
|
|
|
|
|
|
// Prime the state machine
|
|
State = STATE_EXPORT_MU;
|
|
|
|
|
|
while (! fDone) {
|
|
switch (State) {
|
|
case STATE_EXPORT_MU:
|
|
StateExportMU(hWnd);
|
|
break;
|
|
|
|
case STATE_EXPORT_NEXT_MU:
|
|
StateExportNextMU(hWnd);
|
|
break;
|
|
|
|
case STATE_EXPORT_DL:
|
|
StateExportDL(hWnd);
|
|
break;
|
|
|
|
case STATE_EXPORT_NEXT_DL:
|
|
StateExportNextDL(hWnd);
|
|
break;
|
|
|
|
case STATE_EXPORT_FINISH:
|
|
StateExportFinish(hWnd);
|
|
fDone = TRUE;
|
|
break;
|
|
|
|
case STATE_EXPORT_ERROR:
|
|
StateExportError(hWnd);
|
|
// BUGBUG: Should set hResult to something
|
|
break;
|
|
|
|
case STATE_EXPORT_CANCEL:
|
|
StateExportCancel(hWnd);
|
|
break;
|
|
|
|
default:
|
|
DebugTrace("Unknown state %u in PABExport\n", State);
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
HRESULT PABImport(HWND hWnd,
|
|
LPADRBOOK lpAdrBook,
|
|
LPWABOBJECT lpWABObject,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_IMPORT_OPTIONS lpOptions) {
|
|
|
|
BOOL fDone = FALSE;
|
|
HRESULT hResult = hrSuccess;
|
|
|
|
lpAdrBookWAB = lpAdrBook;
|
|
lpfnProgressCB = lpProgressCB;
|
|
lpImportOptions = lpOptions;
|
|
|
|
// Setup memory allocators
|
|
SetGlobalBufferFunctions(lpWABObject);
|
|
|
|
|
|
// Prime the state machine
|
|
State = STATE_IMPORT_MU;
|
|
|
|
|
|
while (! fDone) {
|
|
switch (State) {
|
|
case STATE_IMPORT_MU:
|
|
StateImportMU(hWnd);
|
|
break;
|
|
|
|
case STATE_IMPORT_NEXT_MU:
|
|
StateImportNextMU(hWnd);
|
|
break;
|
|
|
|
case STATE_IMPORT_DL:
|
|
StateImportDL(hWnd);
|
|
break;
|
|
|
|
case STATE_IMPORT_NEXT_DL:
|
|
StateImportNextDL(hWnd);
|
|
break;
|
|
|
|
case STATE_IMPORT_FINISH:
|
|
StateImportFinish(hWnd);
|
|
fDone = TRUE;
|
|
break;
|
|
|
|
case STATE_IMPORT_ERROR:
|
|
StateImportError(hWnd);
|
|
// BUGBUG: Should set hResult to something
|
|
break;
|
|
|
|
case STATE_IMPORT_CANCEL:
|
|
StateImportCancel(hWnd);
|
|
break;
|
|
|
|
default:
|
|
DebugTrace("Unknown state %u in PABImport\n", State);
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
/*
|
|
- HrLoadPrivateWABProps
|
|
-
|
|
* Private function to load Conferencing Named properties
|
|
* as globals up front
|
|
*
|
|
*
|
|
*/
|
|
HRESULT HrLoadPrivateWABPropsForCSV(LPADRBOOK lpIAB)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPSPropTagArray lpta = NULL;
|
|
SCODE sc = 0;
|
|
ULONG i, uMax = prWABConfMax, nStartIndex = OLK_NAMEDPROPS_START;
|
|
LPMAPINAMEID *lppConfPropNames = NULL;
|
|
sc = WABAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
|
|
//sc = WABAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
|
|
if( (HR_FAILED(hr = ResultFromScode(sc))) )
|
|
goto err;
|
|
|
|
for(i=0;i< uMax;i++)
|
|
{
|
|
//sc = WABAllocateMore(sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
|
|
sc = WABAllocateMore( sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
|
|
if(sc)
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto err;
|
|
}
|
|
lppConfPropNames[i]->lpguid = (LPGUID) &PS_Conferencing;
|
|
lppConfPropNames[i]->ulKind = MNID_ID;
|
|
lppConfPropNames[i]->Kind.lID = nStartIndex + i;
|
|
}
|
|
// Load the set of conferencing named props
|
|
//
|
|
if( HR_FAILED(hr = (lpIAB)->lpVtbl->GetIDsFromNames(lpIAB, uMax, lppConfPropNames,
|
|
MAPI_CREATE, &lpta) ))
|
|
goto err;
|
|
|
|
if(lpta)
|
|
{
|
|
// Set the property types on the returned props
|
|
PR_SERVERS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfServers], PT_MV_TSTRING);
|
|
}
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].ulPropTag = PR_SERVERS;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].fChosen = FALSE;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].ids = ids_ExportConfServer;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].lpszName = NULL;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].lpszCSVName = NULL;
|
|
|
|
err:
|
|
if(lpta)
|
|
WABFreeBuffer( lpta );
|
|
if( lppConfPropNames )
|
|
WABFreeBuffer( lppConfPropNames );
|
|
//WABFreeBuffer(lpta);
|
|
return hr;
|
|
}
|