Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1783 lines
57 KiB

/*
* MailUser.C - mostly just a copy of WRAP.C
*
* Wrapper for mailuser and distlist objects.
*
* Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved.
*
*/
#include "_apipch.h"
extern OlkContInfo *FindContainer(LPIAB lpIAB, ULONG cbEID, LPENTRYID lpEID);
/*********************************************************************
*
* The actual Wrapped IMAPIProp methods
*
*/
//
// Wrapped IMAPIProp jump table is defined here...
// Try to use as much of IAB as possible.
//
MailUser_Vtbl vtblMAILUSER = {
VTABLE_FILL
MailUser_QueryInterface,
(MailUser_AddRef_METHOD *) WRAP_AddRef,
MailUser_Release,
(MailUser_GetLastError_METHOD *) IAB_GetLastError,
MailUser_SaveChanges,
MailUser_GetProps,
MailUser_GetPropList,
MailUser_OpenProperty,
MailUser_SetProps,
MailUser_DeleteProps,
MailUser_CopyTo,
MailUser_CopyProps,
MailUser_GetNamesFromIDs,
MailUser_GetIDsFromNames,
};
//
// Interfaces supported by this object
//
#define MailUser_cInterfaces 2
LPIID MailUser_LPIID[MailUser_cInterfaces] =
{
(LPIID)&IID_IMailUser,
(LPIID)&IID_IMAPIProp
};
//
// Interfaces supported by this object
//
#define DistList_cInterfaces 3
LPIID DistList_LPIID[DistList_cInterfaces] =
{
(LPIID)&IID_IDistList,
(LPIID)&IID_IMailUser,
(LPIID)&IID_IMAPIProp
};
HRESULT HrValidateMailUser(LPMailUser lpMailUser);
void MAILUSERFreeContextData(LPMailUser lpMailUser);
void MAILUSERAssociateContextData(LPMAILUSER lpMailUser, LPWABEXTDISPLAY lpWEC);
const TCHAR szMAPIPDL[] = TEXT("MAPIPDL");
extern BOOL bDNisByLN;
// --------
// IUnknown
STDMETHODIMP
MailUser_QueryInterface(LPMailUser lpMailUser,
REFIID lpiid,
LPVOID * lppNewObj)
{
ULONG iIID;
#ifdef PARAMETER_VALIDATION
// Check to see if it has a jump table
if (IsBadReadPtr(lpMailUser, sizeof(LPVOID))) {
// No jump table found
return(ResultFromScode(E_INVALIDARG));
}
// Check to see if the jump table has at least sizeof IUnknown
if (IsBadReadPtr(lpMailUser->lpVtbl, 3 * sizeof(LPVOID))) {
// Jump table not derived from IUnknown
return(ResultFromScode(E_INVALIDARG));
}
// Check to see that it's MailUser_QueryInterface
if (lpMailUser->lpVtbl->QueryInterface != MailUser_QueryInterface) {
// Not my jump table
return(ResultFromScode(E_INVALIDARG));
}
// Is there enough there for an interface ID?
if (IsBadReadPtr(lpiid, sizeof(IID))) {
DebugTraceSc(MailUser_QueryInterface, E_INVALIDARG);
return(ResultFromScode(E_INVALIDARG));
}
// Is there enough there for a new object?
if (IsBadWritePtr(lppNewObj, sizeof(LPMailUser))) {
DebugTraceSc(MailUser_QueryInterface, E_INVALIDARG);
return(ResultFromScode(E_INVALIDARG));
}
#endif // PARAMETER_VALIDATION
EnterCriticalSection(&lpMailUser->cs);
// See if the requested interface is one of ours
// First check with IUnknown, since we all have to support that one...
if (!memcmp(lpiid, &IID_IUnknown, sizeof(IID))) {
goto goodiid; // GROSS! Jump into a for loop!
}
// Now look through all the iids associated with this object, see if any match
for(iIID = 0; iIID < lpMailUser->cIID; iIID++)
if (!memcmp(lpMailUser->rglpIID[iIID], lpiid, sizeof(IID))) {
goodiid:
//
// It's a match of interfaces, we support this one then...
//
++lpMailUser->lcInit;
*lppNewObj = lpMailUser;
LeaveCriticalSection(&lpMailUser->cs);
return 0;
}
//
// No interface we've heard of...
//
LeaveCriticalSection(&lpMailUser->cs);
*lppNewObj = NULL; // OLE requires NULLing out parm on failure
DebugTraceSc(MailUser_QueryInterface, E_NOINTERFACE);
return(ResultFromScode(E_NOINTERFACE));
}
STDMETHODIMP_(ULONG)
MailUser_Release (LPMailUser lpMailUser)
{
#if !defined(NO_VALIDATION)
//
// Make sure the object is valid.
//
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, Release, lpVtbl)) {
return(1);
}
#endif
EnterCriticalSection(&lpMailUser->cs);
--lpMailUser->lcInit;
if (lpMailUser->lcInit == 0) {
// Free any context-menu extension data associated with this mailuser
MAILUSERFreeContextData(lpMailUser);
UlRelease(lpMailUser->lpPropData);
//
// Need to free the object
//
LeaveCriticalSection(&lpMailUser->cs);
DeleteCriticalSection(&lpMailUser->cs);
FreeBufferAndNull(&lpMailUser);
return(0);
}
LeaveCriticalSection(&lpMailUser->cs);
return(lpMailUser->lcInit);
}
// IProperty
STDMETHODIMP
MailUser_SaveChanges(LPMailUser lpMailUser,
ULONG ulFlags)
{
HRESULT hr = hrSuccess;
ULONG ulcValues = 0;
LPSPropValue lpPropArray = NULL, lpspv = NULL, lpPropsOld = NULL, lpPropNew = NULL;
LPSPropTagArray lpProps = NULL;
SPropertyRestriction PropRes;
SPropValue Prop = {0};
ULONG i, j;
ULONG iDisplayName = NOT_FOUND;
ULONG iEmailAddress = NOT_FOUND;
ULONG iDuplicate = 0;
ULONG ulObjType = 0;
BOOL bNewRecord = FALSE;
BOOL fReplace = FALSE;
ULONG ulCount = 0, ulcProps = 0, ulcOld = 0, ulcNew;
LPSBinary rgsbEntryIDs = NULL;
SPropValue OneProp;
BOOL fNewEntry = TRUE;
BOOL fDuplicate = FALSE;
SCODE sc;
SBinary sbEID = {0};
LPSBinary lpsbEID = NULL;
FILETIME ftOldModTime = {0};
FILETIME ftCurrentModTime = {0};
BOOL bSwap = FALSE;
#if !defined(NO_VALIDATION)
// Make sure the object is valid.
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, SaveChanges, lpVtbl)) {
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif
#ifndef DONT_ADDREF_PROPSTORE
if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpMailUser->lpIAB->lpPropertyStore)))) {
hr = ResultFromScode(sc);
goto exitNotAddRefed;
}
#endif
//
//$REVIEW how do we handle the FORCE_SAVE flag ?
//
//
// check read write access ...
//
if (lpMailUser->ulObjAccess == IPROP_READONLY) {
// error - cant save changes
hr = MAPI_E_NO_ACCESS;
goto exit;
}
// If this is a One-Off, we cannot save changes
if (! lpMailUser->lpIAB->lpPropertyStore) {
hr = ResultFromScode(MAPI_E_NO_SUPPORT);
goto exit;
}
//
// Validate the properties for this item
//
if (HR_FAILED(hr = HrValidateMailUser(lpMailUser))) {
goto exit;
}
// see if this entry has an old modification time .. we would check that time in case of a
// merge ..
{
LPSPropValue lpProp = NULL;
if(!HR_FAILED(HrGetOneProp((LPMAPIPROP)lpMailUser, PR_LAST_MODIFICATION_TIME, &lpProp)))
{
CopyMemory(&ftOldModTime, &(lpProp->Value.ft), sizeof(ftOldModTime));
MAPIFreeBuffer(lpProp);
}
}
// Put in the modification time
OneProp.ulPropTag = PR_LAST_MODIFICATION_TIME;
GetSystemTimeAsFileTime(&OneProp.Value.ft);
if(!ftOldModTime.dwLowDateTime && !ftOldModTime.dwHighDateTime)
CopyMemory(&ftOldModTime, &OneProp.Value.ft, sizeof(ftOldModTime)); // if we dont have a mod time, use NOW
if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(
lpMailUser,
1, // cValues
&OneProp, // lpPropArray
NULL))) { // lppProblems
DebugTraceResult( TEXT("SetProps(PR_LAST_MODIFICATION_TIME)"), hr);
goto exit;
}
// BUGBUG: If SaveChanges fails after this, the PR_MODIFICATION_TIME on the
// open object will still be updated, even though it no longer matches
// the persistent copy of the object. I can live with this since it
// really simplifies the code.
// if this is a new entry and there is a folder parent for it,
// add the folder parent's entryid to this entry
// This will be persisted when we do the write record
// Once write record returns a valid entryid, we can update the folder to
// make this new item a part of it
if (fNewEntry && bIsWABSessionProfileAware(lpMailUser->lpIAB) &&
//bAreWABAPIProfileAware(lpMailUser->lpIAB) &&
lpMailUser->pmbinOlk&& lpMailUser->pmbinOlk->lpb && lpMailUser->pmbinOlk->cb)
{
AddFolderParentEIDToItem(lpMailUser->lpIAB,
lpMailUser->pmbinOlk->cb,
(LPENTRYID) lpMailUser->pmbinOlk->lpb,
(LPMAPIPROP)lpMailUser, 0, NULL);
}
//
// We want a lpPropArray that contains everything but the PR_SEARCH_KEY
//
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetPropList( lpMailUser, MAPI_UNICODE, &lpProps)))
goto exit;
if(lpProps)
{
for(i=0;i<lpProps->cValues;i++)
{
if(lpProps->aulPropTag[i] == PR_SEARCH_KEY)
{
for(j=i;j<lpProps->cValues-1;j++)
lpProps->aulPropTag[j] = lpProps->aulPropTag[j+1];
lpProps->cValues--;
break;
}
}
}
//
// Get a LPSPropValue array of all the properties pertaining to this
// entry
//
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(
lpMailUser,
lpProps, // LPSPropTagArray - NULL returns all
MAPI_UNICODE, // flags
&ulcValues,
&lpPropArray)))
{
// DebugPrintError(("GetProps -> %x\n", hr));
goto exit;
}
//
// Determine the entryid of this thing
//
for(i = 0; i < ulcValues; i++) {
if (lpPropArray[i].ulPropTag == PR_DISPLAY_NAME) {
// We use DisplayName as our uniqueness key for Strict or Loose match tests
iDisplayName = i;
}
if (lpPropArray[i].ulPropTag == PR_EMAIL_ADDRESS) {
// We use email address as our secondary uniqueness key for Strict match tests
iEmailAddress = i;
}
if (lpPropArray[i].ulPropTag == PR_ENTRYID) {
if ((lpPropArray[i].Value.bin.cb != 0) &&
(lpPropArray[i].Value.bin.lpb != NULL))
{
sbEID.cb = lpPropArray[i].Value.bin.cb;
sbEID.lpb = lpPropArray[i].Value.bin.lpb;
// If this is a One-Off, we cannot save changes
if(WAB_ONEOFF == IsWABEntryID(sbEID.cb,(LPENTRYID)sbEID.lpb,NULL,NULL,NULL, NULL, NULL))
{
hr = ResultFromScode(MAPI_E_NO_SUPPORT);
goto exit;
}
fNewEntry = FALSE;
continue;
} else {
lpPropArray[i].Value.bin.cb = 0;
}
}
if (lpPropArray[i].ulPropTag == PR_OBJECT_TYPE) {
switch(lpPropArray[i].Value.l) {
case MAPI_MAILUSER:
ulObjType = RECORD_CONTACT;
break;
case MAPI_DISTLIST:
ulObjType = RECORD_DISTLIST;
break;
case MAPI_ABCONT:
ulObjType = RECORD_CONTAINER;
break;
default:
// DebugPrintError(("Unknown Object Type: %d\n",lpPropArray[i].Value.l));
hr = ResultFromScode(MAPI_E_INVALID_OBJECT);
goto exit;
break;
}
}
}
Assert(iDisplayName != NOT_FOUND);
if (fNewEntry && (lpMailUser->ulCreateFlags & (CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE))) {
// Need to test DisplayName against current store... Use FindRecord.
// Only need to test if this is a new record.
PropRes.lpProp = &(lpPropArray[iDisplayName]);
PropRes.relop = RELOP_EQ;
PropRes.ulPropTag = PR_DISPLAY_NAME;
ulCount = 0; // find them all
// Search the property store
Assert(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore);
if (HR_FAILED(hr = FindRecords(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
lpMailUser->pmbinOlk, // pmbinFolder
0, // ulFlags
TRUE, // Always TRUE
&PropRes, // Propertyrestriction
&ulCount, // IN: number of matches to find, OUT: number found
&rgsbEntryIDs))) {
DebugTraceResult(FindRecords, hr);
goto exit;
}
if (ulCount) { // Was a match found?
fDuplicate = TRUE;
iDuplicate = 0;
if (lpMailUser->ulCreateFlags & CREATE_CHECK_DUP_STRICT && iEmailAddress != NOT_FOUND) {
// Check the primary email address too
fDuplicate = FALSE;
for (i = 0; i < ulCount && ! fDuplicate; i++) {
// Look at each entry until a match for email address is found
// Read the record
if (HR_FAILED(hr = ReadRecord(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
&(rgsbEntryIDs[i]), // EntryID
0, // ulFlags
&ulcProps, // number of props returned
&lpspv))) { // properties returned
DebugTraceResult(MailUser_SaveChanges:ReadRecord, hr);
// ignore it and move on
continue;
}
if (ulcProps) {
Assert(lpspv);
if (lpspv) {
// Look for PR_EMAIL_ADDRESS
for (j = 0; j < ulcProps; j++) {
if (lpspv[j].ulPropTag == PR_EMAIL_ADDRESS) {
// Compare the two:
if (! lstrcmpi(lpspv[j].Value.LPSZ,
lpPropArray[iEmailAddress].Value.LPSZ)) {
fDuplicate = TRUE;
iDuplicate = i; // entry to delete on CREATE_REPLACE
}
break;
}
}
// Free the prop array
ReadRecordFreePropArray( lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
ulcProps,
&lpspv);
}
}
}
}
if (fDuplicate) {
// Depending on the flags, we should do something special here.
// Found a duplicate.
if (lpMailUser->ulCreateFlags & CREATE_REPLACE) {
fReplace = TRUE;
} else {
// Fail
DebugTrace(TEXT("SaveChanges found collision... failed\n"));
hr = ResultFromScode(MAPI_E_COLLISION);
goto exit;
}
}
}
}
//
// Write the record to the property store
//
if(sbEID.cb)
lpsbEID = &sbEID;
else if(fReplace)
{
lpsbEID = &(rgsbEntryIDs[iDuplicate]);
Prop.ulPropTag = PR_ENTRYID;
Prop.Value.bin = *lpsbEID;
if (lpMailUser->ulCreateFlags & CREATE_MERGE)
{
// We're now asking the user if he wants to replace - ideally we should just merge
// the new entry with the old entry giving priority to the new data over the old
// This way the user doesnt lose information already on the contact and it becomes
// much easier to update the information through vCards and LDAP etc
// TO do the merge, we get all the existing data on the contact
if (HR_FAILED(hr = ReadRecord(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
&(rgsbEntryIDs[iDuplicate]),
0,
&ulcProps,
&lpspv)))
{
DebugTrace(TEXT("SaveChanges: ReadRecord Failed\n"));
goto exit;
}
for(i=0;i<ulcProps;i++)
{
if(lpspv[i].ulPropTag == PR_LAST_MODIFICATION_TIME)
{
CopyMemory(&ftCurrentModTime, &(lpspv[i].Value.ft), sizeof(ftCurrentModTime));
lpspv[i].ulPropTag = PR_NULL;
break;
}
}
sc = ScMergePropValues( 1, &Prop, // these are added just to make sure the ScMerge wont fail
ulcProps, lpspv,
&ulcOld, &lpPropsOld);
ReadRecordFreePropArray( lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
ulcProps, &lpspv);
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto exit;
}
}
else
{
ulcOld = 1;
lpPropsOld = &Prop;
}
// Nullify any new PR_ENTRYID prop on the new prop set so that
// we retain the old EID
for(i=0;i<ulcValues;i++)
{
if(lpPropArray[i].ulPropTag == PR_ENTRYID)
{
lpPropArray[i].ulPropTag = PR_NULL;
break;
}
}
if (fReplace && lpMailUser->ulCreateFlags & CREATE_MERGE)
{
// Check the FileTimes to see who stomps on whom
if(CompareFileTime(&ftOldModTime, &ftCurrentModTime)<0) // current changes are later than original ones
{
// swap the 2 prop arrays
ULONG ulTemp = ulcValues;
LPSPropValue lpTemp =lpPropArray;
ulcValues = ulcOld; ulcOld = ulTemp;
lpPropArray = lpPropsOld; lpPropsOld = lpTemp;
bSwap = TRUE;
}
}
// Now merge the new props with the old props
sc = ScMergePropValues( ulcOld, lpPropsOld,
ulcValues, lpPropArray,
&ulcNew, &lpPropNew);
// undo a swap above so we can free memory properly
if(bSwap)
{
// swap the 2 prop arrays
ULONG ulTemp = ulcValues;
LPSPropValue lpTemp =lpPropArray;
ulcValues = ulcOld; ulcOld = ulTemp;
lpPropArray = lpPropsOld; lpPropsOld = lpTemp;
}
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto exit;
}
MAPIFreeBuffer(lpPropArray);
lpPropArray = lpPropNew;
ulcValues = ulcNew;
lpPropNew = NULL;
ulcNew = 0;
}
Assert(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore);
// One last thing to check is that if this is a new record, it shouldn't have a record key and
// instance key set on it and if it is an existing record, the record key and instance key should
// be identical to the entryid
{
ULONG iEntryID = NOT_FOUND;
ULONG iRecordKey = NOT_FOUND;
ULONG iInstanceKey = NOT_FOUND;
for(i=0;i<ulcValues;i++)
{
switch(lpPropArray[i].ulPropTag)
{
case PR_ENTRYID:
iEntryID = i;
break;
case PR_RECORD_KEY:
iRecordKey = i;
break;
case PR_INSTANCE_KEY:
iInstanceKey = i;
break;
}
}
if(iEntryID == NOT_FOUND || !lpPropArray[iEntryID].Value.bin.cb)
{
if(iRecordKey != NOT_FOUND)
lpPropArray[iRecordKey].ulPropTag = PR_NULL;
if(iInstanceKey != NOT_FOUND)
lpPropArray[iInstanceKey].ulPropTag = PR_NULL;
}
else
{
if(iRecordKey != NOT_FOUND)
{
lpPropArray[iRecordKey].Value.bin.cb = lpPropArray[iEntryID].Value.bin.cb;
lpPropArray[iRecordKey].Value.bin.lpb = lpPropArray[iEntryID].Value.bin.lpb;
}
if(iInstanceKey != NOT_FOUND)
{
lpPropArray[iInstanceKey].Value.bin.cb = lpPropArray[iEntryID].Value.bin.cb;
lpPropArray[iInstanceKey].Value.bin.lpb = lpPropArray[iEntryID].Value.bin.lpb;
}
}
}
// Just to make sure we knock out all the PR_NULL properties,
// recreate a new version of the PropValueArray if any PR_NULL exist
for(i=0;i<ulcValues;i++)
{
if(lpPropArray[i].ulPropTag == PR_NULL)
{
ULONG ulcNew = 0;
LPSPropValue lpPropsNew = NULL;
SPropValue Prop = {0};
Prop.ulPropTag = PR_NULL;
if(!(sc = ScMergePropValues( 1, &Prop, // these are added just to make sure the ScMerge wont fail
ulcValues, lpPropArray,
&ulcNew, &lpPropsNew)))
{
if(lpPropArray)
FreeBufferAndNull(&lpPropArray);
ulcValues = ulcNew;
lpPropArray = lpPropsNew;
}
break;
}
}
{
OlkContInfo * polkci = NULL;
LPSBinary lpsbContEID = NULL;
if(lpMailUser->pmbinOlk)
{
polkci = FindContainer( lpMailUser->lpIAB, lpMailUser->pmbinOlk->cb, (LPENTRYID)lpMailUser->pmbinOlk->lpb);
if(polkci)
lpsbContEID = polkci->lpEntryID;
}
if (HR_FAILED(hr = WriteRecord( lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
lpsbContEID,
IN OUT &lpsbEID,
IN 0, //flags - reserved
IN ulObjType,
IN ulcValues,
IN lpPropArray)))
{
// DebugPrintError(("WriteRecord Failed: %x\n",hr));
//$REVIEW writerecord will tell us if MAPI_E_OBJECT_DELETED
// how to get MAPI_E_OBJECT_CHANGED or MAPI_E_OBJECT_DELETED ?
goto exit;
}
}
// if sbEID.cb was 0, we now have a new entryid in the lpsbEID struct
if(!sbEID.cb && !fReplace)
{
sbEID.lpb = lpsbEID->lpb;
sbEID.cb = lpsbEID->cb;
}
// if this is a first time save of a new entry, then if profiles are enabled and this entry
// has a folder parent marked on it, add the new entryid to the folder parent ...
if(fNewEntry && bIsWABSessionProfileAware(lpMailUser->lpIAB) &&
//bAreWABAPIProfileAware(lpMailUser->lpIAB) &&
lpMailUser->pmbinOlk&& lpMailUser->pmbinOlk->lpb && lpMailUser->pmbinOlk->cb)
{
AddItemEIDToFolderParent(lpMailUser->lpIAB,
lpMailUser->pmbinOlk->cb,
(LPENTRYID)lpMailUser->pmbinOlk->lpb,
sbEID.cb,
(LPENTRYID)sbEID.lpb);
}
// If this is a first time save, set the local entryid prop.
if (fReplace || fNewEntry)
{
OneProp.ulPropTag = PR_ENTRYID;
OneProp.Value.bin = (fReplace ? *lpsbEID : sbEID);
// Use the low-level SetProps to avoid the PR_ENTRYID filter.
if (HR_FAILED(hr = lpMailUser->lpPropData->lpVtbl->SetProps(
lpMailUser->lpPropData,
1, // cValues
&OneProp, // lpPropArray
NULL))) // lppProblems
{
DebugTraceResult( TEXT("SetProps(PR_ENTRYID)"), hr);
goto exit;
}
}
if (ulFlags & KEEP_OPEN_READWRITE) {
lpMailUser->ulObjAccess = IPROP_READWRITE;
} else {
//$REVIEW
// whether the flag was READONLY or there was no flag,
// we'll make the future access now READONLY
//
lpMailUser->ulObjAccess = IPROP_READONLY;
}
exit:
#ifndef DONT_ADDREF_PROPSTORE
ReleasePropertyStore(lpMailUser->lpIAB->lpPropertyStore);
exitNotAddRefed:
#endif
FreeEntryIDs(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
ulCount,
rgsbEntryIDs);
FreeBufferAndNull(&lpPropArray);
FreeBufferAndNull(&lpProps);
FreeBufferAndNull(&lpPropNew);
if(lpMailUser->ulCreateFlags & CREATE_MERGE)
FreeBufferAndNull(&lpPropsOld);
if(lpsbEID != &sbEID && !fReplace)
FreeEntryIDs(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
1,
lpsbEID);
if ((HR_FAILED(hr)) && (ulFlags & MAPI_DEFERRED_ERRORS)) {
//$REVIEW : this is a grossly trivial handling of MAPI_DEFERRED_ERRORS ..
// BUGBUG: In fact, it isn't handling the errors at all!
//
hr = hrSuccess;
}
return(hr);
}
STDMETHODIMP
MailUser_GetProps(LPMailUser lpMailUser,
LPSPropTagArray lpPropTagArray,
ULONG ulFlags,
ULONG * lpcValues,
LPSPropValue * lppPropArray)
{
#if !defined(NO_VALIDATION)
// Make sure the object is valid.
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetProps, lpVtbl)) {
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif
return(lpMailUser->lpPropData->lpVtbl->GetProps(
lpMailUser->lpPropData,
lpPropTagArray,
ulFlags,
lpcValues,
lppPropArray));
}
STDMETHODIMP
MailUser_GetPropList(LPMailUser lpMailUser,
ULONG ulFlags,
LPSPropTagArray * lppPropTagArray)
{
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetPropList, lpVtbl))
{
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
#endif
return lpMailUser->lpPropData->lpVtbl->GetPropList(
lpMailUser->lpPropData,
ulFlags,
lppPropTagArray);
}
STDMETHODIMP
MailUser_OpenProperty(LPMailUser lpMailUser,
ULONG ulPropTag,
LPCIID lpiid,
ULONG ulInterfaceOptions,
ULONG ulFlags,
LPUNKNOWN * lppUnk)
{
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, OpenProperty, lpVtbl))
{
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
#endif
return lpMailUser->lpPropData->lpVtbl->OpenProperty(
lpMailUser->lpPropData,
ulPropTag,
lpiid,
ulInterfaceOptions,
ulFlags,
lppUnk);
}
STDMETHODIMP
MailUser_SetProps(LPMailUser lpMailUser,
ULONG cValues,
LPSPropValue lpPropArray,
LPSPropProblemArray * lppProblems)
{
ULONG i;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, SetProps, lpVtbl))
{
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
#endif
if (lpMailUser->lpIAB->lpPropertyStore) {
// Filter out any READ-ONLY props.
// Only do this if this is a real, WAB entry. Others, like LDAP
// mailusers should be able to set any props they like.
for (i = 0; i < cValues; i++) {
switch (lpPropArray[i].ulPropTag) {
case PR_ENTRYID:
{
// double check that this is a local entryid before reseting
ULONG cb = lpPropArray[i].Value.bin.cb;
LPENTRYID lp = (LPENTRYID) lpPropArray[i].Value.bin.lpb;
BYTE bType = IsWABEntryID(cb,lp,NULL,NULL,NULL, NULL, NULL);
if(WAB_PAB == bType || WAB_PABSHARED == bType || !cb || !lp)
lpPropArray[i].ulPropTag = PR_NULL;
}
break;
}
}
}
return(lpMailUser->lpPropData->lpVtbl->SetProps(
lpMailUser->lpPropData,
cValues,
lpPropArray,
lppProblems));
}
STDMETHODIMP
MailUser_DeleteProps(LPMailUser lpMailUser,
LPSPropTagArray lpPropTagArray,
LPSPropProblemArray * lppProblems)
{
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, DeleteProps, lpVtbl))
{
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
#endif
return lpMailUser->lpPropData->lpVtbl->DeleteProps(
lpMailUser->lpPropData,
lpPropTagArray,
lppProblems);
}
STDMETHODIMP
MailUser_CopyTo(LPMailUser lpMailUser,
ULONG ciidExclude,
LPCIID rgiidExclude,
LPSPropTagArray lpExcludeProps,
ULONG_PTR ulUIParam,
LPMAPIPROGRESS lpProgress,
LPCIID lpInterface,
LPVOID lpDestObj,
ULONG ulFlags,
LPSPropProblemArray * lppProblems)
{
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, CopyTo, lpVtbl))
{
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
#endif
// Make sure we're not copying to ourselves
if ((LPVOID)lpMailUser == (LPVOID)lpDestObj)
{
DebugTrace(TEXT("OOP MailUser_CopyTo(): Copying to self is not supported\n"));
return ResultFromScode(MAPI_E_NO_ACCESS);
}
return lpMailUser->lpPropData->lpVtbl->CopyTo(
lpMailUser->lpPropData,
ciidExclude,
rgiidExclude,
lpExcludeProps,
ulUIParam,
lpProgress,
lpInterface,
lpDestObj,
ulFlags,
lppProblems);
}
STDMETHODIMP
MailUser_CopyProps(LPMailUser lpMailUser,
LPSPropTagArray lpIncludeProps,
ULONG_PTR ulUIParam,
LPMAPIPROGRESS lpProgress,
LPCIID lpInterface,
LPVOID lpDestObj,
ULONG ulFlags,
LPSPropProblemArray * lppProblems)
{
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, CopyProps, lpVtbl))
{
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
#endif
return lpMailUser->lpPropData->lpVtbl->CopyProps(
lpMailUser->lpPropData,
lpIncludeProps,
ulUIParam,
lpProgress,
lpInterface,
lpDestObj,
ulFlags,
lppProblems);
}
STDMETHODIMP
MailUser_GetNamesFromIDs(LPMailUser lpMailUser,
LPSPropTagArray * lppPropTags,
LPGUID lpPropSetGuid,
ULONG ulFlags,
ULONG * lpcPropNames,
LPMAPINAMEID ** lpppPropNames)
{
#if !defined(NO_VALIDATION)
// Make sure the object is valid.
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetNamesFromIDs, lpVtbl)){
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif
return lpMailUser->lpPropData->lpVtbl->GetNamesFromIDs(
lpMailUser->lpPropData,
lppPropTags,
lpPropSetGuid,
ulFlags,
lpcPropNames,
lpppPropNames);
}
/***************************************************************************
Name : GetIDsFromNames
Purpose : Map names to property tags
Parameters: lpMAILUSER -> MAILUSER object
cPropNames
lppPropNames
ulFlags
lppPropTags
Returns : HRESULT
Comment :
***************************************************************************/
STDMETHODIMP
MailUser_GetIDsFromNames(LPMailUser lpMailUser,
ULONG cPropNames,
LPMAPINAMEID * lppPropNames,
ULONG ulFlags,
LPSPropTagArray * lppPropTags)
{
#if !defined(NO_VALIDATION)
// Make sure the object is valid.
if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetIDsFromNames, lpVtbl)) {
return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
}
#endif
return HrGetIDsFromNames(lpMailUser->lpIAB,
cPropNames,
lppPropNames, ulFlags, lppPropTags);
}
/***************************************************************************
Name : HrSetMAILUSERAccess
Purpose : Sets access flags on a MAILUSER object
Parameters: lpMAILUSER -> MAILUSER object
ulOpenFlags = MAPI flags: MAPI_MODIFY | MAPI_BEST_ACCESS
Returns : HRESULT
Comment : Set the access flags on the MAILUSER.
***************************************************************************/
HRESULT HrSetMAILUSERAccess(LPMAILUSER lpMAILUSER,
ULONG ulFlags)
{
ULONG ulAccess = IPROP_READONLY;
LPMailUser lpMailUser = (LPMailUser)lpMAILUSER;
switch (ulFlags& (MAPI_MODIFY | MAPI_BEST_ACCESS)) {
case MAPI_MODIFY:
case MAPI_BEST_ACCESS:
ulAccess = IPROP_READWRITE;
break;
case 0:
break;
default:
Assert(FALSE);
}
return(lpMailUser->lpPropData->lpVtbl->HrSetObjAccess(lpMailUser->lpPropData, ulAccess));
}
/***************************************************************************
Name : HrNewMAILUSER
Purpose : Creates a new MAILUSER object
Parameters: lpPropertyStore -> property store structure
pmbinOlk = <Outlook> container this entry lives in
If this is a WAB Container, then set the FOLDER_PARENT
prop on the MailUser with this entryid
ulType = type of mailuser to create: {MAPI_MAILUSER, MAPI_DISTLIST}
ulCreateFlags = CreateEntry flags
lppMAILUSER -> Returned MAILUSER object.
Returns : HRESULT
Comment : WAB EID format is MAPI_ENTRYID:
BYTE abFlags[4];
MAPIUID mapiuid; // = WABONEOFFEID
BYTE bData[]; // Contains BYTE type followed by type
// specific data:
// WAB_ONEOFF:
// szDisplayName, szAddrType and szAddress.
// the delimiter is the null between the strings.
//
***************************************************************************/
enum BaseProps{
propPR_OBJECT_TYPE = 0,
propPR_ENTRYID,
propPR_ADDRTYPE,
propMax
};
HRESULT HrNewMAILUSER(LPIAB lpIAB,
LPSBinary pmbinOlk,
ULONG ulType,
ULONG ulCreateFlags,
LPVOID *lppMAILUSER)
{
LPMailUser lpMailUser = NULL;
SCODE sc;
HRESULT hr = hrSuccess;
LPPROPDATA lpPropData = NULL;
SPropValue spv[propMax];
ULONG cProps;
//
// Allocate space for the MAILUSER structure
//
if (FAILED(sc = MAPIAllocateBuffer(sizeof(MailUser), (LPVOID *) &lpMailUser))) {
hr = ResultFromScode(sc);
goto err;
}
ZeroMemory(lpMailUser, sizeof(MailUser));
switch (ulType) {
case MAPI_MAILUSER:
lpMailUser->cIID = MailUser_cInterfaces;
lpMailUser->rglpIID = MailUser_LPIID;
break;
case MAPI_DISTLIST:
lpMailUser->cIID = DistList_cInterfaces;
lpMailUser->rglpIID = DistList_LPIID;
break;
default:
hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
goto err;
}
lpMailUser->lpVtbl = &vtblMAILUSER;
lpMailUser->lcInit = 1; // Caller is a reference
lpMailUser->hLastError = hrSuccess;
lpMailUser->idsLastError = 0;
lpMailUser->lpszComponent = NULL;
lpMailUser->ulContext = 0;
lpMailUser->ulLowLevelError = 0;
lpMailUser->ulErrorFlags = 0;
lpMailUser->ulCreateFlags = ulCreateFlags;
lpMailUser->lpMAPIError = NULL;
lpMailUser->ulObjAccess = IPROP_READWRITE;
lpMailUser->lpEntryID = NULL;
lpMailUser->lpIAB = lpIAB;
if(pmbinOlk)
{
if (FAILED(sc = MAPIAllocateMore(sizeof(SBinary), lpMailUser, (LPVOID *) &(lpMailUser->pmbinOlk)))) {
hr = ResultFromScode(sc);
goto err;
}
if (FAILED(sc = MAPIAllocateMore(pmbinOlk->cb, lpMailUser, (LPVOID *) &(lpMailUser->pmbinOlk->lpb)))) {
hr = ResultFromScode(sc);
goto err;
}
lpMailUser->pmbinOlk->cb = pmbinOlk->cb;
CopyMemory(lpMailUser->pmbinOlk->lpb, pmbinOlk->lpb, pmbinOlk->cb);
}
//
// Create IPropData
//
if (FAILED(sc = CreateIProp((LPIID)&IID_IMAPIPropData,
(ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
(ALLOCATEMORE FAR *) MAPIAllocateMore,
MAPIFreeBuffer,
NULL,
&lpPropData))) {
hr = ResultFromScode(sc);
goto err;
}
// PR_OBJECT_TYPE
spv[propPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
spv[propPR_OBJECT_TYPE].Value.l = ulType;
spv[propPR_ENTRYID].ulPropTag = PR_ENTRYID;
spv[propPR_ENTRYID].Value.bin.lpb = NULL;
spv[propPR_ENTRYID].Value.bin.cb = 0;
cProps = 2;
if (ulType == MAPI_DISTLIST) {
cProps++;
Assert(cProps <= propMax);
spv[propPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE;
spv[propPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szMAPIPDL;; // All DL's have this addrtype
}
//
// Set the default properties
//
if (HR_FAILED(hr = lpPropData->lpVtbl->SetProps(lpPropData,
cProps,
spv,
NULL)))
{
goto err;
}
lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READWRITE);
lpMailUser->lpPropData = lpPropData;
// All we want to do is initialize the MailUsers critical section
InitializeCriticalSection(&lpMailUser->cs);
*lppMAILUSER = (LPVOID)lpMailUser;
return(hrSuccess);
err:
FreeBufferAndNull(&lpMailUser);
UlRelease(lpPropData);
return(hr);
}
/***************************************************************************
Name : ParseDisplayName
Purpose : Parses the display name into first/last names
Parameters: lpDisplayName = input display name
lppFirstName -> in/out first name string
lppLastName -> in/out last name string
lpvRoot = Root object to AllocMore onto (or NULL to use LocalAlloc)
lppLocalFree -> out: if lpvRoot == NULL, this is the LocalAlloc'ed buffer
which must be LocalFree'd.
Returns : TRUE if changes were made
***************************************************************************/
BOOL ParseDisplayName( LPTSTR lpDisplayName,
LPTSTR * lppFirstName,
LPTSTR * lppLastName,
LPVOID lpvRoot,
LPVOID * lppLocalFree)
{
BOOL fChanged = FALSE;
if (lppLocalFree) {
*lppLocalFree = NULL;
}
//
// Handle the case where DisplayName exists, First and Last are missing
//
if (!(*lppFirstName && lstrlen(*lppFirstName)) &&
!(*lppLastName && lstrlen(*lppLastName)) &&
lpDisplayName)
{
ULONG nLen = 0;
BOOL bMatchFound = FALSE;
ULONG ulBracketCount = 0; //counts any brackets and puts them in last name
LPTSTR lpFirstName, lpLastName;
register TCHAR * pch;
LPTSTR lpBuffer = NULL;
nLen = (lstrlen(lpDisplayName)+1);
if (lpvRoot) {
if (AllocateBufferOrMore(sizeof(TCHAR)*nLen, lpvRoot, &lpBuffer)) {
DebugTrace(TEXT("ParseDisplayName can't allocate buffer\n"));
goto exit;
}
} else {
if (lppLocalFree) {
*lppLocalFree = lpBuffer = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*nLen);
}
}
if(!lpBuffer)
goto exit;
StrCpyN(lpBuffer, lpDisplayName, nLen);
//DebugTrace(TEXT("Parsing: <%s>\n"), lpDisplayName);
TrimSpaces(lpBuffer);
nLen = lstrlen(lpBuffer); // recount length
//
// Find the last space in the DisplayName string and assume that everything after it
// is the last name.
//
// We know that the string does not end with a space.
*lppFirstName = lpBuffer;
lpFirstName = *lppFirstName; // default
// If there is a comma or semicolon, assume that it is in the form
// LAST, FIRST and ignore spaces.
pch = lpBuffer;
while (pch && *pch) {
switch (*pch) {
case '(':
case '{':
case '<':
case '[':
ulBracketCount++;
break;
case ')':
case '}':
case '>':
case ']':
if (ulBracketCount) {
ulBracketCount--;
} else {
// No matching bracket, assume no spaces
goto loop_out;
}
break;
case ',':
case ';':
// Here's our break. (Assume first comma is it. Later commas
// are part of first name.)
if (! ulBracketCount) {
lpFirstName = CharNext(pch);
// get past any spaces
//while (*lpFirstName && IsSpace(lpFirstName)) {
// lpFirstName = CharNext(lpFirstName);
//}
lpLastName = lpBuffer;
*pch = '\0'; // Terminate lpLastName
TrimSpaces(lpFirstName);
TrimSpaces(lpLastName);
*lppFirstName = lpFirstName;
*lppLastName = lpLastName;
goto loop_out;
}
break;
}
pch = CharNext(pch);
}
// No comma or semi-colon, look for spaces.
if (bDNisByLN) {
pch = lpBuffer;
// Start at beginning of DN string, looking for space
while (pch && *pch && !fChanged) {
switch (*pch) {
case '(':
case '{':
case '<':
case '[':
ulBracketCount++;
break;
case ')':
case '}':
case '>':
case ']':
if (ulBracketCount) {
ulBracketCount--;
} else {
// No matching bracket, assume no spaces
goto loop_out;
}
break;
default:
// Space?
if (IsSpace(pch)) {
if (! ulBracketCount) {
lpFirstName = CharNext(pch);
lpLastName = lpBuffer;
*pch = '\0'; // Terminate lpLastName
TrimSpaces(lpFirstName);
TrimSpaces(lpLastName);
*lppFirstName = lpFirstName;
*lppLastName = lpLastName;
goto loop_out;
}
}
break;
}
pch = CharNext(pch);
}
} else {
register TCHAR * pchLast;
// Point to NULL. This will add one iteration to the loop but is
// easy and less code than putting it to the previous DBCS char.
pch = lpBuffer + nLen;
while (pch >= lpBuffer && !fChanged) {
switch (*pch) {
case '(':
case '{':
case '<':
case '[':
if (ulBracketCount) {
ulBracketCount--;
} else {
// No matching bracket, assume no spaces
goto loop_out;
}
break;
case ')':
case '}':
case '>':
case ']':
ulBracketCount++;
break;
case ',':
// This probably means that we have last name first, fix it.
if (! ulBracketCount) {
lpFirstName = CharNext(pch);
lpLastName = lpBuffer;
*pch = '\0'; // Terminate lpFirstName
TrimSpaces(lpFirstName);
TrimSpaces(lpLastName);
*lppLastName = lpLastName;
*lppFirstName = lpFirstName;
goto loop_out;
}
break;
default:
// Space?
if (IsSpace(pch)) {
if (! ulBracketCount)
{
// we dont want to break next to a bracket, we
// want to break at the space after the bracket ..
// so if the next char is a bracket, we ignore this stop ..
LPTSTR lpTemp = CharNext(pch);
if( *lpTemp != '(' &&
*lpTemp != '<' &&
*lpTemp != '[' &&
*lpTemp != '{' )
{
lpLastName = CharNext(pch);
*pch = '\0'; // Terminate lpFirstName
TrimSpaces(lpFirstName);
TrimSpaces(lpLastName);
*lppLastName = lpLastName;
goto loop_out;
}
}
}
break;
}
if ((pchLast = CharPrev(lpBuffer, pch)) == pch) {
pch = lpBuffer - 1; // terminate the loop
} else {
pch = pchLast;
}
}
}
loop_out:
// This will force a save operation on exiting so we
fChanged = TRUE; // dont have to do this again the next time ...
}
exit:
return(fChanged);
}
/***************************************************************************
Name : FixDisplayName
Purpose : Creates a display name
IF there is no data to create the name with,
sets the name to Unknown
Parameters: lpFirstName -> in first name string
lpMiddleName -> in middle name string
lpLastName -> in last name string
lpCompanyName -> in company name string
lpNickName -> in NickName string
lppDisplayName = in/out display name
lpvRoot = Root object to AllocMore onto (or NULL to use MAPIAllocateBuffer)
Returns : TRUE if changes were made
Comment :
***************************************************************************/
BOOL FixDisplayName( LPTSTR lpFirstName,
LPTSTR lpMiddleName,
LPTSTR lpLastName,
LPTSTR lpCompanyName,
LPTSTR lpNickName,
LPTSTR * lppDisplayName,
LPVOID lpvRoot)
{
BOOL fChanged = FALSE;
LPTSTR lpDisplayName = *lppDisplayName;
LPTSTR lpszFormattedDisplayName = NULL;
ULONG nLen=0;
// First create the correct Display Name
if(!SetLocalizedDisplayName(lpFirstName,
lpMiddleName,
lpLastName,
lpCompanyName,
lpNickName,
NULL,
0, // 0 means return a allocated string
bDNisByLN,
NULL,
&lpszFormattedDisplayName))
{
DebugPrintError(( TEXT("SetLocalizedDisplayName failed\n")));
// if all the input strings were blank, then this is a special
// case of no names. here we set display name = TEXT("Unknown")
if(lpFirstName || lpMiddleName || lpLastName || lpCompanyName || lpNickName)
goto exit;
}
if(!lpszFormattedDisplayName)
{
TCHAR szBuf[MAX_UI_STR];
DWORD cchSize = 0;
szBuf[0]='\0';
LoadString(hinstMapiX, idsUnknownDisplayName, szBuf, CharSizeOf(szBuf));
cchSize = (lstrlen(szBuf)+1);
lpszFormattedDisplayName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)* cchSize);
if(!lpszFormattedDisplayName)
goto exit;
StrCpyN(lpszFormattedDisplayName, szBuf, cchSize);
}
if(lpszFormattedDisplayName) {
DWORD cchSize = (lstrlen(lpszFormattedDisplayName) + 1);
if (AllocateBufferOrMore(sizeof(TCHAR)* cchSize, lpvRoot, lppDisplayName)) {
DebugTrace(TEXT("FixDisplayName can't allocate buffer\n"));
goto exit;
}
StrCpyN(*lppDisplayName, lpszFormattedDisplayName, cchSize);
fChanged = TRUE;
}
exit:
LocalFreeAndNull(&lpszFormattedDisplayName);
return(fChanged);
}
/***************************************************************************
Name : HrValidateMailUser
Purpose : Validates the properties of a MailUser object
Parameters: lpMailUser -> mailuser object
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT HrValidateMailUser(LPMailUser lpMailUser) {
HRESULT hResult = hrSuccess;
ULONG ulcValues, i;
LPSPropValue lpspv = NULL;
LPTSTR lpADDRTYPE = NULL;
BOOL fChanged = FALSE, fDL = FALSE;
LPTSTR lpGivenName, lpSurname, lpMiddleName, lpCompanyName, lpNickName, lpDisplayName;
// Get the interesting properties
if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(
lpMailUser,
(LPSPropTagArray)&tagaValidate,
MAPI_UNICODE, // flags
&ulcValues,
&lpspv))) {
DebugTraceResult( TEXT("HrValidateMailUser:GetProps"), hResult);
goto exit;
}
// If there is a PR_ADDRTYPE, there must be a PR_EMAIL_ADDRESS
if (! PROP_ERROR(lpspv[ivPR_ADDRTYPE])) {
if (! lstrcmpi(lpspv[ivPR_ADDRTYPE].Value.LPSZ, szMAPIPDL)) {
fDL = TRUE;
} else {
if (PROP_ERROR(lpspv[ivPR_EMAIL_ADDRESS])) {
hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
goto exit;
}
}
}
if (! fDL) {
// Deal with name properties (not for DLs)
if (PROP_ERROR(lpspv[ivPR_SURNAME])) {
lpSurname = NULL;
} else {
lpSurname = lpspv[ivPR_SURNAME].Value.LPSZ;
}
if (PROP_ERROR(lpspv[ivPR_GIVEN_NAME])) {
lpGivenName = NULL;
} else {
lpGivenName = lpspv[ivPR_GIVEN_NAME].Value.LPSZ;
}
if (PROP_ERROR(lpspv[ivPR_MIDDLE_NAME])) {
lpMiddleName = NULL;
} else {
lpMiddleName = lpspv[ivPR_MIDDLE_NAME].Value.LPSZ;
}
if (PROP_ERROR(lpspv[ivPR_COMPANY_NAME])) {
lpCompanyName = NULL;
} else {
lpCompanyName = lpspv[ivPR_COMPANY_NAME].Value.LPSZ;
}
if (PROP_ERROR(lpspv[ivPR_NICKNAME])) {
lpNickName = NULL;
} else {
lpNickName = lpspv[ivPR_NICKNAME].Value.LPSZ;
}
if (PROP_ERROR(lpspv[ivPR_DISPLAY_NAME])) {
lpDisplayName = NULL;
} else {
lpDisplayName = lpspv[ivPR_DISPLAY_NAME].Value.LPSZ;
}
// WAB needs a display name otherwise it cannot handle the contact.
if(!lpDisplayName)
{
fChanged |= FixDisplayName( lpGivenName,
lpMiddleName,
lpSurname,
lpCompanyName,
lpNickName,
(LPTSTR *) (&lpspv[ivPR_DISPLAY_NAME].Value.LPSZ),
lpspv);
}
if (fChanged) {
lpspv[ivPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
}
}
// Must have a display name and an object type
if (PROP_ERROR(lpspv[ivPR_DISPLAY_NAME]) || PROP_ERROR(lpspv[ivPR_OBJECT_TYPE]) ||
lstrlen(lpspv[ivPR_DISPLAY_NAME].Value.LPSZ) == 0) {
hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
goto exit;
}
// If there is a PR_CONTACT_ADDRTYPES there must be a PR_CONTACT_EMAIL_ADDRESSES
if (! PROP_ERROR(lpspv[ivPR_CONTACT_ADDRTYPES]) && PROP_ERROR(lpspv[ivPR_CONTACT_EMAIL_ADDRESSES])) {
hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
goto exit;
}
// Save changes
if (fChanged) {
// Null out any error values
for (i = 0; i < ulcValues; i++) {
if (PROP_ERROR(lpspv[i])) {
lpspv[i].ulPropTag = PR_NULL;
}
}
if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
ulcValues,
lpspv,
NULL))) {
DebugTraceResult( TEXT("HrValidateMailUser:SetProps"), hResult);
goto exit;
}
}
exit:
FreeBufferAndNull(&lpspv);
return(hResult);
}
//$$
/*
- MAILUSERAssociateContextData
-
* With Context Menu extensions, we pass data to other apps and other apps
* need this data to exsist as long as the corresponding MailUser exists
*/
void MAILUSERAssociateContextData(LPMAILUSER lpMailUser, LPWABEXTDISPLAY lpWEC)
{
((LPMailUser)lpMailUser)->lpv = (LPVOID) lpWEC;
}
//$$
/*
- MAILUSERFreeContextData
-
* If Context Menu data was associated with this MailUSer, its time to clean it up
*/
void MAILUSERFreeContextData(LPMailUser lpMailUser)
{
LPWABEXTDISPLAY lpWEC = (LPWABEXTDISPLAY) lpMailUser->lpv;
if(!lpWEC)
return;
if(lpWEC->lpv)
FreePadrlist((LPADRLIST)lpWEC->lpv);
if(lpWEC->lpsz)
LocalFree(lpWEC->lpsz);
LocalFree(lpWEC);
}