1814 lines
50 KiB
C
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;
|
|
}
|