windows-nt/Source/XPSP1/NT/printscan/fax/exchange/ab/ablogon.c
2020-09-26 16:20:57 +08:00

1814 lines
50 KiB
C

/***********************************************************************
*
* ABLOGON.C
*
*
* The Microsoft At Work Fax Address Book Provider.
*
* This file has the code to implement the Microsoft At Work Fax Address Book's logon
* object.
*
* The following routines are implemented in this file:
*
* ABPLOGON_QueryInterface
* ABPLOGON_Release
* ABPLOGON_Logoff
* ABPLOGON_OpenEntry
* ABPLOGON_CompareEntryIDs
* ABPLOGON_Advise
* ABPLOGON_Unadvise
* ABPLOGON_OpenStatusEntry
* ABPLOGON_OpenTemplateID
* ABPLOGON_GetOneOffTable
* ABPLOGON_PrepareRecips
*
* LpMuidFromLogon
* HrLpszGetCurrentFileName
* HrReplaceCurrentfileName
* GenerateContainerDN
* HrBuildRootHier
*
*
* Copyright 1992, 1993, 1994 Microsoft Corporation. All Rights Reserved.
*
* Revision History:
*
* When Who What
* -------- ------------------ ---------------------------------------
* 8.3.94 MAPI Original source from MAPI sample ABP build 304
* 8.3.94 Yoram Yaacovi Moved code from the FAX ABP original abp.c to here
* 11.11.94 Yoram Yaacovi Upgrade to MAPI 318 (PR_INSTANCE_KEY)
*
***********************************************************************/
#include "faxab.h"
ABPLOGON_Vtbl vtblABPLOGON =
{
ABPLOGON_QueryInterface,
(ABPLOGON_AddRef_METHOD *) ROOT_AddRef,
ABPLOGON_Release,
(ABPLOGON_GetLastError_METHOD *) ROOT_GetLastError,
ABPLOGON_Logoff,
ABPLOGON_OpenEntry,
ABPLOGON_CompareEntryIDs,
ABPLOGON_Advise,
ABPLOGON_Unadvise,
ABPLOGON_OpenStatusEntry,
ABPLOGON_OpenTemplateID,
ABPLOGON_GetOneOffTable,
ABPLOGON_PrepareRecips
};
/*
- HrNewABLogon
-
*
* Creates a new Microsoft At Work Fax AB Logon object.
*/
HRESULT
HrNewABLogon( LPABLOGON * lppABLogon,
LPABPROVIDER lpABP,
LPMAPISUP lpMAPISup,
LPTSTR lpszFABFile,
LPMAPIUID lpmuid,
HINSTANCE hLibrary,
LPALLOCATEBUFFER lpAllocBuff,
LPALLOCATEMORE lpAllocMore,
LPFREEBUFFER lpFreeBuff,
LPMALLOC lpMalloc
)
{
SCODE sc;
HRESULT hResult = hrSuccess;
SPropValue rgSPVStat[6];
LPABPLOGON lpABPLogon = NULL;
#ifdef UNICODE
CHAR szFileName[ MAX_PATH ];
#endif
/*
* Allocate space for the lpABPLogon object
*/
sc = lpAllocBuff(SIZEOF(ABPLOGON), &lpABPLogon);
if (FAILED(sc))
{
hResult = ResultFromScode(sc);
goto out;
}
/*
* Initialize the ABPLogon object
*/
lpABPLogon->lpVtbl = &vtblABPLOGON;
lpABPLogon->lcInit = 1;
lpABPLogon->hResult = hrSuccess;
lpABPLogon->idsLastError = 0;
lpABPLogon->hLibrary = hLibrary;
lpABPLogon->lpMalloc = lpMalloc;
lpABPLogon->lpAllocBuff = lpAllocBuff;
lpABPLogon->lpAllocMore = lpAllocMore;
lpABPLogon->lpFreeBuff = lpFreeBuff;
lpABPLogon->lpMapiSup = lpMAPISup;
lpABPLogon->lpABP = (LPABPROVIDER) lpABP;
lpABPLogon->lpszFileName = lpszFABFile;
lpABPLogon->muidID = *lpmuid;
lpABPLogon->lpTDatRoot = NULL;
lpABPLogon->lpTDatOO = NULL;
/*
* Register my status row...
*/
// MAPI doesn't use UNICODE for this one...
rgSPVStat[0].ulPropTag = PR_DISPLAY_NAME_A;
#ifdef UNICODE
szFileName[0] = 0;
WideCharToMultiByte( CP_ACP, 0, lpszFABFile, -1, szFileName, ARRAYSIZE(szFileName), NULL, NULL );
rgSPVStat[0].Value.lpszA = szFileName;
#else
rgSPVStat[0].Value.lpszA = lpszFABFile;
#endif
rgSPVStat[1].ulPropTag = PR_RESOURCE_METHODS;
rgSPVStat[1].Value.l = 0;
rgSPVStat[2].ulPropTag = PR_RESOURCE_FLAGS;
rgSPVStat[2].Value.l = 0;
rgSPVStat[3].ulPropTag = PR_STATUS_CODE;
rgSPVStat[3].Value.l = STATUS_AVAILABLE;
// MAPI doesn't use UNICODE for this one
rgSPVStat[4].ulPropTag = PR_STATUS_STRING_A;
rgSPVStat[4].Value.lpszA = "Available";
// MAPI doesn't use UNICODE for this one
rgSPVStat[5].ulPropTag = PR_PROVIDER_DISPLAY_A;
rgSPVStat[5].Value.lpszA = "Microsoft Fax Address Book Provider";
/*
* Set the Status Row for this provider,
* but do not allow an error from setting the
* status row to cause failure to Logon.
*/
(void)lpMAPISup->lpVtbl->ModifyStatusRow(lpMAPISup,
ARRAYSIZE(rgSPVStat), rgSPVStat, 0);
/*
* AddRef the support object, because we're keeping
* a pointer to it in our Logon object.
*/
lpMAPISup->lpVtbl->AddRef(lpMAPISup);
/*
* AddRef our parent ABInit object
*/
lpABP->lpVtbl->AddRef(lpABP);
InitializeCriticalSection(&lpABPLogon->cs);
*lppABLogon = (LPABLOGON) lpABPLogon;
out:
DebugTraceResult(HrNewABPLogon, hResult);
return hResult;
}
/*************************************************************************
*
- ABPLOGON_QueryInterface
-
*/
STDMETHODIMP
ABPLOGON_QueryInterface( LPABPLOGON lpABPLogon,
REFIID lpiid,
LPVOID * ppvObj
)
{
if ( IsBadReadPtr(lpiid, SIZEOF(IID)) ||
IsBadWritePtr(ppvObj, SIZEOF(LPVOID))
)
{
DebugTraceSc(ABPLOGON_QueryInterface, E_INVALIDARG);
return ResultFromScode(E_INVALIDARG);
}
/* See if the requested interface is one of ours */
if ( memcmp(lpiid, &IID_IUnknown, SIZEOF(IID)) &&
memcmp(lpiid, &IID_IABLogon, SIZEOF(IID))
)
{
*ppvObj = NULL; /* OLE requires zeroing [out] parameter on error */
DebugTraceSc(ABPLOGON_QueryInterface, E_NOINTERFACE);
return ResultFromScode(E_NOINTERFACE);
}
/* We'll do this one. Bump the usage count and return a new pointer. */
EnterCriticalSection(&lpABPLogon->cs);
++lpABPLogon->lcInit;
LeaveCriticalSection(&lpABPLogon->cs);
*ppvObj = lpABPLogon;
return hrSuccess;
}
/*
* Use ROOTs AddRef
*/
/*************************************************************************
*
- ABPLOGON_Release
-
*/
STDMETHODIMP_(ULONG)
ABPLOGON_Release(LPABPLOGON lpABPLogon)
{
LONG lcInit;
EnterCriticalSection(&lpABPLogon->cs);
lcInit = --lpABPLogon->lcInit;
LeaveCriticalSection(&lpABPLogon->cs);
if (lcInit == 0)
{
DeleteCriticalSection(&lpABPLogon->cs);
lpABPLogon->lpVtbl = NULL;
lpABPLogon->lpFreeBuff(lpABPLogon);
return (0);
}
return lcInit;
}
/*************************************************************************
*
- ABPLOGON_Logoff
-
* Logoff from this logon object. Clean up any resources/objects that
* our logon object has accumulated.
*
*
*/
STDMETHODIMP
ABPLOGON_Logoff(LPABPLOGON lpABPLogon, ULONG ulFlags)
{
DebugTrace("AWFXAB32(ABPLOGON_Logoff): entering\n");
#ifdef DO_WE_REALLY_NEED_TAPI
/*
* Let TAPI go
*/
DeinitTAPI();
#endif
/*
* Remove this logon object from the list of known
* logon objects associated with this initialization
* of this provider.
*/
(void) RemoveLogonObject(lpABPLogon->lpABP, lpABPLogon, lpABPLogon->lpFreeBuff);
/*
* No longer need to be holding on to our parent
*/
lpABPLogon->lpABP->lpVtbl->Release(lpABPLogon->lpABP);
/*
* Free up the file
*/
lpABPLogon->lpFreeBuff(lpABPLogon->lpszFileName);
if (lpABPLogon->lpTDatRoot)
lpABPLogon->lpTDatRoot->lpVtbl->Release(lpABPLogon->lpTDatRoot);
if (lpABPLogon->lpTDatOO)
lpABPLogon->lpTDatOO->lpVtbl->Release(lpABPLogon->lpTDatOO);
/*
* very last thing I should do is release the support object
*/
lpABPLogon->lpMapiSup->lpVtbl->Release(lpABPLogon->lpMapiSup);
DebugTrace("AWFXAB32(ABPLOGON_Logoff): leaving\n");
return hrSuccess;
}
/*************************************************************************
*
- ABPLOGON_OpenEntry
-
* Creates an object with (at least) the IMAPIProp interface from an
* entryID.
*
* There are four valid types of entryIDs handled:
*
* NULL <- return back the root container object
* DIR_ENTRYID <- return back the directory container object
* USR_ENTRYID <- return back the MAILUSER object
* OOUSER_ENTRYID <- return back the OneOff MAILUSER object
*
* Note: This call is reused for all other internal objects that support OpenEntry().
* Those other calls *must* check their parameters before calling this method.
* The only other way this method is called is via MAPI which does parameter checking
* for us. The most we'll do here is assert our parameters.
*/
STDMETHODIMP
ABPLOGON_OpenEntry( LPABPLOGON lpABPLogon,
ULONG cbEntryID,
LPENTRYID lpEntryID,
LPCIID lpInterface,
ULONG ulFlags,
ULONG * lpulObjType,
LPUNKNOWN * lppUnk
)
{
LPDIR_ENTRYID lpEID = (LPDIR_ENTRYID) lpEntryID;
HRESULT hResult = hrSuccess;
LPTSTR lpszFileName;
/*
* Check the EntryID
*/
// used to be: if (!lpEntryID)
if (!cbEntryID)
{
LPABCONT lpABCont = NULL;
/*
* Special case: the root level object
*/
NFAssertSz(!lpEntryID, "Non-NULL entry id passed with 0 cb to OpenEntry()\n");
/* Make this new object */
/*
* Get the current .FAB file name from our logon object
*/
hResult = HrLpszGetCurrentFileName((LPABLOGON) lpABPLogon, &lpszFileName);
if (HR_FAILED(hResult))
goto out;
// If there is a real Fax AB
if ((fExposeFaxAB) &&
(lpszFileName[0] != 0))
hResult = HrNewROOT((LPABCONT *) lppUnk,
lpulObjType,
(LPABLOGON) lpABPLogon,
lpInterface,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc);
else
// No Fax AB container
return ResultFromScode (MAPI_E_INTERFACE_NOT_SUPPORTED);
lpABPLogon->lpFreeBuff(lpszFileName);
goto out;
}
/*
* There's an entryID there, is it mine??
* I need to check because I'm reusing this routine for
* my Container->OpenEntry call, and I can't be sure the
* client will always be well behaved.
*
* When this routine is called from MAPI, this call is redundant. But
* because I'm reusing this routine, I gotta check.
*/
/* Compare MAPIUIDs */
if (memcmp(&(((LPDIR_ENTRYID) lpEntryID)->muid), &muidABMAWF,
SIZEOF(MAPIUID)))
{
/*
* Not mine!
*/
hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
DebugTraceResult(ABPLOGON_OpenEntry, hResult);
goto out;
}
/*
* What object does this correspond to??
*/
/* I've only got two types: containers and users */
if (lpEID->ulType == MAWF_DIRECTORY)
{
LPABLOGON lpABPLogonT = NULL;
/* entry id must have the same verson number */
if (lpEID->ulVersion != MAWF_VERSION)
{
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
SetErrorIDS(lpABPLogon, hResult, IDS_OLD_EID);
goto out;
}
/*
* find the correct logon object for this entryid
*/
(void) FindLogonObject(lpABPLogon->lpABP, &lpEID->muidID, &lpABPLogonT);
/* did we find the corresponding logon object */
if (!lpABPLogonT)
{
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
goto out;
}
// If I don't have a fab file at this point, I can't open the AB container
HrLpszGetCurrentFileName((LPABLOGON) lpABPLogonT, &lpszFileName);
if (lpszFileName[0] == 0)
{
hResult = ResultFromScode (MAPI_E_NO_SUPPORT);
DebugTraceResult(ABPLOGON_OpenEntry, hResult);
goto out;
}
hResult = HrNewFaxDirectory( (LPABCONT *) lppUnk,
lpulObjType,
(LPABLOGON) lpABPLogonT,
lpInterface,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc);
goto out;
}
if (lpEID->ulType == MAWF_USER)
{
if (cbEntryID == (ULONG) sizeof(USR_ENTRYID))
{
hResult = HrNewFaxUser( (LPMAILUSER *) lppUnk,
lpulObjType,
cbEntryID,
lpEntryID,
(LPABLOGON) lpABPLogon,
lpInterface,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc);
goto out;
}
}
if (lpEID->ulType == MAWF_ONEOFF)
{
if (cbEntryID == (ULONG) sizeof(OOUSER_ENTRYID))
{
hResult = HrNewFaxOOUser( (LPMAILUSER *) lppUnk,
lpulObjType,
cbEntryID,
lpEntryID,
(LPABLOGON) lpABPLogon,
lpInterface,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc);
goto out;
}
}
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
out:
DebugTraceResult(ABPLOGON_OpenEntry, hResult);
return hResult;
}
/*************************************************************************
*
- ABPLOGON_CompareEntryIDs
-
* If the two entryids are mine and they're of the same type, then
* just do a binary comparison to see if they're equal.
*
*/
STDMETHODIMP
ABPLOGON_CompareEntryIDs( LPABPLOGON lpABPLogon,
ULONG cbEntryID1,
LPENTRYID lpEntryID1,
ULONG cbEntryID2,
LPENTRYID lpEntryID2,
ULONG ulFlags,
ULONG * lpulResult
)
{
LPDIR_ENTRYID lpEID1 = (LPDIR_ENTRYID) lpEntryID1;
LPDIR_ENTRYID lpEID2 = (LPDIR_ENTRYID) lpEntryID2;
HRESULT hResult = hrSuccess;
/*
* Check to see if their MUID is mine
*/
if ( memcmp(&(lpEID1->muid), &muidABMAWF, SIZEOF(MAPIUID)) ||
memcmp(&(lpEID2->muid), &muidABMAWF, SIZEOF(MAPIUID))
)
{
/*
* No recognition of these entryids.
*/
*lpulResult = (ULONG) FALSE;
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
goto out;
}
/*
* See if the type of entryids are the same
*/
if (lpEID1->ulType != lpEID2->ulType)
{
/*
* They're not, so they don't match
*/
*lpulResult = (ULONG) FALSE;
goto out;
}
/*
* See if the entryids are the same size. They'd better be
* if they're the same type.
*/
if (cbEntryID1 != cbEntryID2)
{
/*
* They're not?!? Then I don't know these...
*/
*lpulResult = (ULONG) FALSE;
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
goto out;
}
/*
* Check for Directory entryids
*/
if (lpEID1->ulType == MAWF_DIRECTORY)
{
/*
* Ok, I'm dealing with directory entryids
*/
/*
* Better make sure it's the right size
*/
if (cbEntryID1 != sizeof(DIR_ENTRYID))
{
/*
* This doesn't make sense. I don't recognize this entryid.
*/
*lpulResult = (ULONG) FALSE;
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
goto out;
}
/*
* At this point it's just a memcmp
*/
if (memcmp(lpEID1, lpEID2, SIZEOF(DIR_ENTRYID)))
{
/*
* They're not equal
*/
*lpulResult = (ULONG) FALSE;
goto out;
}
/*
* They must be the same
*/
*lpulResult = (ULONG) TRUE;
goto out;
}
if (lpEID1->ulType == MAWF_USER)
{
/*
* Ok, I'm dealing with user entryids
*/
/*
* Better make sure it's the right size
*/
if (cbEntryID1 != sizeof(USR_ENTRYID))
{
/*
* This doesn't make sense. I don't recognize this entryid.
*/
*lpulResult = (ULONG) FALSE;
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
goto out;
}
/*
* At this point it's just a memcmp
*/
if (memcmp(lpEID1, lpEID2, SIZEOF(USR_ENTRYID)))
{
/*
* They're not equal
*/
*lpulResult = (ULONG) FALSE;
goto out;
}
/*
* They must be the same
*/
*lpulResult = (ULONG) TRUE;
goto out;
}
if (lpEID1->ulType == MAWF_ONEOFF)
{
/*
* Ok, I'm dealing with oneoff user entryids
*/
/*
* Better make sure it's the right size
*/
if (cbEntryID1 != SIZEOF(OOUSER_ENTRYID))
{
/*
* This doesn't make sense. I don't recognize this entryid.
*/
*lpulResult = (ULONG) FALSE;
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
goto out;
}
/*
* At this point it's just a memcmp
*/
if (memcmp(lpEID1, lpEID2, SIZEOF(OOUSER_ENTRYID)))
{
/*
* They're not equal
*/
*lpulResult = (ULONG) FALSE;
goto out;
}
/*
* They must be the same
*/
*lpulResult = (ULONG) TRUE;
goto out;
}
/*
* It's no entryid I know of
*/
*lpulResult = (ULONG) FALSE;
hResult = ResultFromScode(MAPI_E_UNKNOWN_ENTRYID);
out:
DebugTraceResult(ABPLOGON_CompareEntryIDs, hResult);
return hResult;
}
/*************************************************************************
*
- ABPLOGON_OpenStatusEntry
-
*
*
*
*/
STDMETHODIMP
ABPLOGON_OpenStatusEntry( LPABPLOGON lpABPLogon,
LPCIID lpIID,
ULONG ulFlags,
ULONG FAR * lpulObjType,
LPMAPISTATUS FAR * lppEntry
)
{
HRESULT hr;
/*
* Validate Parameters
*/
if ( IsBadReadPtr(lpABPLogon, (UINT) SIZEOF(ABPLOGON)) ||
(lpIID && IsBadReadPtr(lpIID, (UINT) SIZEOF(IID))) ||
IsBadWritePtr(lpulObjType, (UINT) SIZEOF(ULONG FAR *)) ||
IsBadWritePtr(lppEntry, (UINT) SIZEOF(LPMAPISTATUS))
)
{
DebugTraceSc(ABPLogon_OpenStatusEntry, E_INVALIDARG);
return ResultFromScode(E_INVALIDARG);
}
hr = HrNewStatusObject( lppEntry,
lpulObjType,
ulFlags,
(LPABLOGON) lpABPLogon,
lpIID,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc);
DebugTraceResult(ABPLOGON_OpenStatusEntry, hr);
return hr;
}
/*************************************************************************
*
- ABPLOGON_OpenTemplateID
-
*
*
*
*/
STDMETHODIMP
ABPLOGON_OpenTemplateID( LPABPLOGON lpABPLogon,
ULONG cbTemplateId,
LPENTRYID lpTemplateId,
ULONG ulTemplateFlags,
LPMAPIPROP lpMAPIPropData,
LPCIID lpInterface,
LPMAPIPROP * lppMAPIPropNew,
LPMAPIPROP lpMAPIPropSibling
)
{
HRESULT hResult;
/*
* Validate Parameters
*/
if ( IsBadReadPtr(lpABPLogon, (UINT) SIZEOF(ABPLOGON)) ||
IsBadReadPtr(lpTemplateId, (UINT) cbTemplateId) ||
IsBadReadPtr(lpMAPIPropData, (UINT) SIZEOF(LPVOID)) ||
(lpInterface && IsBadReadPtr(lpInterface, (UINT) sizeof(IID))) ||
IsBadWritePtr(lppMAPIPropNew, (UINT) SIZEOF(LPMAPIPROP)) ||
(lpMAPIPropSibling && IsBadReadPtr(lpMAPIPropSibling, (UINT) SIZEOF(LPVOID)))
)
{
DebugTraceSc(ABPLogon_OpenTemplateID, E_INVALIDARG);
return ResultFromScode(E_INVALIDARG);
}
/* //$ need stronger checking here... */
/* entryid better be right size */
if (cbTemplateId != sizeof(OOUSER_ENTRYID) && cbTemplateId != sizeof(USR_ENTRYID))
{
hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
goto out;
}
/* is it my entry id compare MAPIUIDs */
if (memcmp(&(((LPUSR_ENTRYID) lpTemplateId)->muid), &muidABMAWF, SIZEOF(MAPIUID)))
{
/*
* Not mine!
*/
hResult = ResultFromScode( MAPI_E_INVALID_ENTRYID );
goto out;
}
/* better be a oneoff user entryid or a user entry id */
if (((LPUSR_ENTRYID) lpTemplateId)->ulType == MAWF_ONEOFF)
{
hResult = HrNewOOTID( lppMAPIPropNew,
cbTemplateId,
lpTemplateId,
ulTemplateFlags,
lpMAPIPropData,
(LPABLOGON) lpABPLogon,
lpInterface,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc
);
}
else if (((LPUSR_ENTRYID) lpTemplateId)->ulType == MAWF_USER)
{
hResult = HrNewTID( lppMAPIPropNew,
cbTemplateId,
lpTemplateId,
ulTemplateFlags,
lpMAPIPropData,
(LPABLOGON) lpABPLogon,
lpInterface,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc
);
}
else
{
hResult = MakeResult(MAPI_E_INVALID_ENTRYID);
}
out:
DebugTraceResult(ABPLOGON_OpenTemplateID, hResult);
return hResult;
}
/*
- ABPLOGON_GetOneOffTable
-
* Returns the lists of one-offs that this providers can support creation of.
* This list is added to the entries gathered from all the other AB logon objects
* and exposed to the user as the list of things that can be created on a
* message. Also this total list is available to other providers through the
* support method GetOneOffTable().
*
* Note: There's a bug here that if there are more than one Microsoft At Work Fax Address Books
* installed on a particular profile, then there will be multiple entries in the
* one-off table from this provider. This can be changed to only have one one-off
* entry, no matter how many FABs are configured in a profile, if the one-off table
* was associated with the ABInit object.
*/
/*
* Column set for the oneoff table
*/
enum { ivalootPR_DISPLAY_NAME = 0,
ivalootPR_ENTRYID,
ivalootPR_DEPTH,
ivalootPR_SELECTABLE,
ivalootPR_ADDRTYPE,
ivalootPR_DISPLAY_TYPE,
ivalootPR_INSTANCE_KEY,
ivalootMax };
static const SizedSPropTagArray(ivalootMax, tagaColSetOOTable) =
{
ivalootMax,
{
PR_DISPLAY_NAME_A,
PR_ENTRYID,
PR_DEPTH,
PR_SELECTABLE,
PR_ADDRTYPE_A,
PR_DISPLAY_TYPE,
PR_INSTANCE_KEY
}
};
STDMETHODIMP
ABPLOGON_GetOneOffTable( LPABPLOGON lpABPLogon,
ULONG ulFlags,
LPMAPITABLE * lppTable
)
{
SCODE sc;
HRESULT hResult;
SRow sRow;
SPropValue rgsPropValue[ivalootMax];
CHAR displayNameString[MAX_DISPLAY_NAME];
ULONG ulInstanceKey = 1;
HINSTANCE hInst;
#ifdef UNICODE
CHAR szEMT[ MAX_PATH ];
#endif
/*
* Validate Parameters
*/
if ( ulFlags & ~(MAPI_UNICODE) )
{
DebugTraceArg( APBLOGON_GetOneOffTable, "Unknown Flags" );
return ResultFromScode( MAPI_E_UNKNOWN_FLAGS );
}
if ( ulFlags & MAPI_UNICODE )
{
DebugTraceArg( APBLOGON_GetOneOffTable, "UNICODE not supported" );
return ResultFromScode( MAPI_E_BAD_CHARWIDTH );
}
if ( IsBadReadPtr(lpABPLogon, (UINT) SIZEOF(ABPLOGON))
|| IsBadWritePtr(lppTable, (UINT) SIZEOF(LPMAPITABLE))
)
{
DebugTraceSc(ABPLogon_GetOneOffTable, E_INVALIDARG);
return ResultFromScode(E_INVALIDARG);
}
EnterCriticalSection(&lpABPLogon->cs);
/*
* If there's not one already associated with this logon object,
* then create one.
*/
if (!lpABPLogon->lpTDatOO)
{
/* Create a Table data object */
sc = CreateTable(
(LPIID) &IID_IMAPITableData,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc,
0,
PR_DISPLAY_NAME_A,
(LPSPropTagArray) &tagaColSetOOTable,
&(lpABPLogon->lpTDatOO));
if (FAILED(sc))
{
hResult = ResultFromScode(sc);
goto out;
}
// Get the instance handle, so that I can get the display strings off the resource file
hInst = lpABPLogon->hLibrary;
// Initialize the row
sRow.cValues = ivalootMax;
sRow.lpProps = rgsPropValue;
/*
* Fill the table
*
* we want to add two entries to the one-off table, so that we'll get:
*
* Microsoft Fax
* Fax
*/
// First do the 'Microsoft Fax'
// Name of the One-Off
rgsPropValue[ivalootPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
LoadStringA( hInst, IDS_MAWF_NAME, displayNameString, ARRAYSIZE(displayNameString));
rgsPropValue[ivalootPR_DISPLAY_NAME].Value.lpszA = displayNameString;
rgsPropValue[ivalootPR_ENTRYID].ulPropTag = PR_ENTRYID;
rgsPropValue[ivalootPR_ENTRYID].Value.bin.cb = SIZEOF(OOUSER_ENTRYID);
rgsPropValue[ivalootPR_ENTRYID].Value.bin.lpb = (LPVOID) &ONEOFF_EID;
// the hierarcy level (how far to indent a display name). I choose not to indent
rgsPropValue[ivalootPR_DEPTH].ulPropTag = PR_DEPTH;
rgsPropValue[ivalootPR_DEPTH].Value.l = 0;
// Selection flags. TRUE indicates this entry ID can be used in CreateEntry() call.
rgsPropValue[ivalootPR_SELECTABLE].ulPropTag = PR_SELECTABLE;
rgsPropValue[ivalootPR_SELECTABLE].Value.b = TRUE;
// The address type that would be generated by an entry
// created from this template
rgsPropValue[ivalootPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE_A;
#ifdef UNICODE
szEMT[0] = 0;
WideCharToMultiByte( CP_ACP, 0, lpszEMT, -1, szEMT, ARRAYSIZE(szEMT), NULL, NULL );
rgsPropValue[ivalootPR_ADDRTYPE].Value.lpszA = szEMT;
#else
rgsPropValue[ivalootPR_ADDRTYPE].Value.LPSZ = lpszEMT;
#endif
/*
* The display type associated with a recipient built with this template
*/
rgsPropValue[ivalootPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
rgsPropValue[ivalootPR_DISPLAY_TYPE].Value.lpszA = DT_MAILUSER;
/*
* The instance key of this row in this one-off table.
* using 1 for this row
*/
ulInstanceKey = 1;
rgsPropValue[ivalootPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
rgsPropValue[ivalootPR_INSTANCE_KEY].Value.bin.cb = SIZEOF(ULONG);
rgsPropValue[ivalootPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &ulInstanceKey;
(void) lpABPLogon->lpTDatOO->lpVtbl->HrModifyRow(
lpABPLogon->lpTDatOO,
&sRow);
#ifdef DO_MULTI_LEVEL_ADDRESS_BOOK_STUFF
// Now do the 'Fax'
// Name of the One-Off
rgsPropValue[ivalootPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
LoadStringA(hInst, IDS_FAX_NAME, displayNameString, ARRAYSIZE(displayNameString));
rgsPropValue[ivalootPR_DISPLAY_NAME].Value.lpszA = displayNameString;
// The entry ID for this template. MAPI will call OpenEntry() with this entry ID
// RtlZeroMemory(&EntryID, sizeof(OOUSER_ENTRYID));
rgsPropValue[ivalootPR_ENTRYID].ulPropTag = PR_ENTRYID;
rgsPropValue[ivalootPR_ENTRYID].Value.bin.cb = SIZEOF(OOUSER_ENTRYID);
rgsPropValue[ivalootPR_ENTRYID].Value.bin.lpb = (LPVOID) &ONEOFF_EID;
// the hierarcy level (how far to indent a display name). I choose not to indent
rgsPropValue[ivalootPR_DEPTH].ulPropTag = PR_DEPTH;
rgsPropValue[ivalootPR_DEPTH].Value.l = 1;
// Selection flags. TRUE indicates this entry ID can be used in CreateEntry() call.
rgsPropValue[ivalootPR_SELECTABLE].ulPropTag = PR_SELECTABLE;
rgsPropValue[ivalootPR_SELECTABLE].Value.b = TRUE;
// The address type that would be generated by an entry
// created from this template
rgsPropValue[ivalootPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE_A;
#ifdef UNICODE
rgsPropValue[ivalootPR_ADDRTYPE].Value.lpszA = szEMT;
#else
rgsPropValue[ivalootPR_ADDRTYPE].Value.LPSZ = lpszEMT;
#endif
/*
* The display type associated with a recipient built with this template
*/
rgsPropValue[ivalootPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
rgsPropValue[ivalootPR_DISPLAY_TYPE].Value.lpszA = DT_MAILUSER;
/*
* The instance key of this row in this one-off table.
* using 2 for this row
*/
ulInstanceKey = 2;
rgsPropValue[ivalootPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
rgsPropValue[ivalootPR_INSTANCE_KEY].Value.bin.cb = SIZEOF(ULONG);
rgsPropValue[ivalootPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &ulInstanceKey;
(void) lpABPLogon->lpTDatOO->lpVtbl->HrModifyRow(
lpABPLogon->lpTDatOO,
&sRow);
#endif
}
/*
* Get a view to return to the caller
*/
hResult = lpABPLogon->lpTDatOO->lpVtbl->HrGetView(
lpABPLogon->lpTDatOO,
NULL,
NULL,
0,
(LPMAPITABLE *) lppTable);
out:
LeaveCriticalSection(&lpABPLogon->cs);
DebugTraceResult(ABPLogon_GetOneOffTable, hResult);
return hResult;
}
/*************************************************************************
*
- ABPLOGON_Advise
-
* NYI
*
*
*/
STDMETHODIMP
ABPLOGON_Advise( LPABPLOGON lpABPLogon,
ULONG cbEntryID,
LPENTRYID lpEntryID,
ULONG ulEventMask,
LPMAPIADVISESINK lpAdviseSink,
ULONG FAR * lpulConnection
)
{
DebugTraceSc(ABPLOGON_Advise, MAPI_E_NO_SUPPORT);
return ResultFromScode(MAPI_E_NO_SUPPORT);
}
/*************************************************************************
*
- ABPLOGON_Unadvise
-
* NYI
*
*
*/
STDMETHODIMP
ABPLOGON_Unadvise(LPABPLOGON lpABPLogon, ULONG ulConnection)
{
DebugTraceSc(ABPLOGON_Unadvise, MAPI_E_NO_SUPPORT);
return ResultFromScode(MAPI_E_NO_SUPPORT);
}
/*************************************************************************
*
- ABPLOGON_PrepareRecips
-
* Takes a list of recipients and sets values for a requested list of
* properties (lpPropTagArray) on each of the recipients, from the respective
* address book entry of the recipient. If the recipient already has
* some properties set on it, those that exist on the address book entry
* will override the one that are on the recipient. Those that do NOT
* exist in the address book entry will stay.
*
*
*/
STDMETHODIMP
ABPLOGON_PrepareRecips( LPABPLOGON lpABPLogon,
ULONG ulFlags,
LPSPropTagArray lpPropTagArray,
LPADRLIST lpRecipList
)
{
HRESULT hResult = hrSuccess;
UINT iRecip;
UINT iProp;
ULONG cValues;
LPSPropValue lpspvUser = NULL;
LPSPropValue lpNewRecip = NULL;
LPMAPIPROP lpMAPIPropEntry = NULL;
SCODE sc = S_OK;
ULONG ulObjType;
BOOL fUselpspvUser;
if (!lpPropTagArray)
{
/*
* They only want us to update our entryID from ephemeral to
* permanent. Since ours are already permanent, we don't need to
* do anything.
*/
goto out;
}
/* loop through all the recipients */
for (iRecip = 0; iRecip < lpRecipList->cEntries; iRecip++)
{
LPUSR_ENTRYID lpEntryID = NULL;
ULONG cbEntryID;
LPSPropValue lpPropVal = NULL;
LPSPropValue rgpropvalsRecip = lpRecipList->aEntries[iRecip].rgPropVals;
ULONG cPropsRecip = lpRecipList->aEntries[iRecip].cValues;
/* For each recipient, find its entryid */
lpPropVal = PpropFindProp( rgpropvalsRecip, cPropsRecip, PR_ENTRYID );
if ( lpPropVal )
{
lpEntryID = (LPUSR_ENTRYID)lpPropVal->Value.bin.lpb;
cbEntryID = lpPropVal->Value.bin.cb;
}
else
continue;
/* Is it one of ours? */
if ( cbEntryID < CbNewENTRYID(0)
|| IsBadReadPtr( (LPVOID) lpEntryID, (UINT) cbEntryID ) )
{
continue; /* no, keep looking */
}
if ( memcmp( &(lpEntryID->muid), &muidABMAWF, SIZEOF(MAPIUID) ) )
continue; /* no, keep looking */
/* Try and open it. */
hResult = HrNewFaxUser( (LPMAILUSER *)&lpMAPIPropEntry,
&ulObjType,
cbEntryID,
(LPENTRYID) lpEntryID,
(LPABLOGON) lpABPLogon,
NULL,
lpABPLogon->hLibrary,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc
);
if ( HR_FAILED(hResult) )
{
/* Couldn't open it...; Ignore it and keep looking */
hResult = hrSuccess;
DebugTrace( "ABPLOGON_PrepareRecips sees a bad user entry ID\n" );
continue;
}
/* Get the properties requested */
hResult = lpMAPIPropEntry->lpVtbl->GetProps( lpMAPIPropEntry,
lpPropTagArray,
0, /* ansi */
&cValues, &lpspvUser );
/* No longer need lpMAPIPropEntry */
lpMAPIPropEntry->lpVtbl->Release(lpMAPIPropEntry);
lpMAPIPropEntry = NULL;
if (HR_FAILED(hResult))
{
/* Failed getting properties. Cleanup and ignore this entry */
hResult = hrSuccess;
continue;
}
hResult = hrSuccess;
Assert(cValues == lpPropTagArray->cValues);
/*
* This is the hard part.
* Merge the two property sets: lpspvUser and lpsPropVal. Note that
* both of these sets may have the same property - chances are they do.
* for these conflicts, lpspvUser should be the one we get the property
* from.
*
* Guess how big the resultant SPropValue array is, and allocate one of that
* size.
*/
sc = lpABPLogon->lpAllocBuff( (cValues + cPropsRecip) * SIZEOF( SPropValue ),
&lpNewRecip);
if (FAILED(sc))
{
/*
* Ok, to fail the call here. If we're running into out of memory conditions
* we're all in trouble.
*/
hResult = ResultFromScode( sc );
goto err;
}
/*
* Copy lpspvUser properties over to lpNewRecip
* Check each property in lpsvUser to ensure that it isn't PT_ERROR, if so
* find the propval in rgpropvalsRecip ( the [in] recip prop val array ),
* if it exists and use that property.
*/
for (iProp = 0; iProp < cValues; iProp++)
{
fUselpspvUser = TRUE;
if ( PROP_TYPE( lpspvUser[iProp].ulPropTag ) == PT_ERROR )
{
lpPropVal = PpropFindProp( rgpropvalsRecip, cPropsRecip,
lpPropTagArray->aulPropTag[iProp] );
if ( lpPropVal )
{
sc = PropCopyMore( lpNewRecip + iProp, lpPropVal,
lpABPLogon->lpAllocMore, lpNewRecip );
fUselpspvUser = FALSE;
}
}
if ( fUselpspvUser )
{
sc = PropCopyMore( lpNewRecip + iProp, lpspvUser + iProp,
lpABPLogon->lpAllocMore, lpNewRecip );
}
if (FAILED(sc))
{
if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
{
hResult = MakeResult(sc);
goto err;
}
/*
* Otherwise we've run into something wierd in the prop value array
* like PT_UNSPECIFIED, PT_NULL, or PT_OBJECT. In which case continue
* on.
*/
}
}
/* Done with lpspvUser */
lpABPLogon->lpFreeBuff( lpspvUser );
lpspvUser = NULL;
/*
* Copy those properties that aren't already in lpNewRecip
* from rgpropvalsRecip. Don't copy over the PT_ERROR prop vals
*/
for ( iProp = 0; iProp < cPropsRecip; iProp++ )
{
if ( PpropFindProp( lpNewRecip, cValues, rgpropvalsRecip[iProp].ulPropTag )
|| PROP_TYPE( rgpropvalsRecip[iProp].ulPropTag ) == PT_ERROR )
continue;
sc = PropCopyMore( lpNewRecip + cValues, rgpropvalsRecip + iProp,
lpABPLogon->lpAllocMore, lpNewRecip );
if ( FAILED( sc ) )
{
if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
{
hResult = ResultFromScode( sc );
goto err;
}
/*
* Otherwise we've run into something wierd in the prop value array
* like PT_UNSPECIFIED, PT_NULL, or PT_OBJECT. In which case continue
* on.
*/
}
cValues++;
}
/*
* Replace the AdrEntry in the AdrList with this new lpNewRecip. And
* don't forget the cValues!
*/
lpRecipList->aEntries[iRecip].rgPropVals = lpNewRecip;
lpRecipList->aEntries[iRecip].cValues = cValues;
/* Finally, free up the old AdrEntry. */
lpABPLogon->lpFreeBuff( rgpropvalsRecip );
}
out:
DebugTraceResult( ABPLOGON_PrepareRecips, hResult );
return hResult;
err:
lpABPLogon->lpFreeBuff( lpspvUser );
goto out;
}
/*************************************************************************
* LpMuidFromLogon -
* Returns the particular ABPLOGON object's unique identifier.
*
*/
LPMAPIUID
LpMuidFromLogon(LPABLOGON lpABLogon)
{
LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
AssertSz(!IsBadReadPtr(lpABPLogon, SIZEOF(ABPLOGON)), "Bad logon object!\n");
return (&(lpABPLogon->muidID));
}
/*************************************************************************
* HrLpszGetCurrentFileName -
* Returns a copy of the current .FAB file pointed to by this logon object.
*
*/
HRESULT
HrLpszGetCurrentFileName(LPABLOGON lpABLogon, LPTSTR * lppszFileName)
{
LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
SCODE sc;
HRESULT hResult = hrSuccess;
AssertSz(!IsBadReadPtr(lpABPLogon, SIZEOF(ABPLOGON)), "FAB: Bad logon object!\n");
AssertSz(!IsBadWritePtr(lppszFileName, SIZEOF(LPTSTR)), "FAB: Bad dest string!\n");
EnterCriticalSection(&lpABPLogon->cs);
sc = lpABPLogon->lpAllocBuff( (lstrlen(lpABPLogon->lpszFileName)+1)*SIZEOF(TCHAR), lppszFileName);
if (FAILED(sc))
{
hResult = ResultFromScode(sc);
goto ret;
}
lstrcpy( *lppszFileName, lpABPLogon->lpszFileName);
ret:
LeaveCriticalSection(&lpABPLogon->cs);
DebugTraceResult(HrLpszGetCurrentFileName, hResult);
return hResult;
}
/*
* HrReplaceCurrentFileName -
* Replaces the current file name associated with this logon object and tries
* to save it all away in the profile.
*/
HRESULT
HrReplaceCurrentFileName(LPABLOGON lpABLogon, LPTSTR lpszNewFile)
{
LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
HRESULT hResult = hrSuccess;
LPPROFSECT lpProfSect = NULL;
LPTSTR lpstrT;
SCODE sc;
SPropValue rgspv[1];
#ifdef UNICODE
CHAR szAnsiFileName[ MAX_PATH ];
#endif
AssertSz(!IsBadReadPtr(lpABPLogon, SIZEOF(ABPLOGON)), "Bad logon object!\n");
EnterCriticalSection(&lpABPLogon->cs);
/*
* FAB file name has changed have to update profile and objects
*/
if (lstrcmp(lpszNewFile, lpABPLogon->lpszFileName))
{
/*
* Open the private profile section...
*/
hResult = lpABPLogon->lpMapiSup->lpVtbl->OpenProfileSection(
lpABPLogon->lpMapiSup,
NULL,
MAPI_MODIFY,
&lpProfSect);
if (HR_FAILED(hResult))
{
/*
* Shouldn't get here, but in case I do, just...
*/
goto ret;
}
/*
* Save the new name back into the profile
*/
rgspv[0].ulPropTag = PR_FAB_FILE_A;
#ifdef UNICODE
szAnsiFileName[0] = 0;
WideCharToMultiByte( CP_ACP, 0, lpszNewFile, -1, szAnsiFileName, ARRAYSIZE(szAnsiFileName), NULL, NULL );
rgspv[0].Value.lpszA = szAnsiFileName;
#else
rgspv[0].Value.LPSZ = lpszNewFile;
#endif
/*
* Don't care if I can save it in the profile or not.
* Saving it's a nice to have, but absolutely required
* for operation of this particular provider.
*/
(void) lpProfSect->lpVtbl->SetProps(
lpProfSect,
1, // ansi
rgspv,
NULL);
lpProfSect->lpVtbl->Release(lpProfSect);
/*
* Allocate and copy this new one
*/
sc = lpABPLogon->lpAllocBuff( (lstrlen(lpszNewFile)+1)*SIZEOF(TCHAR), &lpstrT);
if (FAILED(sc))
{
hResult = ResultFromScode(sc);
goto ret;
}
lstrcpy( lpstrT, lpszNewFile );
/*
* Free up the old one...
*/
lpABPLogon->lpFreeBuff(lpABPLogon->lpszFileName);
/*
* Put in the new one.
*/
lpABPLogon->lpszFileName = lpstrT;
/*
* Update the hierarchy table
*/
hResult = HrBuildRootHier((LPABLOGON)lpABPLogon, NULL);
}
ret:
LeaveCriticalSection(&lpABPLogon->cs);
DebugTraceResult(HrReplaceCurrentFileName, hResult);
return hResult;
}
/*
* GenerateContainerDN -
* Common code for generating the display name of the single
* container exposed from this logon object.
*/
#ifdef SAB // from sample AB
void
GenerateContainerDN(LPABLOGON lpABLogon, LPTSTR lpszName)
{
LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
LPTSTR lpszFileName;
int ich;
AssertSz(!IsBadReadPtr(lpABPLogon, SIZEOF(ABPLOGON)), "Bad logon object!\n");
EnterCriticalSection(&lpABPLogon->cs);
lpszFileName = lpABPLogon->lpszFileName;
// get the filename without the path
for (ich = lstrlen(lpszFileName) - 1; ich >= 0; ich--)
{
if (lpszFileName[ich] == TEXT('\\'))
break;
}
// skip past the backslash
ich++;
wsprintf(lpszName, TEXT("FAB using %s"), lpszFileName + ich);
LeaveCriticalSection(&lpABPLogon->cs);
}
#else // Fax AB
void
GenerateContainerDN(HINSTANCE hInst, LPTSTR lpszName)
{
LoadString (hInst, IDS_ADDRESS_BOOK_ROOT_CONT, lpszName, MAX_DISPLAY_NAME);
}
#endif
/*
- HrBuildRootHier
-
*
* Builds up the root hierarchy for the Microsoft At Work Fax Address Book.
*
*
*/
enum { ivalPR_DISPLAY_NAME = 0,
ivalPR_ENTRYID,
ivalPR_DEPTH,
ivalPR_OBJECT_TYPE,
ivalPR_DISPLAY_TYPE,
ivalPR_CONTAINER_FLAGS,
ivalPR_INSTANCE_KEY,
ivalPR_AB_PROVIDER_ID,
cvalMax };
static const SizedSPropTagArray(cvalMax, tagaRootColSet) =
{
cvalMax,
{
PR_DISPLAY_NAME_A,
PR_ENTRYID,
PR_DEPTH,
PR_OBJECT_TYPE,
PR_DISPLAY_TYPE,
PR_CONTAINER_FLAGS,
PR_INSTANCE_KEY,
PR_AB_PROVIDER_ID
}
};
HRESULT
HrBuildRootHier(LPABLOGON lpABLogon, LPMAPITABLE * lppMAPITable)
{
HRESULT hResult;
SCODE sc;
SRow sRow;
SPropValue rgsPropValue[cvalMax];
ULONG ulInstanceKey = 1;
TCHAR szBuf[MAX_PATH];
#ifdef UNICODE
CHAR szAnsiBuf[MAX_PATH];
#endif
HINSTANCE hInst;
LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
DIR_ENTRYID eidRoot = { {0, 0, 0, 0},
MUIDABMAWF,
MAWF_VERSION,
MAWF_DIRECTORY };
EnterCriticalSection(&lpABPLogon->cs);
hInst = lpABPLogon->hLibrary;
/*
* See if we have a TaD yet
*/
if (!lpABPLogon->lpTDatRoot)
{
/* Create a Table Data object */
if ( sc = CreateTable((LPIID) &IID_IMAPITableData,
lpABPLogon->lpAllocBuff,
lpABPLogon->lpAllocMore,
lpABPLogon->lpFreeBuff,
lpABPLogon->lpMalloc,
0,
PR_ENTRYID,
(LPSPropTagArray) &tagaRootColSet,
&(lpABPLogon->lpTDatRoot))
)
{
hResult = ResultFromScode(sc);
goto out;
}
}
/* Constants */
sRow.cValues = cvalMax;
sRow.lpProps = rgsPropValue;
/* First, the Display Name stuff*/
rgsPropValue[ivalPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
#ifdef SAB
GenerateContainerDN((LPABLOGON) lpABPLogon, szBuf);
#else
GenerateContainerDN(hInst, szBuf);
#endif
#ifdef UNICODE
szAnsiBuf[0] = 0;
WideCharToMultiByte( CP_ACP, 0, szBuf, -1, szAnsiBuf, ARRAYSIZE(szAnsiBuf), NULL, NULL );
rgsPropValue[ivalPR_DISPLAY_NAME].Value.lpszA = szAnsiBuf;
#else
rgsPropValue[ivalPR_DISPLAY_NAME].Value.lpszA = szBuf;
#endif
/*
* For each FAB logon object associated with it's init object,
* we have a unique MAPIUID. It's the only thing that distinguishes
* one FAB entryid from another in the merged hierarchy table that
* MAPI generates.
*/
rgsPropValue[ivalPR_ENTRYID].ulPropTag = PR_ENTRYID;
eidRoot.muidID = lpABPLogon->muidID;
rgsPropValue[ivalPR_ENTRYID].Value.bin.cb = SIZEOF(DIR_ENTRYID);
rgsPropValue[ivalPR_ENTRYID].Value.bin.lpb = (LPVOID) &eidRoot;
rgsPropValue[ivalPR_DEPTH].ulPropTag = PR_DEPTH;
rgsPropValue[ivalPR_DEPTH].Value.l = 0;
rgsPropValue[ivalPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
rgsPropValue[ivalPR_OBJECT_TYPE].Value.l = MAPI_ABCONT;
rgsPropValue[ivalPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
rgsPropValue[ivalPR_DISPLAY_TYPE].Value.l = DT_NOT_SPECIFIC;
rgsPropValue[ivalPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS;
rgsPropValue[ivalPR_CONTAINER_FLAGS].Value.l = AB_RECIPIENTS | AB_UNMODIFIABLE;
rgsPropValue[ivalPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
rgsPropValue[ivalPR_INSTANCE_KEY].Value.bin.cb = SIZEOF(ULONG);
rgsPropValue[ivalPR_INSTANCE_KEY].Value.bin.lpb = (LPBYTE) &ulInstanceKey;
rgsPropValue[ivalPR_AB_PROVIDER_ID].ulPropTag = PR_AB_PROVIDER_ID;
rgsPropValue[ivalPR_AB_PROVIDER_ID].Value.bin.cb = SIZEOF(MAPIUID);
rgsPropValue[ivalPR_AB_PROVIDER_ID].Value.bin.lpb = (LPBYTE) &muidABMAWF;
hResult = lpABPLogon->lpTDatRoot->lpVtbl->HrModifyRow( lpABPLogon->lpTDatRoot, &sRow );
if (HR_FAILED(hResult))
goto out;
/*
* Check to see if they want a view returned as well
*/
if (lppMAPITable)
{
/* Get a view from the Table data object */
hResult =
lpABPLogon->lpTDatRoot->lpVtbl->HrGetView(
lpABPLogon->lpTDatRoot,
NULL,
NULL,
0,
lppMAPITable);
}
out:
LeaveCriticalSection(&lpABPLogon->cs);
DebugTraceResult(HrBuildRootHier, hResult);
return hResult;
}
/*
* Checks to see if the file passed in is still the actual file that
* should be browsed.
*/
BOOL
FEqualFABFiles( LPABLOGON lpABLogon,
LPTSTR lpszFileName)
{
LPABPLOGON lpABPLogon = (LPABPLOGON) lpABLogon;
BOOL fEqual;
AssertSz(!IsBadReadPtr(lpABPLogon, SIZEOF(ABPLOGON)), "Bad logon object!\n");
EnterCriticalSection(&lpABPLogon->cs);
fEqual = !lstrcmp( lpszFileName, lpABPLogon->lpszFileName );
LeaveCriticalSection(&lpABPLogon->cs);
return fEqual;
}