|
|
/*
* IPROP.C * * IProperty in memory */ #include "_apipch.h"
// #pragma SEGMENT(IProp)
//
// IPropData jump table is defined here...
//
IPDAT_Vtbl vtblIPDAT = { VTABLE_FILL (IPDAT_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface, (IPDAT_AddRef_METHOD FAR *) UNKOBJ_AddRef, IPDAT_Release, (IPDAT_GetLastError_METHOD FAR *) UNKOBJ_GetLastError, IPDAT_SaveChanges, IPDAT_GetProps, IPDAT_GetPropList, IPDAT_OpenProperty, IPDAT_SetProps, IPDAT_DeleteProps, IPDAT_CopyTo, IPDAT_CopyProps, IPDAT_GetNamesFromIDs, IPDAT_GetIDsFromNames, IPDAT_HrSetObjAccess, IPDAT_HrSetPropAccess, IPDAT_HrGetPropAccess, IPDAT_HrAddObjProps };
/* Interface which can be queried fro lpIPDAT.
* * It is important that the order of the interfaces supported be preserved * and that IID_IUnknown be the last in the list. */ IID const FAR * argpiidIPDAT[] = { &IID_IMAPIPropData, &IID_IMAPIProp, &IID_IUnknown };
#define CIID_IPROP_INHERITS 1
#define CIID_IPROPDATA_INHERITS 2
/*
* Utility functions/macros used by iprop. */
#define AlignPropVal(_cb) Align8(_cb)
SCODE ScDupNameID(LPIPDAT lpIPDAT, LPVOID lpvBaseAlloc, LPMAPINAMEID lpNameSrc, LPMAPINAMEID * lppNameDest) { SCODE sc;
//
// Allocate space for the name
//
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT, sizeof(MAPINAMEID), lpvBaseAlloc, lppNameDest); if (FAILED(sc)) { goto err; } MemCopy(*lppNameDest, lpNameSrc, sizeof(MAPINAMEID));
//
// Copy the lpguid
//
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT, sizeof(GUID), lpvBaseAlloc, &((*lppNameDest)->lpguid)); if (FAILED(sc)) { goto err; } MemCopy((*lppNameDest)->lpguid, lpNameSrc->lpguid, sizeof(GUID));
//
// conditionally copy the string
//
if (lpNameSrc->ulKind == MNID_STRING) { UINT cbString;
cbString = (lstrlenW(lpNameSrc->Kind.lpwstrName)+1)*sizeof(WCHAR);
//
// Copy the lpwstrName
//
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT, cbString, lpvBaseAlloc, &((*lppNameDest)->Kind.lpwstrName)); if (FAILED(sc)) { goto err; } MemCopy((*lppNameDest)->Kind.lpwstrName, lpNameSrc->Kind.lpwstrName, cbString); }
out: return sc;
err: goto out; }
SCODE ScMakeMAPINames(LPIPDAT lpIPDAT, LPSPropTagArray lpsPTaga, LPMAPINAMEID ** lpppPropNames) { SCODE sc; LPGUID lpMAPIGuid = NULL; int iProp; LPMAPINAMEID rgNames = NULL; //
// First off, allocate enough space in lppPropNames
// to hold all the names.
//
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, lpsPTaga->cValues*sizeof(LPMAPINAMEID), (LPVOID *)lpppPropNames);
if (FAILED(sc)) { goto out; }
//
// Allocate the guid -
//$ Do I really need to do this?? bjd
//
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT, sizeof(GUID), *lpppPropNames, &lpMAPIGuid); if (FAILED(sc)) { goto out; } MemCopy(lpMAPIGuid, (LPGUID) &PS_MAPI, sizeof(GUID));
//
// Allocate a block of MAPINAMEIDs
//
sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT, lpsPTaga->cValues*sizeof(MAPINAMEID), *lpppPropNames, &rgNames);
if (FAILED(sc)) { goto out; }
for (iProp = 0; iProp < (int) lpsPTaga->cValues; iProp++) { //
// First make the name
//
rgNames[iProp].lpguid = lpMAPIGuid; rgNames[iProp].ulKind = MNID_ID; rgNames[iProp].Kind.lID = PROP_ID(lpsPTaga->aulPropTag[iProp]);
//
// Now put it in the name array
//
(*lpppPropNames)[iProp] = &(rgNames[iProp]); }
out: return sc; }
/*
* FreeLpLstSPV() * * Purpose: * Releases objects and frees memory used by lpLstSPV. * Handles NULL. * * Arguments * lpIPDAT Pointer to IPropData object (alloc and free heap) * lpLstSPV The property value list entry which is to be freed. * * Returns * VOID * */ VOID FreeLpLstSPV( LPIPDAT lpIPDAT, LPLSTSPV lpLstSPV) {
if (!lpLstSPV) { return; }
/* Free the property list node. This also frees the property value
* and property name string. */ UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPV); }
/*
* LinkLstSPV() * * Purpose: * Link a new property node after an existing property node in a singly * linked list. lppLstLnk points to the element that will preceed * the newly linked element. This element may be the list head. * * Arguments * lppLstLnk Pointer to list entry (or list head) AFTER which * lpLstLnk will be inserted. * lpLstLnk The element to be inserted in the singly linked list. * * Returns * VOID */ VOID LinkLstLnk( LPLSTLNK FAR * lppLstLnk, LPLSTLNK lpLstLnk) { /* Always insert at the head of the list.
*/ lpLstLnk->lpNext = *lppLstLnk; *lppLstLnk = lpLstLnk; }
/*
* UnlinkLstLNK() * * Purpose: * Unlink the next element in the list. You pass a pointer the element * before the one to be unlinked (this can be the list head). * * The input is typed as LPPLSTLNK because the element before the one to * be unlinked should point to the one one that is to be linked. * * Arguments * lppLstLnk Pointer to the element before the element that is to be * unlinked from the singly linked list. * * Returns * VOID */ VOID UnlinkLstLnk( LPPLSTLNK lppLstLnk) { /* Unlink the element following the one passed in.
*/ if (*lppLstLnk) { ((LPLSTLNK) lppLstLnk)->lpNext = (*lppLstLnk)->lpNext; } }
/*
* lpplstspvFindProp() * * Purpose: * Locate a property in the linked list of properties (lppLstSPV), * return a pointer to pointer to it. * * Pointer to pointer is returned to make it easy to unlink the singly * linked list entry if required. * * Arguments * lppLstLnkHead Pointer to the head of a singly linked list which is * to be searched. It may also point to the element * before the first one to be searched if a partial list * search (lppLstLnkHead->next to the end) is desired. * ulPropTag The property tag for which a match is desired. * NOTE! Only the PROP_ID portion is compared. * * Returns: * NULL if the requested property is not in the list * lppLstSPV to the property it found in the list. */ LPPLSTLNK LPPLSTLNKFindProp( LPPLSTLNK lppLstLnkHead, ULONG ulPropTag) { ULONG ulID2Find = PROP_ID(ulPropTag); LPLSTLNK lpLstLnk; LPPLSTLNK lppLstLnk;
for ( lpLstLnk = *lppLstLnkHead, lppLstLnk = lppLstLnkHead ; lpLstLnk ; lppLstLnk = (LPPLSTLNK) lpLstLnk, lpLstLnk = lpLstLnk->lpNext) { /* If this property matches the one we are looking for return a
* pointer to the one before it. */ if (ulID2Find == PROP_ID(lpLstLnk->ulKey)) { return lppLstLnk; } }
return NULL; }
/*
* ScCreateSPV() * * Purpose: * Create a lstSPV for the given property and copy the property to it. * * Arguments * lpIPDAT Pointer to IPropData object (alloc and free heap) * lpPropToAdd Pointer to a property value for which a property value * list entry is to be created. * lppLstSPV Pointer to the memory location which will receive a pointer * to the newly allocated list entry. * * Returns * SCODE */ SCODE ScCreateSPV(LPIPDAT lpIPDAT, LPSPropValue lpPropToAdd, LPLSTSPV FAR * lppLstSPV) { SCODE sc = S_OK; LPLSTSPV lpLstSPV = NULL; LPSPropValue lpPropNew = NULL; ULONG cbToAllocate = 0;
/* Calculate the space needed to hold the entire property
*/ sc = ScCountProps( 1, lpPropToAdd, &cbToAllocate ); if (FAILED(sc)) { DebugTrace(TEXT("ScCreateSPV() - ScCountProps failed (SCODE = 0x%08lX)\n"), sc ); goto error; }
/* Account for the base LSTSPV.
*/ cbToAllocate += AlignPropVal(CBLSTSPV);
/* Allocate the whole chunk
*/ if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, cbToAllocate, &lpLstSPV))) { goto error; }
lpPropNew = (LPSPropValue) (((LPBYTE)lpLstSPV) + AlignPropVal(CBLSTSPV));
/* Initialize the property node.
*/ lpLstSPV->ulAccess = IPROP_READWRITE | IPROP_DIRTY; lpLstSPV->lstlnk.ulKey = lpPropToAdd->ulPropTag;
/* Copy the property.
*/ if (sc = ScCopyProps(1, lpPropToAdd, lpPropNew, NULL)) { DebugTrace(TEXT("ScCreateSPV() - Error copying prop (SCODE = 0x%08lX)\n"), sc ); goto error; }
/* Link in the new property value...
*/ lpLstSPV->lpPropVal = lpPropNew;
/* ...and return the new property node.
*/ *lppLstSPV = lpLstSPV;
goto out;
error: UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPV);
out: return sc; }
SCODE ScMakeNamePropList( LPIPDAT lpIPDAT, ULONG ulCount, LPLSTSPN lplstSpn, LPSPropTagArray FAR * lppPropTagArray, ULONG ulFlags, LPGUID lpGuid) { SCODE sc; UNALIGNED ULONG FAR * lpulPropTag;
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, CbNewSPropTagArray(ulCount), (LPVOID *) lppPropTagArray))) { return sc; }
/* Initialize the count of PropTags to 0.
*/ (*lppPropTagArray)->cValues = 0;
for ( lpulPropTag = (*lppPropTagArray)->aulPropTag ; lplstSpn ; lplstSpn = (LPLSTSPN)lplstSpn->lstlnk.lpNext) { /* Set the next PropTag and increment the count of PropTags.
*/
//
// See if we have a guid to look for.
// If it's not the one we're looking for, then we keep looking.
//
if (lpGuid && (memcmp(lpGuid, lplstSpn->lpPropName->lpguid, sizeof(GUID))) ) continue;
//
// Three cases here:
// We don't want strings
// We don't want IDs
// We don't care - we want all.
//
if ( ((lplstSpn->lpPropName->ulKind == MNID_ID) && (ulFlags & MAPI_NO_IDS)) || ((lplstSpn->lpPropName->ulKind == MNID_STRING) && (ulFlags & MAPI_NO_STRINGS)) ) continue;
//
// We want these tags
//
*lpulPropTag = lplstSpn->lstlnk.ulKey; lpulPropTag++; (*lppPropTagArray)->cValues++;
}
return sc; }
/*
* ScMakePropList * * Purpose: * Allocate memory for, and fill in a complete list of properties for * the given lpIPDAT. * * Arguments * lpIPDAT Pointer to IPropData object (alloc and free heap) * lppPropTagArray Pointer to the memory location which will receive a * pointer to the newly allocated Tag array. * * Returns * SCODE */ SCODE ScMakePropList( LPIPDAT lpIPDAT, ULONG ulCount, LPLSTLNK lplstLink, LPSPropTagArray FAR * lppPropTagArray, ULONG ulUpperBound) { SCODE sc; UNALIGNED ULONG FAR * lpulPropTag;
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, CbNewSPropTagArray(ulCount), (LPVOID *) lppPropTagArray))) { return sc; }
/* Initialize the count of PropTags to 0.
*/ (*lppPropTagArray)->cValues = 0;
for ( lpulPropTag = (*lppPropTagArray)->aulPropTag ; lplstLink ; lplstLink = lplstLink->lpNext) { /* Set the next PropTag and increment the count of PropTags.
*/ if (PROP_ID(lplstLink->ulKey) < ulUpperBound) // Not <= !
{ *lpulPropTag = lplstLink->ulKey; (*lppPropTagArray)->cValues++; lpulPropTag++; } }
return sc; }
/****************************************************************
* - CreateIProp - * Purpose * Used for creating a property interface in memory. * * * Arguments * lpInterface Pointer to the interface ID of the object the caller * wants. This should match IID_IMAPIPropData for the * current version of IPROP.DLL. * lpfAllocateBuffer Pointer to MAPI memory allocator. * lpfAllocateMore Pointer to MAPI memory allocate more. * lpfFreeBuffer Pointer to MAPI memory de-allocator. * lppMAPIPropData Pointer to memory location which will receive a * pointer to the new IMAPIPropData object. * * Notes * The caller must insure the MAPI support object from which it drew the * memory allocation routines is not Released before the new IPropData. * * Returns * SCODE * */
STDAPI_(SCODE) CreateIProp(LPCIID lpInterface, ALLOCATEBUFFER FAR *lpfAllocateBuffer, ALLOCATEMORE FAR * lpfAllocateMore, FREEBUFFER FAR * lpfFreeBuffer, LPVOID lpvReserved, LPPROPDATA FAR * lppMAPIPropData ) {
SCODE sc; LPIPDAT lpIPDAT = NULL;
// validate paremeters
AssertSz( lpfAllocateBuffer && !IsBadCodePtr( (FARPROC)lpfAllocateBuffer ), TEXT("lpfAllocateBuffer fails address check") );
AssertSz( !lpfAllocateMore || !IsBadCodePtr( (FARPROC)lpfAllocateMore ), TEXT("lpfAllocateMore fails address check") );
AssertSz( !lpfFreeBuffer || !IsBadCodePtr( (FARPROC)lpfFreeBuffer ), TEXT("lpfFreeBuffer fails address check") );
AssertSz( lppMAPIPropData && !IsBadWritePtr( lppMAPIPropData, sizeof( LPPROPDATA ) ), TEXT("LppMAPIPropData fails address check") );
/* Make sure that the caller is asking for an object that we support.
*/ if ( lpInterface && !IsEqualGUID(lpInterface, &IID_IMAPIPropData)) { sc = MAPI_E_INTERFACE_NOT_SUPPORTED; goto error; }
//
// Create a IPDAT per object for lpMAPIPropInternal so that it gets
// called first.
if (FAILED(sc = lpfAllocateBuffer(CBIPDAT, &lpIPDAT))) { goto error; }
/* Init the object to 0, NULL
*/ memset( (BYTE *) lpIPDAT, 0, sizeof(*lpIPDAT));
/* Fill in the object specific instance data.
*/ lpIPDAT->inst.lpfAllocateBuffer = lpfAllocateBuffer; lpIPDAT->inst.lpfAllocateMore = lpfAllocateMore; lpIPDAT->inst.lpfFreeBuffer = lpfFreeBuffer;
#ifndef MAC
lpIPDAT->inst.hinst = hinstMapiX;//HinstMapi();
#ifdef DEBUG
if (lpIPDAT->inst.hinst == NULL) TraceSz1( TEXT("IPROP: GetModuleHandle failed with error %08lX"), GetLastError()); #endif /* DEBUG */
#else
lpIPDAT->inst.hinst = hinstMapiX;//(HINSTANCE) GetCurrentProcess();
#endif
/* Initialize the TEXT("standard") object.
* This must be the last operation that * can fail. If not, explicitly call * UNKOBJ_Deinit() for failures after * a successful UNKOBJ_Init. */ if (FAILED(sc = UNKOBJ_Init( (LPUNKOBJ) lpIPDAT , (UNKOBJ_Vtbl FAR *) &vtblIPDAT , sizeof(vtblIPDAT) , (LPIID FAR *) argpiidIPDAT , dimensionof( argpiidIPDAT) , &(lpIPDAT->inst)))) { DebugTrace( TEXT("CreateIProp() - Error initializing IPDAT object (SCODE = 0x%08lX)\n"), sc ); goto error; }
/* Initialize the defaults in IPROP specific part of the object.
*/ lpIPDAT->ulObjAccess = IPROP_READWRITE; lpIPDAT->ulNextMapID = 0x8000;
*lppMAPIPropData = (LPPROPDATA) lpIPDAT;
return S_OK;
error: if (lpIPDAT) { lpfFreeBuffer(lpIPDAT); }
return sc; }
// --------
// IUnknown
/*
- IPDAT_Release - * Purpose: * Decrements reference count on the IPropData object and * removes instance data if reference count becomes zero. * * Arguments: * lpIPDAT The IPropData object to be released. * * Returns: * Decremented reference count * * Side effects: * * Errors: */ STDMETHODIMP_(ULONG) IPDAT_Release (LPIPDAT lpIPDAT) { ULONG ulcRef;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, Release, lpVtbl)) { DebugTrace( TEXT("IPDAT::Release() - Bad object passed\n") ); return 1; } #endif
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT); ulcRef = --lpIPDAT->ulcRef; UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
/* Free the object.
* * No critical section lock is required since we are guaranteed to be * the only thread accessing the object (ie ulcRef == 0). */ if (!ulcRef) { LPLSTLNK lpLstLnk; LPLSTLNK lpLstLnkNext; FREEBUFFER * lpfFreeBuffer;
/* Free the property value list.
*/ for ( lpLstLnk = (LPLSTLNK) (lpIPDAT->lpLstSPV); lpLstLnk; ) { lpLstLnkNext = lpLstLnk->lpNext; FreeLpLstSPV( lpIPDAT, (LPLSTSPV) lpLstLnk); lpLstLnk = lpLstLnkNext; }
/* Free the ID to NAME map list.
*/ for ( lpLstLnk = (LPLSTLNK) (lpIPDAT->lpLstSPN); lpLstLnk; ) { lpLstLnkNext = lpLstLnk->lpNext; UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstLnk); lpLstLnk = lpLstLnkNext; }
/* Free the object.
*/
lpfFreeBuffer = lpIPDAT->inst.lpfFreeBuffer; UNKOBJ_Deinit((LPUNKOBJ) lpIPDAT);
lpIPDAT->lpVtbl = NULL; lpfFreeBuffer(lpIPDAT); }
return ulcRef; }
/*
- IPDAT_SaveChanges - * Purpose: * This DOES not actually save changes since all changes (SetProps etc) * become effective immediately. This method will invalidate or keep * the IPropData object open depending on the flags passed in. * * Arguments: * lpIPDAT IPropData object to save changes on. * ulFlags KEEP_OPEN_READONLY * KEEP_OPEN_READWRITE * FORCE_SAVE (valid but no support) * * Returns: * HRESULT * */ STDMETHODIMP IPDAT_SaveChanges (LPIPDAT lpIPDAT, ULONG ulFlags) { SCODE sc = S_OK;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, SaveChanges, lpVtbl)) { DebugTrace( TEXT("IPDAT::SaveChanges() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_SaveChanges( lpIPDAT, ulFlags );
#endif
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
//$REVIEW is this really needed?
/* Check object access rights.
*/ if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE)) { sc = MAPI_E_NO_ACCESS; goto error; }
/* IPROP objects are always up to date (saved to memory) so all
* we have to do is figure out whether and how to leave it open. */ if (!(ulFlags & (KEEP_OPEN_READONLY | KEEP_OPEN_READWRITE))) { /* We really should invalidate the object here but we have no
* clear cut way to call the MakeInvalid method since * we don't have a pointer to the support object! */ //$REVIEW If we are ever going to hand the client an unwrapped interface
//$REVIEW to IMAPIProp then we must get our own support object!
sc = S_OK; goto out; }
//$BUG Combine the READWRITE and READONLY flags to IPROP_WRITABLE.
else if (ulFlags & KEEP_OPEN_READWRITE) { lpIPDAT->ulObjAccess |= IPROP_READWRITE; lpIPDAT->ulObjAccess &= ~IPROP_READONLY; }
else { lpIPDAT->ulObjAccess |= IPROP_READONLY; lpIPDAT->ulObjAccess &= ~IPROP_READWRITE; }
goto out;
error: UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return ResultFromScode(sc); }
/*
- IPDAT_GetProps - * Purpose: * Returns in lpcValues and lppPropArray the values of the properties * in lpPropTagArray. If the latter is NULL, all properties available * (except PT_OBJECT) from the IPropData object are returned. * * Arguments: * lpIPDAT The IPropData object whose properties are requested. * lpPropTagArray Pointer to a counted array of property tags of * properties requested. * lpcValues Pointer to the memory location which will receive the * number of values returned. * lppPropArray Pointer to the memory location which will receive the * address of the returned property value array. * * Returns: * HRESULT * * Notes: * Now UNICODE enabled. If UNICODE is set, then any string properties * not otherwise specified to be String8 are returned in UNICODE, otherwise * unspecified string properties are in String8. String Properties with * unspecified types occur when GetProps() is used with a NULL for the * lpPropTagArray. * */ STDMETHODIMP IPDAT_GetProps (LPIPDAT lpIPDAT, LPSPropTagArray lpPropTagArray, ULONG ulFlags, ULONG FAR * lpcValues, LPSPropValue FAR * lppPropArray) { SCODE sc = S_OK; ULONG ulcWarning = 0; ULONG iProp = 0; LPSPropValue lpPropValue = NULL;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetProps, lpVtbl)) { DebugTrace( TEXT("IPDAT::GetProps() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_GetProps(lpIPDAT, lpPropTagArray, ulFlags, lpcValues, lppPropArray); #endif
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* If they aren't asking for anything specific, then
* just copy what we have and be done with it. */ if (!lpPropTagArray) { LPLSTSPV lpLstSPV;
if (!lpIPDAT->ulCount) { /* iProp is initialized to 0 on entry. */ *lpcValues = iProp; *lppPropArray = lpPropValue; goto out; }
/* Allocate space for all listed properties. Space allocated for
* properties which are not actually returned is simply wasted. */ //$REVIEW This would be a good place for a MAPI reallocBuf function.
if (sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , lpIPDAT->ulCount * sizeof (SPropValue) , &lpPropValue)) { //
// Memory error
//
goto error; }
*lpcValues = 0;
/* iProp is initialized to 0 on method entry.
*/ for ( lpLstSPV = lpIPDAT->lpLstSPV; lpLstSPV; lpLstSPV = (LPLSTSPV) (lpLstSPV->lstlnk.lpNext)) { /* Copy the property.
*/ switch (PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag)) { case PT_OBJECT: case PT_NULL: /* These properties with type PT_NULL and PT_OBJECT are handled
* specially. PropCopyMore doesn't handle them now. */ lpPropValue[iProp].ulPropTag = lpLstSPV->lpPropVal->ulPropTag; iProp++; break;
default: if (FAILED(sc = PropCopyMore( &(lpPropValue[iProp]), (LPSPropValue) (lpLstSPV->lpPropVal), lpIPDAT->inst.lpfAllocateMore, lpPropValue))) { goto error; } iProp++; break; } }
/* Return the propValue array and the count of properties actually
* returned. */ *lpcValues = iProp; *lppPropArray = lpPropValue;
// Handle UNICODE / String conversions depending on ulFlags
//
// Default WAB Handling is going to be in Unicode so don't need to worry about the MAPI_UNICODE
// flag. Only when the flag is not supplied do we have to provide the non-Unicode data
//
// We'll leave the Unicode code in place anyway for now
if (ulFlags & MAPI_UNICODE ) { if(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0)) goto error; } else { if(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0)) goto error; } } else { //
// So they want only specific properties
//
// Allocate space for the new stuff - enuf to give them all they want
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, lpPropTagArray->cValues * sizeof (SPropValue), &lpPropValue))) goto error;
//
// Go through the list of prop tags they want, find each one
// in lpIPDAT->lpLstSPV, and copy it over to lpPropValue
//
for (iProp = 0; iProp < lpPropTagArray->cValues; iProp++) { LPPLSTLNK lppLstLnk; LPLSTSPV lpLstSPV; ULONG ulProp2Find = lpPropTagArray->aulPropTag[iProp]; ULONG ulType2Find = PROP_TYPE(ulProp2Find);
/* If the property is in our list try to copy it.
*/ if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV), ulProp2Find)) && (lpLstSPV = (LPLSTSPV) (*lppLstLnk))) { ULONG ulType2Check = PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag);
/* Make sure the property value can be returned in the form the
* caller expects. If not then set a PT_ERROR scode and make * sure we return an error. */ if (!( ((ulType2Find == PT_STRING8) && (ulType2Check == PT_UNICODE)) || ((ulType2Find == PT_UNICODE) && (ulType2Check == PT_STRING8)) || ((ulType2Find == PT_MV_STRING8) && (ulType2Check == PT_MV_UNICODE)) || ((ulType2Find == PT_MV_UNICODE) && (ulType2Check == PT_MV_STRING8)) )) { if ( (ulType2Find != ulType2Check) && (ulType2Find != PT_UNSPECIFIED)) { lpPropValue[iProp].ulPropTag = PROP_TAG( PT_ERROR , PROP_ID(ulProp2Find)); lpPropValue[iProp].Value.err = MAPI_E_INVALID_TYPE; ulcWarning += 1; continue; } }
/* Copy the property.
* Properties of these types are handled specially because * PropCopyMore can't handle them now. */ if ( (ulType2Check == PT_OBJECT) || (ulType2Check == PT_NULL) || (ulType2Check == PT_ERROR)) { MemCopy( (BYTE *) &(lpPropValue[iProp]), (BYTE *) (lpLstSPV->lpPropVal), sizeof(SPropValue)); } else { // @todo [PaulHi] 1/19/99
// The problem with first copying the string properties and THEN converting
// them if necessary is that an allocation is preformed for each step. The
// original allocation isn't released until the property array is released.
// It would be more efficient (memory wise) to do the allocation once, after
// any necessary conversion is done. Vikram had special code to do this (similar
// to else condition below) but missed multi-valued strings. This makes for more
// complex and duplicate code. Should this code be changed accordingly?
// First copy the property
if (FAILED(sc = PropCopyMore( &(lpPropValue[iProp]), (LPSPropValue)(lpLstSPV->lpPropVal), lpIPDAT->inst.lpfAllocateMore, lpPropValue))) { goto error; } //
// Next convert ANSI-UNICODE or UNICODE-ANSI as requested by caller
//
if ( ((ulType2Find == PT_UNICODE) && (ulType2Check == PT_STRING8)) || ((ulType2Find == PT_MV_UNICODE) && (ulType2Check == PT_MV_STRING8)) ) { // Convert single or multiple value ANSI store string to UNICODE
if(FAILED(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, lpPropValue, iProp+1, iProp))) goto error; } else if ( ((ulType2Find == PT_STRING8) && (ulType2Check == PT_UNICODE)) || ((ulType2Find == PT_MV_STRING8) && (ulType2Check == PT_MV_UNICODE)) ) { // Convert single or multiple value UNICODE store string to ANSI
if(FAILED(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, lpPropValue, iProp+1, iProp))) goto error; } } } /* Property wasn't found.
*/ else { //
// [PaulHi] 1/14/99 Raid 63006
// If a property of type PR_EMAIL_ADDRESS was requested and not found
// then check to see if an email address is in the multi-valued
// PR_CONTACT_EMAIL_ADDRESSES property. If so copy the first email
// address to the PR_EMAIL_ADDRESS slot.
//
ULONG ulProp2Check = PR_EMAIL_ADDRESS; if (PROP_ID(ulProp2Find) == PROP_ID(ulProp2Check) ) { // Look for a PR_CONTACT_EMAIL_ADDRESSES property
LPPLSTLNK lppLstLnk; LPLSTSPV lpLstSPV; ULONG ulNewProp2Find = PR_CONTACT_EMAIL_ADDRESSES;
if ( (lppLstLnk = LPPLSTLNKFindProp((LPPLSTLNK) &(lpIPDAT->lpLstSPV), ulNewProp2Find)) && (lpLstSPV = (LPLSTSPV) (*lppLstLnk)) ) { ULONG ulType2Check = PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag); BYTE * pPropBuf = NULL; UINT cBufSize = 0;
// We know that we looked up a MV string so just check for ANSI
// or UNICODE property types
if (ulType2Check == PT_MV_STRING8) { LPSTR lpstr = NULL;
//
// Get the first ANSI email string in array
//
if ( ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszA.cValues == 0 ) { Assert(0); goto convert_error; } lpstr = ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszA.lppszA[0]; cBufSize = lstrlenA(lpstr)+1;
// If caller requested UNICODE then convert before allocating MAPI
// buffer space
if (ulType2Find == PT_UNICODE) { // Allocate room for the new UNICODE string
if ( lpIPDAT->inst.lpfAllocateMore((cBufSize * sizeof(WCHAR)), lpPropValue, &pPropBuf) ) { goto error; }
if ( MultiByteToWideChar(CP_ACP, 0, lpstr, -1, (LPWSTR)pPropBuf, cBufSize) == 0 ) { Assert(0); goto convert_error; }
// Assign property and fix up property tag
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(ulProp2Find)); lpPropValue[iProp].Value.lpszW = (LPWSTR)pPropBuf; } else { // Otherwise just copy string property to property value
// array
// Allocate room for the new ANSI string
if (lpIPDAT->inst.lpfAllocateMore(cBufSize, lpPropValue, &pPropBuf)) { goto error; }
// Copy property and fix up property tag
MemCopy((BYTE *)pPropBuf, (BYTE *)lpstr, cBufSize); lpPropValue[iProp].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulProp2Find)); lpPropValue[iProp].Value.lpszA = (LPSTR)pPropBuf; } } else if (ulType2Check == PT_MV_UNICODE) { LPWSTR lpwstr = NULL;
//
// Get the first UNICODE email string in array
//
if ( ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszW.cValues == 0 ) { Assert(0); goto convert_error; } lpwstr = ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszW.lppszW[0];
// If caller requested ANSI then convert before allocating MAPI
// buffer space
if (ulType2Find == PT_STRING8) { cBufSize = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, NULL, 0, NULL, NULL) + 1;
// Allocate room for the new ANSI string
if ( lpIPDAT->inst.lpfAllocateMore(cBufSize, lpPropValue, &pPropBuf) ) { goto error; }
if ( WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, (LPSTR)pPropBuf, cBufSize, NULL, NULL) == 0 ) { Assert(0); goto convert_error; }
// Assign property and fix up property tag
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulProp2Find)); lpPropValue[iProp].Value.lpszA = (LPSTR)pPropBuf; } else { // Otherwise just copy string property to property value
// array
cBufSize = lstrlenW(lpwstr)+1;
// Allocate room for the new UNICODE string
if (lpIPDAT->inst.lpfAllocateMore((sizeof(WCHAR) * cBufSize), lpPropValue, &pPropBuf)) { goto error; }
// Copy property and fix up property tag
MemCopy((BYTE *)pPropBuf, (BYTE *)lpwstr, (sizeof(WCHAR) * cBufSize)); lpPropValue[iProp].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(ulProp2Find)); lpPropValue[iProp].Value.lpszW = (LPWSTR)pPropBuf; } } else { Assert(0); goto convert_error; }
// Success
continue; } }
convert_error:
// Otherwise return error for this property
lpPropValue[iProp].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulProp2Find)); lpPropValue[iProp].Value.err = MAPI_E_NOT_FOUND;
/* Increment the warning count to trigger MAPI_W_ERRORS_RETURNED.
*/ ulcWarning += 1; } }
*lpcValues = iProp; *lppPropArray = lpPropValue; }
// [PaulHi] 1/15/99
// Mass property conversion (ANIS/UNICODE) should only be done when the caller
// doesn't specifically request property tag types.
#if 0
//
// Handle UNICODE / String conversions depending on ulFlags
//
// Default WAB Handling is going to be in Unicode so don't need to worry about the MAPI_UNICODE
// flag. Only when the flag is not supplied do we have to provide the non-Unicode data
//
// We'll leave the Unicode code in place anyway for now
if (ulFlags & MAPI_UNICODE ) { if(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0)) goto error; } else { if(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0)) goto error; } #endif
goto out;
error: UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropValue ); UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: if (ulcWarning) sc = MAPI_W_ERRORS_RETURNED;
UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT); return ResultFromScode(sc); }
/*
- IPDAT_GetPropList - * Purpose: * Returns in lpPropTagArray the list of all currently available properties * (including PT_OBJECT) in the IPropData object. * * Now supports UNICODE flag in ulFlag. Conversion of String Proptags based * whether MAPI_UNICODE is set or not. * * Arguments: * lpIPDAT The IPropData object whose properties are requested. * lppPropTagArray Pointer to the memory location which will receive * a property tag array of the listed properties. * Returns: * HRESULT * */ STDMETHODIMP IPDAT_GetPropList (LPIPDAT lpIPDAT, ULONG ulFlags, LPSPropTagArray FAR * lppPropTagArray) { SCODE sc = S_OK; ULONG uTagA = 0, uTagW = 0, iTag = 0;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetPropList, lpVtbl)) { DebugTrace( TEXT("IPDAT::GetPropList() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_GetPropList( lpIPDAT, ulFlags, lppPropTagArray );
#endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
sc = ScMakePropList( lpIPDAT, lpIPDAT->ulCount, (LPLSTLNK) lpIPDAT->lpLstSPV, lppPropTagArray, (ULONG) -1 ); if ( FAILED( sc ) ) goto error;
// Support for UNICODE / String8
for ( iTag = 0; iTag < (*lppPropTagArray)->cValues; iTag++ ) { uTagA = uTagW = 0; switch(PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag] )) { case PT_STRING8: uTagW = PT_UNICODE; break; case PT_MV_STRING8: uTagW = PT_MV_UNICODE; break; case PT_UNICODE: uTagA = PT_STRING8; break; case PT_MV_UNICODE: uTagA = PT_MV_STRING8; break; default: continue; break; } if ( ulFlags & MAPI_UNICODE && uTagW) (*lppPropTagArray)->aulPropTag[iTag] = CHANGE_PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag], uTagW); else if ( ulFlags & ~MAPI_UNICODE && uTagA) (*lppPropTagArray)->aulPropTag[iTag] = CHANGE_PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag], uTagA); }
goto out;
error: UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_OpenProperty - * Purpose: * OpenProperty is not supported for IPROP.DLL. It will, however, validate * the input parameters. * * Arguments: * lpIPDAT The IPropData object which contains the property/ * ulPropTag Property tag for the desired property. * lpiid Pointer to the ID for the requested interface. * ulInterfaceOptions Specifies interface-specific behavior * ulFlags MAPI_CREATE, MAPI_MODIFY, MAPI_DEFERRED_ERRORS * lppUnk Pointer to the newly created interface pointer * * Returns: * HRESULT * */ STDMETHODIMP IPDAT_OpenProperty (LPIPDAT lpIPDAT, ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN FAR * lppUnk) { SCODE sc = S_OK;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, OpenProperty, lpVtbl)) { DebugTrace( TEXT("IPDAT::OpenProperty() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_OpenProperty( lpIPDAT, ulPropTag, lpiid, ulInterfaceOptions, ulFlags, lppUnk);
#endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* We don't support OpenProperty.
*/ sc = MAPI_E_INTERFACE_NOT_SUPPORTED;
/*
*error: */ UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
/*
*out: */ UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_SetProps - * Purpose: * Sets the properties listed in <lpPropArray>. * Returns an array of problems in <lppProblems> if there were any, * NULL If there weren't any. * * Arguments: * lpIPDAT The IPropData object whose properties are to be set. * cValues The count of properties to be set. * lpPropArray Pointer to a an array of <cValues> property value * structures. * lppProblems Pointer to memory location which will receive a * pointer to a problem array if non-catastrophic * errors occur. NULL if no problem array is desired. * * Returns: * HRESULT * */ STDMETHODIMP IPDAT_SetProps (LPIPDAT lpIPDAT, ULONG cValues, LPSPropValue lpPropArray, LPSPropProblemArray FAR * lppProblems) { SCODE sc = S_OK; int iProp = 0; LPLSTSPV lpLstSPVNew = NULL; LPSPropProblemArray lpProblems = NULL; LPSPropValue lpPropToAdd = NULL;
#if !defined(NO_VALIDATION)
// Make sure the object is valid.
if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, SetProps, lpVtbl)) { DebugTrace( TEXT("IPDAT::SetProps() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_SetProps( lpIPDAT, cValues, lpPropArray, lppProblems); #endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* Check access rights...
*/ if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE)) { sc = MAPI_E_NO_ACCESS; goto error; }
if (lppProblems) { /* Initially indicate no problems.
*/ *lppProblems = NULL;
/* Allocate the property problem array.
* Because we expect the property list to be of TEXT("reasonable") size we * go ahead and allocate enough entries for every property to have a * problem. */ //$REVIEW This is a place where a MAPI reallocBuf function would be useful.
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , CbNewSPropProblemArray(cValues) , &lpProblems))) { goto error; }
lpProblems->cProblem = 0; }
/* Loop through the list of properties to set..
*/ for (iProp = 0; iProp < (int)cValues; iProp++) { ULONG ulProp2Find = lpPropArray[iProp].ulPropTag; LPPLSTLNK lppLstLnk; LPLSTSPV lpLstSPV;
/* Reset the temp prop name and value pointers so we don't accidentally
* free the wrong one on an error. */ lpLstSPVNew = NULL;
lpPropToAdd = NULL;
/* Ignore properties with type PT_ERROR or PR_NULL.
*/ if ((PROP_TYPE(ulProp2Find) == PT_ERROR) || (ulProp2Find == PR_NULL)) { continue; }
/* PT_OBJECT and PT_UNSPECIFIED properties get caught in parameter
* validation. */
/* If a writable property with the given tag already exists then
* delete it (we will create another version of it later). * * If a readonly property with the given tag already exists then * include an error in the problem array. */
if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , ulProp2Find)) && (lpLstSPV = (LPLSTSPV) (*lppLstLnk))) { /* If it is readonly then put an entry into the problem
* array. */ if (!(lpLstSPV->ulAccess & IPROP_READWRITE)) { AddProblem( lpProblems , iProp , lpPropArray[iProp].ulPropTag , MAPI_E_NO_ACCESS);
goto nextProp; }
/* Unlink the found property and free its memory.
*/ UnlinkLstLnk( lppLstLnk); lpIPDAT->ulCount -= 1; FreeLpLstSPV( lpIPDAT, lpLstSPV); }
// Native string storage within the WAB is now in UNICODE
// so if any property being set on the object is in ANSI/DBCS .. convert this to UNICODE
// before trying to add it here ..
if( PROP_TYPE(lpPropArray[iProp].ulPropTag) == PT_STRING8 || PROP_TYPE(lpPropArray[iProp].ulPropTag) == PT_MV_STRING8 ) { // Create a temp copy of this sepcific property array so that we can munge the
// data .. I would rather not munge the original array because caller might expect to use it
// .. there's no gaurantee its safely modifiable
//
ULONG cbToAllocate = 0;
sc = ScCountProps( 1, &(lpPropArray[iProp]), &cbToAllocate ); if (FAILED(sc)) { DebugTrace(TEXT("SetProps() - ScCountProps failed (SCODE = 0x%08lX)\n"), sc ); goto error; }
/* Allocate the whole chunk
*/ if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, cbToAllocate, &lpPropToAdd))) { goto error; }
/* Copy the property.
*/ if (sc = ScCopyProps(1, &(lpPropArray[iProp]), lpPropToAdd, NULL)) { DebugTrace(TEXT("SetProps() - Error copying prop (SCODE = 0x%08lX)\n"), sc ); goto error; }
// Now convert all the strings in this temp duplicate
if ( sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, lpPropToAdd, 1, 0)) { DebugTrace(TEXT("SetProps() - error convert W to A\n")); goto error; } }
/* Create a new property value list entry.
* * NOTE! This automatically marks the property as dirty and writeable. */ if (FAILED(sc = ScCreateSPV( lpIPDAT, lpPropToAdd ? lpPropToAdd : &(lpPropArray[iProp]), &lpLstSPVNew))) { goto error; }
/* Link the new property to our list of props.
*/ LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPV) , &(lpLstSPVNew->lstlnk)); lpIPDAT->ulCount += 1;
nextProp: UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropToAdd); }
if (lppProblems && lpProblems->cProblem) { *lppProblems = lpProblems; }
else { UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems); }
goto out;
error: UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPVNew); UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems); UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0); UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropToAdd);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_DeleteProps - * Purpose: * Deletes the properties listed in lpPropTagArray from the IPropData * object. Returns a list of problems in <lppProblems) if there were * problems deleting specific properties, NULL If there weren't any. * * Arguments: * lpIPDAT The IPropData object whose properties are to be * deleted. * lpPropTagArray Pointer to a counted array of property tags of the * properties to be deleted. Must not be NULL. * lppProblems Pointer to address of a property problem structure * to be returned. NULL if no problem array is * desired. * Returns: * HRESULT */ STDMETHODIMP IPDAT_DeleteProps( LPIPDAT lpIPDAT, LPSPropTagArray lpPropTagArray, LPSPropProblemArray FAR *lppProblems) { SCODE sc = S_OK; LPSPropProblemArray lpProblems = NULL; int iProp; LPULONG lpulProp2Find;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, DeleteProps, lpVtbl)) { DebugTrace( TEXT("IPDAT::DeleteProps() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_DeleteProps( lpIPDAT, lpPropTagArray, lppProblems );
#endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* Check access rights...
*/ if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE)) { sc = MAPI_E_NO_ACCESS; goto error; }
if (lppProblems) { /* Initially indicate no problems.
*/ *lppProblems = NULL;
/* Allocate the property problem array.
* Because we expect the property list to be of TEXT("reasonable") size we * go ahead and allocate enough entries for every property to have a * problem. */ //$REVIEW This is a place where a MAPI reallocBuf function would be useful.
if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , CbNewSPropProblemArray(lpPropTagArray->cValues) , &lpProblems))) { goto error; }
lpProblems->cProblem = 0; }
// Loop through the list of properties to delete..
for ( iProp = 0, lpulProp2Find = ((LPULONG)(lpPropTagArray->aulPropTag)) ; iProp < (int)(lpPropTagArray->cValues) ; lpulProp2Find++, iProp++) { LPPLSTLNK lppLstLnk; LPLSTSPV lpLstSPV;
/* If a writable property with the given ID already exists then
* delete it. * * If a readonly property with the given ID already exists then * include an error in the problem array. */
if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , *lpulProp2Find)) && (lpLstSPV = (LPLSTSPV) (*lppLstLnk))) { /* If it is readonly then put an entry into the problem
* array. */ if (!(lpLstSPV->ulAccess & IPROP_READWRITE)) { AddProblem( lpProblems , iProp , *lpulProp2Find , MAPI_E_NO_ACCESS);
continue; }
/* Unlink the found property and free its memory.
*/ UnlinkLstLnk( lppLstLnk); lpIPDAT->ulCount -= 1; FreeLpLstSPV( lpIPDAT, lpLstSPV); } }
if (lppProblems && lpProblems->cProblem) { *lppProblems = lpProblems; }
else { UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems); }
goto out;
error: UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems); UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
//---------------------------------------------------------------------------
// Name: FTagExists()
//
// Description:
// Determines if a Proptag exists in proptag array.
//
// Parameters:
// Returns:
// Effects:
// Notes:
// Revision:
//---------------------------------------------------------------------------
static BOOL FTagExists( LPSPropTagArray lptaga, ULONG ulTagToFind ) { LONG ctag = (LONG)lptaga->cValues - 1;
for ( ; ctag >= 0; --ctag ) { if ( lptaga->aulPropTag[ctag] == ulTagToFind ) return TRUE; }
return FALSE; }
/*
- HrCopyProps - * Purpose: * Copies properties from an IPropData object to * another object with an IMAPIProp interface. * * If lpptaInclude is not null then only properties listed by it will * be copied. If lpptaExclude is not NULL then none of the properties * listed by it will be copied regardless of whether they appear in * lpptaInclude. PROP_TYPEs in lpptaInclude and lpptaExclude are * ignored. * * Property names are copied! * If a property is named in the source object (lpIPDAT) and the name * does not exist in the destination object, a new named property ID * will be requested from the destination * * If the IMAPIPropData interface is supplied for the destination * then individual property access flags will be copied to the destination. * * Arguments: * lpIPDATSrc The source IPropData object. * lpIPDATDst The destination IPropData object. May be NULL. * lpmpDst The destination IMAPIProp object. May NOT be NULL. * lpptaInclude Pointer to a counted array of property tags of * properties that will be copied. May be NULL. * lpptaExclude Pointer to a counted array of property tags of * properties not to be copied. May be NULL. * ulFlags MAPI_MOVE * MAPI_NOREPLACE * MAPI_DIALOG (not supported) * MAPI_STD_DIALOG (not supported) * lppProblems Pointer to memory location which will receive a * pointer the the list of problems. NULL if no * propblem array is desired. * * Returns: * HRESULT * * Side effects: * * Notes: * * Rewrote copy prop handling to call Destination MAPIProp object twice. Once * for Names to ID mappings and the other for one SetProps. * * Errors: */ STDMETHODIMP HrCopyProps ( LPIPDAT lpIPDATSrc, LPPROPDATA lpIPDATDst, LPMAPIPROP lpmpDst, LPSPropTagArray lptagaInclude, LPSPropTagArray lptagaExclude, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems) { SCODE sc = S_OK; HRESULT hr; LPSPropProblemArray lpProbDest = NULL; LPSPropProblemArray lpOurProblems = NULL; LPSPropTagArray lptagaDst = NULL; LPSPropValue rgspvSrcProps = NULL; ULONG FAR * rgulSrcAccess = NULL; ULONG cPropsSrc; LPSPropTagArray lptagaSrc = NULL; LPSPropTagArray lptagaNamedIDTags = NULL; ULONG FAR * rgulSpvRef; WORD idx; ULONG cPropNames = 0; LPMAPINAMEID FAR * lppPropNames = NULL; LPSPropTagArray lpNamedTagsDst = NULL; LPSPropValue lpspv; #if DEBUG
ULONG cSrcProps = lpIPDATSrc->ulCount; #endif
// If the MAPI_NOREPLACE flag was set then we need to know what properties
// the destination already has.
if ( ulFlags & MAPI_NOREPLACE ) { hr = lpmpDst->lpVtbl->GetPropList( lpmpDst, MAPI_UNICODE, &lptagaDst );
if ( HR_FAILED( hr ) ) goto error; }
// If MAPI_MOVE, we need to know what props we have to delete from the source.
// Get source access rights if destination supports IMAPIPropData
if ( lpIPDATDst || ulFlags & MAPI_MOVE ) { if ( !lptagaInclude ) { hr = IPDAT_GetPropList( lpIPDATSrc, 0, &lptagaSrc );
if ( HR_FAILED( hr ) ) goto error; } else { // Dup the include prop tag list so we can write in
// updated Named IDs
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc, CbSPropTagArray( lptagaInclude ), &lptagaSrc ); if ( FAILED( sc ) ) { hr = ResultFromScode(sc); goto error; }
memcpy( lptagaSrc, lptagaInclude, CbSPropTagArray( lptagaInclude ) ); }
if ( lpIPDATDst ) { hr = IPDAT_HrGetPropAccess( lpIPDATSrc, &lptagaInclude, &rgulSrcAccess );
if ( HR_FAILED( hr ) ) goto error; } }
// Preset the problem array pointer to NULL (ie no problems).
if ( lppProblems ) { *lppProblems = NULL;
// Setup our own problem array if there are any problems with
// GetIDsFromNames or GetNamesFromIDs...
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc, CbNewSPropProblemArray( lpIPDATSrc->ulCount ), &lpOurProblems ); if ( FAILED( sc ) ) { hr = ResultFromScode( sc ); goto error; }
lpOurProblems->cProblem = 0; }
hr = IPDAT_GetProps( lpIPDATSrc, lptagaInclude, 0, &cPropsSrc, &rgspvSrcProps );
if ( HR_FAILED( hr ) ) { goto error; }
// allocate a proptag array to handle named ID mapping
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc, CbNewSPropTagArray( cPropsSrc ), &lptagaNamedIDTags );
if ( FAILED( sc ) ) { hr = ResultFromScode( sc ); goto error; }
// Allocate the Named ID cross ref array to allow cross ref of
// Named ID back to the original property.
sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc, cPropsSrc * sizeof(ULONG), &rgulSpvRef );
if ( FAILED( sc ) ) { hr = ResultFromScode( sc ); goto error; }
lptagaNamedIDTags->cValues = 0;
// strafe throught the prop array to deal with excluded
// and/or named ID proptags
for ( lpspv = rgspvSrcProps, idx = 0;
idx < cPropsSrc;
++idx, ++lpspv ) { // check for excluded props
if ( lptagaExclude ) { if ( FTagExists( lptagaExclude, lpspv->ulPropTag ) ) { if ( lptagaSrc ) { // We're assuming that IMAPIPropData keeps the proplist
// and the propvalue array in sync.
Assert( lptagaSrc->aulPropTag[idx] == lpspv->ulPropTag ); lptagaSrc->aulPropTag[idx] = PR_NULL; }
lpspv->ulPropTag = PR_NULL;
continue; } }
// if in named ID range.
if ( MIN_NAMED_PROP_ID <= PROP_ID(lpspv->ulPropTag) && PROP_ID(lpspv->ulPropTag) <= MAX_NAMED_PROP_ID ) { lptagaNamedIDTags->aulPropTag[lptagaNamedIDTags->cValues] = lpspv->ulPropTag;
// remember which propval ID references
rgulSpvRef[lptagaNamedIDTags->cValues] = (ULONG)idx; ++lptagaNamedIDTags->cValues; } }
// Did we find any named IDs
if ( lptagaNamedIDTags->cValues ) { hr = IPDAT_GetNamesFromIDs( lpIPDATSrc, &lptagaNamedIDTags, NULL, 0, &cPropNames, &lppPropNames );
// Report any failures in our problem array.
if ( hr ) { goto NameIDProblem; }
// assert that we got what we requested
Assert( cPropNames == lptagaNamedIDTags->cValues );
// Get Tag IDs from the Destination, create them if they don't exist.
hr = lpmpDst->lpVtbl->GetIDsFromNames( lpmpDst, cPropNames, lppPropNames, MAPI_CREATE, &lpNamedTagsDst );
// Deal with Named ID errors/warnings.
NameIDProblem:
if ( hr ) { for ( idx = 0; idx < lptagaNamedIDTags->cValues ;idx++ ) { // if we got a MAPI failure set problem array with that error for the
// affected proptags
if ( HR_FAILED( hr ) ) { if ( lppProblems ) { AddProblem( lpOurProblems, rgulSpvRef[idx], lptagaNamedIDTags->aulPropTag[idx], GetScode( hr ) ); } } else { Assert( cPropNames == lptagaNamedIDTags->cValues );
if ( !lppPropNames[idx]->Kind.lpwstrName || ( lpNamedTagsDst && PROP_TYPE(lpNamedTagsDst->aulPropTag[idx]) == PT_ERROR ) ) { if ( lppProblems ) { AddProblem( lpOurProblems, rgulSpvRef[idx], lptagaNamedIDTags->aulPropTag[idx], MAPI_E_NOT_FOUND ); } } } // Set src propval's proptag and proptag to PR_NULL so we don't
// process it any further.
rgspvSrcProps[rgulSpvRef[idx]].ulPropTag = PR_NULL; lptagaSrc->aulPropTag[rgulSpvRef[idx]] = PR_NULL; } }
// Fix up the src propvalue tags
for ( idx = 0; idx < cPropNames; ++idx ) { if ( rgspvSrcProps[rgulSpvRef[idx]].ulPropTag == PR_NULL ) continue;
rgspvSrcProps[rgulSpvRef[idx]].ulPropTag = CHANGE_PROP_TYPE( lpNamedTagsDst->aulPropTag[idx], PROP_TYPE( rgspvSrcProps[rgulSpvRef[idx]].ulPropTag ) ); } }
// If propval exists in the destination remove from src propvals.
// We do this here after the named IDs have been fixed up.
if ( ulFlags & MAPI_NOREPLACE ) { // spin through the props one more time
for ( lpspv = rgspvSrcProps, idx = 0;
idx < cPropsSrc;
++idx, ++lpspv ) { if ( FTagExists( lptagaDst, lpspv->ulPropTag ) ) { // ensure that proptag list and propval array are in sync
Assert( !lpIPDATDst || lpspv->ulPropTag == lptagaSrc->aulPropTag[idx] );
lpspv->ulPropTag = PR_NULL;
if ( lpIPDATDst ) { // We can't be modifying access rights on NOREPLACE
lptagaSrc->aulPropTag[idx] = PR_NULL; } } } }
// Now set the props...
hr = lpmpDst->lpVtbl->SetProps( lpmpDst, cPropsSrc, rgspvSrcProps, &lpProbDest );
if ( HR_FAILED( hr ) ) goto error;
// Handle MAPI_MOVE
if ( ulFlags & MAPI_MOVE ) { // Do we care about problems if delete from the source has any? Nah...
hr = IPDAT_DeleteProps( lpIPDATSrc, lptagaSrc, NULL ); if ( HR_FAILED( hr ) ) goto error; }
// Transfer the access rights
if ( lpIPDATDst ) { // Did we find any Named IDs
if ( lptagaNamedIDTags->cValues ) { // fix up the proptags to match the dest.
for ( idx = 0; idx < cPropNames; ++idx ) { if ( lptagaSrc->aulPropTag[rgulSpvRef[idx]] == PR_NULL ) continue;
lptagaSrc->aulPropTag[rgulSpvRef[idx]] = CHANGE_PROP_TYPE( lpNamedTagsDst->aulPropTag[idx], PROP_TYPE( lptagaSrc->aulPropTag[rgulSpvRef[idx]] ) ); } }
hr = IPDAT_HrSetPropAccess( (LPIPDAT)lpIPDATDst, lptagaSrc, rgulSrcAccess );
if ( HR_FAILED( hr ) ) goto error; }
// Return the problem array if requested and there were problems...
if ( lppProblems ) { if ( lpProbDest && lpProbDest->cProblem ) { Assert( lpProbDest->cProblem + lpOurProblems->cProblem <= cSrcProps );
// move/merge the lpProbDest (dest) into our problem array
for ( idx = 0; idx < lpProbDest->cProblem; idx++ ) { AddProblem( lpOurProblems, lpProbDest->aProblem[idx].ulIndex, lpProbDest->aProblem[idx].ulPropTag, lpProbDest->aProblem[idx].scode ); }
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpProbDest ); }
if ( lpOurProblems->cProblem ) { *lppProblems = lpOurProblems; hr = ResultFromScode( MAPI_W_ERRORS_RETURNED ); } } else { // ...else dispose of the problem array.
UNKOBJ_Free( (LPUNKOBJ)lpIPDATSrc, lpOurProblems ); }
out:
UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaSrc ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaDst ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgulSrcAccess ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgspvSrcProps ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaNamedIDTags ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lppPropNames ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpNamedTagsDst ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgulSpvRef );
DebugTraceResult( HrCopyProps, hr );
return hr;
error: /* Free the prop problem array.
*/ UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpOurProblems ); UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpProbDest ); goto out; }
/*
- IPDAT_CopyTo - * Purpose: * Copies all but the excluded properties from this IPropData object to * another object which must support the IMAPIProp interface. * * Property names are copied! * If a property is named in the source object (lpIPDAT) and the name * does not exist in the destination object, a new named property ID * will be requested from the destination * * If the IMAPIPropData interface is supported on the destination is not * excluded by the caller then individual property access flags will be * copied to the destination. * * Arguments: * lpIPDAT The source IPropData object. * ciidExclude Count of excluded interfaces in rgiidExclude * rgiidExclude Array of iid's specifying excluded interfaces * lpPropTagArray Pointer to a counted array of property tags of * properties not to be copied, can be NULL * ulUIParam Handle of parent window cast to ULONG, NULL if * no dialog reqeuested * lpInterface Interface ID of the interface of lpDestObj * (not used). * lpvDestObj destination object * ulFlags MAPI_MOVE * MAPI_NOREPLACE * MAPI_DIALOG (not supported) * MAPI_STD_DIALOG (not supported) * lppProblems Pointer to memory location which will receive a * pointer the the list of problems. NULL if no * propblem array is desired. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_CopyTo ( LPIPDAT lpIPDAT, ULONG ciidExclude, LPCIID rgiidExclude, LPSPropTagArray lpExcludeProps, ULONG_PTR ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpInterface, LPVOID lpDestObj, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems) { HRESULT hResult = hrSuccess; LPUNKNOWN lpunkDest = (LPUNKNOWN) lpDestObj; LPPROPDATA lpPropData = NULL; LPMAPIPROP lpMapiProp = NULL; UINT ucT; LPCIID FAR *lppiid;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, CopyTo, lpVtbl)) { DebugTrace( TEXT("IPDAT::CopyTo() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_CopyTo( lpIPDAT, ciidExclude, rgiidExclude, lpExcludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
#endif // not NO_VALIDATION
// Make sure we're not copying to ourselves
if ( (LPVOID)lpIPDAT == (LPVOID)lpDestObj ) { DebugTrace( TEXT("IProp: Copying to self is not supported\n") ); return ResultFromScode( MAPI_E_NO_ACCESS ); }
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* Determine the best interface to copy contents into. It really doesn't
* matter what MAPI specified as the interface ID to the destination. We * only understand IMAPIPropData and IMAPIProp. * * We depend on IUnknown being last in the array of IDs that we support. */ for ( ucT = (UINT)(lpIPDAT->ulcIID), lppiid = (LPCIID FAR *) argpiidIPDAT ; ucT > CIID_IPROP_INHERITS ; lppiid++, ucT--) { /* See if the interface is excluded.
*/ if ( !FIsExcludedIID( *lppiid, rgiidExclude, ciidExclude) && !HR_FAILED(lpunkDest->lpVtbl->QueryInterface( lpunkDest , *lppiid , (LPVOID FAR *) &lpMapiProp))) { /* We found a good destination interface so quit looking.
*/ break; } }
/* Determine which interface we ended up with and set up to use that
* interface. */ if (ucT <= CIID_IPROP_INHERITS) { /* Didn't find an interface at least as good as IProp so we can't
* do the CopyTo. */ hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); goto error; }
/* If we ended up with IPropData as the best common interface then use it.
*/ if (*lppiid == &IID_IMAPIPropData) { lpPropData = (LPPROPDATA) lpMapiProp; }
/* Copy all properties that are not excluded. Copy extra prop access
* information if IPropData is supported by the destination. */ if (HR_FAILED(hResult = HrCopyProps( lpIPDAT , lpPropData , lpMapiProp , NULL , lpExcludeProps , ulFlags , lppProblems))) { goto error; }
out: /* Release the object obtained with QueryInterface.
*/ if (lpMapiProp) { UlRelease(lpMapiProp); }
/* Free the prop tag array that we got from the destination.
*/ UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
DebugTraceResult( IPDAT_CopyTo, hResult); return hResult;
error: /* Free the prop problem array.
*/ UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, GetScode(hResult), 0); goto out; }
/*
- IPDAT_CopyProps - * Purpose: * Copies all the listed properties from this IPropData object to * another object which must support the IMAPIProp interface. * * Property names are copied! * If a property is named in the source object (lpIPDAT) and the name * does not exist in the destination object, a new named property ID * will be requested from the destination * * If the IMAPIPropData interface is supported on the destination is not * excluded by the caller then individual property access flags will be * copied to the destination. * * Arguments: * lpIPDAT The source IPropData object. * lpPropTagArray Pointer to a counted array of property tags of * properties to be copied, CAN NOT be NULL * ulUIParam Handle of parent window cast to ULONG, NULL if * no dialog reqeuested * lpInterface Interface ID of the interface of lpDestObj * (not used). * lpvDestObj destination object * ulFlags MAPI_MOVE * MAPI_NOREPLACE * MAPI_DIALOG (not supported) * MAPI_STD_DIALOG (not supported) * lppProblems Pointer to memory location which will receive a * pointer the the list of problems. NULL if no * propblem array is desired. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_CopyProps ( LPIPDAT lpIPDAT, LPSPropTagArray lpPropTagArray, ULONG_PTR ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpInterface, LPVOID lpDestObj, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems) { HRESULT hResult; LPUNKNOWN lpunkDest = (LPUNKNOWN) lpDestObj; LPPROPDATA lpPropData = NULL; LPMAPIPROP lpMapiProp = NULL; UINT ucT; LPCIID FAR *lppiid;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, CopyProps, lpVtbl)) { DebugTrace( TEXT("IPDAT::CopyProps() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_CopyProps( lpIPDAT, lpPropTagArray, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
#endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* Determine the best interface to copy contents into. It really doesn't
* matter what MAPI specified as the interface ID to the destination. We * only understand IMAPIPropData and IMAPIProp. * * We depend on IUnknown being last in the array of IDs that we support. */ for ( ucT = (UINT)(lpIPDAT->ulcIID), lppiid = (LPCIID FAR *) argpiidIPDAT ; ucT > CIID_IPROP_INHERITS ; lppiid++, ucT--) { /* See if the interface is excluded.
*/ if (!HR_FAILED(lpunkDest->lpVtbl->QueryInterface( lpunkDest , *lppiid , (LPVOID FAR *) &lpMapiProp))) { /* We found a good destination interface so quit looking.
*/ break; } }
/* Determine which interface we ended up with and set up to use that
* interface. */ if (ucT <= CIID_IPROP_INHERITS) { /* Didn't find an interface at least as good as IProp so we can't
* do the CopyTo. */ hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); goto error; }
/* If we ended up with IPropData as the best common interface then use it.
*/ if (*lppiid == &IID_IMAPIPropData) { lpPropData = (LPPROPDATA) lpMapiProp; }
/* Copy all properties that are not excluded. Copy extra prop access
* information if IPropData is supported by the destination. */ if (HR_FAILED(hResult = HrCopyProps( lpIPDAT , lpPropData , lpMapiProp , lpPropTagArray , NULL , ulFlags , lppProblems))) { goto error; }
out: /* Release the object obtained with QueryInterface.
*/ if (lpMapiProp) { UlRelease(lpMapiProp); }
/* Free the prop tag array that we got from the destination.
*/ UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
DebugTraceResult( IPDAT_CopyProps, hResult); return hResult;
error: /* Free the prop problem array.
*/ UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, GetScode(hResult), 0); goto out; }
/*
- IPDAT_GetNamesFromIDs - * Purpose: * Return the unicode string associated with the given ID * * Arguments: * lpIPDAT The IPropData object whose property name is desired. * lppPropTags Pointer to pointer to a property tag array listing * the properties whose names are desired. If it * points to NULL then we will create a property tag * array listing ALL properties available from the * IPropData object. * ulFlags reserved, must be 0 * lpcPropNames Pointer to memory location which will receive the * count of strings listed in lpppszPropNames. * lpppszPropNames pointer to variable for address of an array of * unicode property name strings. Freed by * MAPIFreeBuffer * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_GetNamesFromIDs ( LPIPDAT lpIPDAT, LPSPropTagArray FAR * lppPropTags, LPGUID lpPropSetGuid, ULONG ulFlags, ULONG FAR * lpcPropNames, LPMAPINAMEID FAR * FAR *lpppPropNames) { SCODE sc = S_OK; LPSPropTagArray lpsPTaga = NULL; LPSPropTagArray lpsptOut = NULL; ULONG cTags; ULONG FAR *lpulProp2Find; LPMAPINAMEID FAR * lppPropNames = NULL; LPMAPINAMEID FAR * lppNameT; BOOL fWarning = FALSE;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetNamesFromIDs, lpVtbl)) { DebugTrace( TEXT("IPDAT::GetNamesFromIDs() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_GetNamesFromIDs( lpIPDAT, lppPropTags, lpPropSetGuid, ulFlags, lpcPropNames, lpppPropNames);
#endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* If no prop tag array was passed in then create one...
*/ if (!(*lppPropTags)) { if (lpPropSetGuid && !memcmp(lpPropSetGuid, &PS_MAPI, sizeof(GUID))) { //
// We're dealing with the mapi property set
// In this case, we need to build up a list
// of all the properties on this object less
// than 0x8000 - not quite the same as GetPropList().
//
sc = ScMakePropList(lpIPDAT, lpIPDAT->ulCount, (LPLSTLNK) lpIPDAT->lpLstSPV, &lpsPTaga, (ULONG)0x8000);
if (FAILED(sc)) { goto error; }
//
// For each one of these proptags, we need to
// build up the names for them using the PS_MAPI
// guid.
//
sc = ScMakeMAPINames(lpIPDAT, lpsPTaga, &lppPropNames); if (FAILED(sc)) { goto error; } *lpppPropNames = lppPropNames; *lpcPropNames = lpsPTaga->cValues; *lppPropTags = lpsPTaga;
// Done: we're outta here!
goto out;
}
if (FAILED(sc = ScMakeNamePropList( lpIPDAT, (lpIPDAT->ulNextMapID-0x8000), lpIPDAT->lpLstSPN, &lpsPTaga, ulFlags, lpPropSetGuid))) { goto error; } } /* ...else use the one that was passed in.
*/ else if (*lppPropTags) { lpsPTaga = *lppPropTags; }
/* Allocate the array of name pointers.
*/ if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , lpsPTaga->cValues * sizeof(LPMAPINAMEID) , (LPVOID) &lppPropNames))) { goto error; }
/* Find each property in the list and see if it has a UNICODE name.
*/ for ( cTags = lpsPTaga->cValues , lpulProp2Find = (ULONG FAR *) (lpsPTaga->aulPropTag) , lppNameT = lppPropNames ; cTags ; cTags--, lpulProp2Find++, lppNameT++) { LPPLSTLNK lppLstLnk; LPLSTSPN lpLstSPN;
/* If there is a ID to NAME map for the property and it has a name.
* then copy the UNICODE string and pass it back. */ if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)&(lpIPDAT->lpLstSPN) , *lpulProp2Find)) && (lpLstSPN = (LPLSTSPN) (*lppLstLnk)) && lpLstSPN->lpPropName) { sc = ScDupNameID(lpIPDAT, lppPropNames, // Alloc'd more here.
lpLstSPN->lpPropName, lppNameT); if (FAILED(sc)) { goto error; } }
/* Else no ID to NAME map exists for the property so return NULL.
*/ else { /* The property has no name, Flag a warning.
*/ *lppNameT = NULL; fWarning = TRUE; } }
*lpppPropNames = lppPropNames; if (!(*lppPropTags)) { *lppPropTags = lpsPTaga; } *lpcPropNames = lpsPTaga->cValues;
goto out;
error: /* If we created the tag array then we need to free it on error.
* lpsPTaga must be NULL on MAPI_E_INVALID_PARAMETER. */ if (lpsPTaga && !(*lppPropTags)) { UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpsPTaga); }
/* Free the array of pointers to names and names.
*/ UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lppPropNames);
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
if ( fWarning ) sc = MAPI_W_ERRORS_RETURNED;
return MakeResult(sc); }
/*
- IPDAT_GetIDsFromNames - * Purpose: * Return the property ID for the properties named by the supplied * UNICODE strings. If no property ID is currently TEXT("named") by one of * the strings and MAPI_CREATE is specified in the flags then a new * property ID in the range 0x8000 to 0xfffe will be allocated for that * string a returned in the property tag array. * * If problems occur (eg. no name found and can't create) then the entry * for the name that had the problem will be set to have a NULL PROP_ID * and PT_ERROR type. * * All property tags successfully returned will have type PT_UNSPECIFIED. * * Arguments: * lpIPDAT The IPropData object for which property IDs are * requested. * cPropNames Count of strings in for which IDs are requested. * lppszPropNames Pointer ot array of pointers unicode strings which * name the properties for which IDs are requested. * ulFlags Reserved, must be 0 * lppPropTags Pointer to memory location which will receive a * pointer to a new property tag array listing the * requested property tags. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_GetIDsFromNames ( LPIPDAT lpIPDAT, ULONG cPropNames, LPMAPINAMEID FAR * lppPropNames, ULONG ulFlags, LPSPropTagArray FAR * lppPropTags) { SCODE sc = S_OK; ULONG ulcWarnings = 0; LPSPropTagArray lpPTaga = NULL; LPULONG lpulProp2Set;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetIDsFromNames, lpVtbl)) { DebugTrace( TEXT("IPDAT::GetIDsFromNames() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
Validate_IMAPIProp_GetIDsFromNames( lpIPDAT, cPropNames, lppPropNames, ulFlags, lppPropTags);
#endif // not NO_VALIDATION
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* If the caller wants to change our ID to NAME mapping, make sure access
* is allowed. */ if ( (ulFlags & MAPI_CREATE) && !(lpIPDAT->ulObjAccess & IPROP_READWRITE)) { sc = MAPI_E_NO_ACCESS; goto error; }
/*
* Check to see if there are no names being passed */ if (!cPropNames) { /*
* There aren't so build up a list of all proptags > 0x8000 */ sc = ScMakeNamePropList( lpIPDAT, (lpIPDAT->ulNextMapID-0x8000), lpIPDAT->lpLstSPN, &lpPTaga, 0, NULL); if (FAILED(sc)) { goto error; }
*lppPropTags = lpPTaga; goto out; }
/* Allocate space for the new SPropTagArray.
*/ if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , CbNewSPropTagArray(cPropNames) , (LPVOID) &lpPTaga))) { goto error; }
lpPTaga->cValues = cPropNames;
/* Find each ID in the list passed in.
*/ for ( lpulProp2Set = (LPULONG) (lpPTaga->aulPropTag) ; cPropNames ; cPropNames--, lpulProp2Set++, lppPropNames++) { LPLSTSPN lpLstSPN;
//
// First see if it's from PS_MAPI
//
if (!memcmp((*lppPropNames)->lpguid, &PS_MAPI, sizeof(GUID))) { //
// Yup, it is, so validate that it is a MNID_ID
//
if ((*lppPropNames)->ulKind == MNID_ID) { *lpulProp2Set = (*lppPropNames)->Kind.lID; } else { *lpulProp2Set = PROP_TAG( PT_ERROR, 0); ulcWarnings++; } continue; }
//
// Next, validate that if we have a PS_PUBLIC_STRINGS...
//
if (!memcmp((*lppPropNames)->lpguid, &PS_PUBLIC_STRINGS, sizeof(GUID))) { //
// ...that it is a MNID_STRING
//
if ((*lppPropNames)->ulKind != MNID_STRING) { //
// It's not, so it's a malformed name
//
*lpulProp2Set = PROP_TAG( PT_ERROR, 0); ulcWarnings++; continue; } }
/* Try to find the name in our list of ID to NAME maps.
*/ for ( lpLstSPN = lpIPDAT->lpLstSPN ; lpLstSPN ; lpLstSPN = (LPLSTSPN) (lpLstSPN->lstlnk.lpNext)) { /* If the name doesn't match keep looking.
*/ if (FEqualNames( *lppPropNames, lpLstSPN->lpPropName )) { break; } }
/* If we found a matching NAME then set the ID.
*/ if (lpLstSPN) { *lpulProp2Set = lpLstSPN->lstlnk.ulKey; } else if (ulFlags & MAPI_CREATE) {
/* Create a new map if we didn't find one and MAPI_CREATE was
* specified. */
/* Allocate space for the new ID to NAME map.
*/ if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , sizeof(LSTSPN) , (LPVOID) &lpLstSPN))) { goto error; }
sc = ScDupNameID(lpIPDAT, lpLstSPN, // Alloc'd more here.
*lppPropNames, &(lpLstSPN->lpPropName));
if (FAILED(sc)) { //
// Don't try to add it.
//
UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPN); goto error; }
/* Set the ID to NAME map.
*/ lpLstSPN->lstlnk.ulKey = PROP_TAG( 0, lpIPDAT->ulNextMapID++);
/* Link the new map as the first list element.
*/ LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPN) , &(lpLstSPN->lstlnk));
/* Return the newly created Prop Tag.
*/ *lpulProp2Set = lpLstSPN->lstlnk.ulKey; }
/* Else we didn't find the NAME and we can't create one so
* set ID to error. */ else { *lpulProp2Set = PROP_TAG( PT_ERROR, 0); ulcWarnings++; } }
*lppPropTags = lpPTaga;
if (ulcWarnings) { sc = MAPI_W_ERRORS_RETURNED; }
goto out;
error: UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPTaga); UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_HrSetObjAccess - * Purpose: * Sets the read/write access and the clean/dirty status of IPropData * object as a whole. * * The read/write access bits can be used to prevent a client from * changing or deleting a property via the IMAPIProp methods or from * changing the read/write access and status bits of individual properties. * It can also be used to prevent the creation of new properties or * property names. * * Arguments: * lpIPDAT The IPropData object for which access rights and * status will be set. * ulAccess The new access/status flags to be set. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_HrSetObjAccess ( LPIPDAT lpIPDAT, ULONG ulAccess ) { SCODE sc = S_OK;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrSetObjAccess, lpVtbl)) { DebugTrace( TEXT("IPDAT::HrSetObjAccess() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif
if (ulAccess & ~(IPROP_READONLY | IPROP_READWRITE)) { return ResultFromScode(MAPI_E_UNKNOWN_FLAGS); }
if ( !(ulAccess & (IPROP_READONLY | IPROP_READWRITE)) || ( (ulAccess & (IPROP_READONLY | IPROP_READWRITE)) == (IPROP_READONLY | IPROP_READWRITE))) { DebugTrace( TEXT("IPDAT::HrSetObjAccess() - Conflicting access flags.\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
lpIPDAT->ulObjAccess = ulAccess;
/*
*out: */ UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_HrSetPropAccess - * Purpose: * Sets the read/write access and the clean/dirty status of individual * properties contained by the IPropData object. * * The read/write access bits can be used to prevent a client from * changing or deleting a property via the IMAPIProp methods. * * The clean/dirty bits can be used to determine if a client has changed * a writable property. * * Arguments: * lpIPDAT The IPropData object for which property access * rights and status will be set. * lpsPropTagArray List of property tags whose access/status will change. * rgulAccess Array of new access/status flags in the same order as * as the list of property tags in <lpsPropTagArray>. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_HrSetPropAccess( LPIPDAT lpIPDAT, LPSPropTagArray lpsPropTagArray, ULONG FAR * rgulAccess) { SCODE sc = S_OK; ULONG ulcProps; ULONG FAR *lpulPropTag; ULONG FAR *lpulAccess;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrSetPropAccess, lpVtbl)) { DebugTrace( TEXT("IPDAT::HrSetPropAccess() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
/* Validate parameters.
*/ if ( FBadDelPTA(lpsPropTagArray) || IsBadReadPtr(rgulAccess, (UINT) (lpsPropTagArray->cValues)*sizeof(ULONG))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
/* Make sure they don't try setting reserved access bits.
*/ for ( lpulAccess = rgulAccess + lpsPropTagArray->cValues ; --lpulAccess >= rgulAccess ; ) { if ( (*lpulAccess & ~( IPROP_READONLY | IPROP_READWRITE | IPROP_CLEAN | IPROP_DIRTY)) || !(*lpulAccess & (IPROP_READONLY | IPROP_READWRITE)) || ( (*lpulAccess & (IPROP_READONLY | IPROP_READWRITE)) == (IPROP_READONLY | IPROP_READWRITE)) || !(*lpulAccess & (IPROP_CLEAN | IPROP_DIRTY)) || ( (*lpulAccess & (IPROP_CLEAN | IPROP_DIRTY)) == (IPROP_CLEAN | IPROP_DIRTY))) { DebugTrace( TEXT("IPDAT::HrSetPropAccess() - Conflicting access flags.\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); } } #endif
/* The exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
// Loop through the list of properties on which to set access/status.
for ( ulcProps = lpsPropTagArray->cValues , lpulPropTag = (ULONG FAR *)(lpsPropTagArray->aulPropTag) , lpulAccess = rgulAccess ; ulcProps ; ulcProps--, lpulPropTag++, lpulAccess++) { LPPLSTLNK lppLstLnk;
/* If the property is in our list then set the new access rights and
* status flags for it. If it's not in our list then ignore it. */ if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , *lpulPropTag)) { ((LPLSTSPV) (*lppLstLnk))->ulAccess = *lpulAccess; } }
/*
*out: */ UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_HrGetPropAccess - * Purpose: * Returns the read/write access and the clean/dirty status of individual * properties contained by the IPropData object. * * The read/write access bits can be used to prevent a client from * changing or deleting a property via the IMAPIProp methods. * * The clean/dirty bits can be used to determine if a client has changed * a writable property. * * Arguments: * lpIPDAT The IPropData object for which property access * rights and status is requested. * lpsPropTagArray List of property tags whose access/status is requested. * lprgulAccess Pointer to the memory location which will receive a * pointer to an array of access/status flags in the same * order as the list of property tags in <lpsPropTagArray>. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_HrGetPropAccess( LPIPDAT lpIPDAT, LPSPropTagArray FAR * lppsPropTagArray, ULONG FAR * FAR * lprgulAccess) { SCODE sc = S_OK; HRESULT hResult = hrSuccess; ULONG ulcProps; LPSPropTagArray lpsPTaga = NULL; ULONG FAR *lpulPropTag; ULONG FAR *lpulAccessNew = NULL; ULONG FAR *lpulAccess;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrGetPropAccess, lpVtbl)) { DebugTrace( TEXT("IPDAT::HrGetPropAccess() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
/* Validate parameters.
*/ if ( IsBadReadPtr( lppsPropTagArray, sizeof(LPSPropTagArray)) || (*lppsPropTagArray && FBadDelPTA(*lppsPropTagArray)) || IsBadWritePtr( lprgulAccess, sizeof(ULONG FAR *))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* If a list of tags was passed in then use it...
*/ if (lppsPropTagArray && *lppsPropTagArray) { lpsPTaga = *lppsPropTagArray; } else { /* ...else get a list of tags for all properties in our list.
*/ sc = ScMakePropList(lpIPDAT, lpIPDAT->ulCount, (LPLSTLNK) lpIPDAT->lpLstSPV, &lpsPTaga, (ULONG) -1); if (FAILED(sc)) { goto error; } }
/* Allocate space for the list of access rights / status flags.
*/ sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, lpsPTaga->cValues * sizeof(ULONG), &lpulAccessNew); if (FAILED(sc)) { goto error; }
/* Loop through the list of properties for which rights/flags are
* requested. */ for ( ulcProps = lpsPTaga->cValues , lpulPropTag = (ULONG FAR *)(lpsPTaga->aulPropTag) , lpulAccess = lpulAccessNew ; ulcProps ; ulcProps--, lpulPropTag++, lpulAccess++) { LPPLSTLNK lppLstLnk;
/* If the property is in our list then set the new access rights and
* status flags for it. If it's not in our list then ignore it. */ if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , *lpulPropTag)) { *lpulAccess = ((LPLSTSPV) (*lppLstLnk))->ulAccess; } }
/* If requested return a tag list to the caller.
*/ if (lppsPropTagArray && !*lppsPropTagArray) { *lppsPropTagArray = lpsPTaga; }
/* Return the access rights / status flags.
*/ *lprgulAccess = lpulAccessNew;
goto out;
error: /* If we created the tag array then free it.
*/ if (!lppsPropTagArray || !*lppsPropTagArray) { UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpsPTaga); }
/* Free the access rights / status flags list.
*/ UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpulAccessNew);
UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
/*
- IPDAT_HrAddObjProps - * Purpose: * Since object properties can not be created by SetProps, this method * is included so that object properties can be included in the list * of properties available from the IPropData object. Adding an object * property will result in the property tag showing up in the list when * GetPropList is called. * * Arguments: * lpIPDAT The IPropData object for which object properties are * to be added. * lpPropTags List of object properties to be added. * lprgulAccess Pointer to the memory location which will receive a * pointer to an array of problem entries if there * were problems entering the new properties. NULL if * no problems array is desired. * * Returns: * HRESULT * * Side effects: * * Errors: */ STDMETHODIMP IPDAT_HrAddObjProps( LPIPDAT lpIPDAT, LPSPropTagArray lpPropTags, LPSPropProblemArray FAR * lppProblems) { SCODE sc = S_OK; LPSPropProblemArray lpProblems = NULL; LPLSTSPV lpLstSPV = NULL; SPropValue propVal; ULONG UNALIGNED FAR *lpulPropTag; ULONG cValues;
#if !defined(NO_VALIDATION)
/* Make sure the object is valid.
*/ if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrAddObjProps, lpVtbl)) { DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad object passed\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
/* Validate parameters.
*/ if ( IsBadReadPtr(lpPropTags, CbNewSPropTagArray(0)) || IsBadReadPtr(lpPropTags, CbSPropTagArray(lpPropTags))) { DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad Prop Tag Array.\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
for ( lpulPropTag = lpPropTags->aulPropTag + lpPropTags->cValues ; --lpulPropTag >= lpPropTags->aulPropTag ; ) { if ( (PROP_ID(*lpulPropTag) == PROP_ID_NULL) || (PROP_ID(*lpulPropTag) == PROP_ID_INVALID) || (PROP_TYPE(*lpulPropTag) != PT_OBJECT)) { DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad Prop Tag.\n") ); return ResultFromScode(MAPI_E_INVALID_PARAMETER); } }
#endif
/* The error exit assumes that we are already in a critical section.
*/ UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
/* Check access rights...
*/ if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE)) { sc = MAPI_E_NO_ACCESS; goto error; }
if (lppProblems) { /* Initially indicate that there were no problems.
*/ *lppProblems = NULL;
/* Allocate a problem array that is big enough to report problems on
* all the properties. Unused entries just end up as wasted space. */ if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , CbNewSPropProblemArray(lpIPDAT->ulCount) , &lpProblems))) { goto error; }
lpProblems->cProblem = 0; }
/* Loop through the list and add/replace each property listed.
*/ memset( (BYTE *) &propVal, 0, sizeof(SPropValue)); for ( cValues = lpPropTags->cValues, lpulPropTag = (ULONG FAR *)(lpPropTags->aulPropTag) ; cValues ; lpulPropTag++, cValues--) { LPPLSTLNK lppLstLnk; LPLSTSPV lpLstSPV;
/* If the property is in the list and write enabled then delete it
* from the list. */ if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , *lpulPropTag)) { /* Make sure that we can delete the old property.
*/ if ( (lpLstSPV = (LPLSTSPV) (*lppLstLnk)) && !(lpLstSPV->ulAccess & IPROP_READWRITE)) { AddProblem( lpProblems , cValues , *lpulPropTag , MAPI_E_NO_ACCESS);
continue; }
/* Delete the old property.
*/ UnlinkLstLnk( lppLstLnk); FreeLpLstSPV( lpIPDAT, lpLstSPV); lpIPDAT->ulCount -= 1; }
/* Create a new property entry and link it to our list.
*/
propVal.ulPropTag = *lpulPropTag;
if (FAILED(sc = ScCreateSPV( lpIPDAT, &propVal, &lpLstSPV))) { goto error; }
lpLstSPV->ulAccess = IPROP_READWRITE; LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPV) , (LPLSTLNK) lpLstSPV); lpIPDAT->ulCount += 1; }
/* Return the problem array if requested and there were problems...
*/ if (lppProblems && lpProblems->cProblem) { *lppProblems = lpProblems; }
/* ...else dispose of the problem array.
*/ else { UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems); }
goto out;
error: /* Free the prop problem array.
*/ UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems); UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
out: UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
return MakeResult(sc); }
//----------------------------------------------------------------------------
// Synopsis: SCODE ScWCToAnsi()
//
// Description:
// Converts a Wide Char string to an Ansi string with the passed
// in MAPI More Allocator.
// If lpMapiAllocMore and lpBase are NULL and *lppszAnsi is not NULL
// then we assume *lppszAnsi is a pre allocated buffer
//
// Parameters:
// Returns:
// Effects:
// Notes:
// Revision:
//----------------------------------------------------------------------------
SCODE ScWCToAnsiMore( LPALLOCATEMORE lpMapiAllocMore, LPVOID lpBase, LPWSTR lpszWC, LPSTR * lppszAnsi ) { SCODE sc = S_OK; INT cch;
if ( !lpszWC ) { if(lpMapiAllocMore && lpBase) *lppszAnsi = NULL; else if(*lppszAnsi) *(*lppszAnsi) = '\0'; goto ret; }
// [PaulHi] 3/31/99 Raid 73845 Determine the actual DBCS buffer size needed
// cch = lstrlenW( lpszWC ) + 1;
cch = WideCharToMultiByte(CP_ACP, 0, lpszWC, -1, NULL, 0, NULL, NULL) + 1;
if(lpMapiAllocMore && lpBase) { sc = lpMapiAllocMore( cch, lpBase, lppszAnsi ); if ( FAILED( sc ) ) { DebugTrace( TEXT("ScWCToAnsi() OOM\n") ); goto ret; } }
if (!lppszAnsi || !WideCharToMultiByte(CP_ACP, 0, lpszWC, -1, *lppszAnsi, cch, NULL, NULL)) { DebugTrace( TEXT("ScWcToAnsi(), Conversion from Wide char to multibyte failed\n") ); sc = MAPI_E_CALL_FAILED; goto ret; }
ret:
DebugTraceSc( ScWCToAnsi, sc ); return sc; }
/*
- - LPCSTR ConvertWtoA(LPWSTR lpszW); * * LocalAllocs a ANSI version of an LPWSTR * * Caller is responsible for freeing */ LPSTR ConvertWtoA(LPCWSTR lpszW) { int cch; LPSTR lpC = NULL;
if ( !lpszW) goto ret;
// cch = lstrlenW( lpszW ) + 1;
cch = WideCharToMultiByte( CP_ACP, 0, lpszW, -1, NULL, 0, NULL, NULL ); cch = cch + 1;
if(lpC = LocalAlloc(LMEM_ZEROINIT, cch)) { WideCharToMultiByte( CP_ACP, 0, lpszW, -1, lpC, cch, NULL, NULL ); } ret: return lpC; }
//----------------------------------------------------------------------------
// Synopsis: SCODE ScAnsiToWC()
//
// Description:
// Converts an ANSI string to a Wide Character string with the
// passed in MAPI More allocator.
// If lpMapiAllocMore and lpBase are NULL and *lppszWC is not NULL
// then we assume *lppszWC is a pre allocated buffer
// Parameters:
// Returns:
// Effects:
// Notes:
// Revision:
//----------------------------------------------------------------------------
SCODE ScAnsiToWCMore( LPALLOCATEMORE lpMapiAllocMore, LPVOID lpBase, LPSTR lpszAnsi, LPWSTR * lppszWC ) { SCODE sc = S_OK; INT cch; ULONG ulSize;
if ( !lpszAnsi ) { if(lpMapiAllocMore && lpBase) *lppszWC = NULL; goto ret; }
cch = lstrlenA( lpszAnsi ) + 1; ulSize = cch * sizeof( WCHAR );
if(lpMapiAllocMore && lpBase) { sc = lpMapiAllocMore( ulSize, lpBase, lppszWC ); if ( FAILED( sc ) ) { DebugTrace( TEXT("ScAnsiToWC() OOM\n") ); goto ret; } }
if ( !MultiByteToWideChar( GetACP(), 0, lpszAnsi, -1, *lppszWC, cch ) ) { DebugTrace( TEXT("ScAnsiToWC(), Conversion from Wide char to multibyte failed\n") ); sc = MAPI_E_CALL_FAILED; goto ret; }
ret:
DebugTraceSc( ScAnsiToWC, sc ); return sc; } /*
- - LPCSTR ConvertWtoA(LPWSTR lpszW); * * LocalAllocs a ANSI version of an LPWSTR * * Caller is responsible for freeing */ LPWSTR ConvertAtoW(LPCSTR lpszA) { int cch; LPWSTR lpW = NULL; ULONG ulSize;
if ( !lpszA) goto ret;
cch = (lstrlenA( lpszA ) + 1); ulSize = cch*sizeof(WCHAR);
if(lpW = LocalAlloc(LMEM_ZEROINIT, ulSize)) { MultiByteToWideChar( GetACP(), 0, lpszA, -1, lpW, cch ); } ret: return lpW; }
/*
- - ScConvertAPropsToW - * Takes in an SPropValue array and goes in and adds W versions of all strings * to replace the A versions * It's assumed that all the MAPIAllocations will take place off the root of the * SPropValue array * */ SCODE ScConvertAPropsToW(LPALLOCATEMORE lpMapiAllocMore, LPSPropValue lpPropValue, ULONG ulcProps, ULONG ulStart) { ULONG iProp = 0; SCODE sc = 0; LPWSTR lpszConvertedW = NULL;
// There are 2 types of props we want to convert
// PT_STRING8 and
// PT_MV_STRING8
for ( iProp = ulStart; iProp < ulcProps; iProp++ ) { // Convert ANSI strings to UNICODE if required
if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_STRING8 ) { //if ( !lpPropTagArray ||
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
{ sc = ScAnsiToWCMore( lpMapiAllocMore, lpPropValue, lpPropValue[iProp].Value.lpszA, (LPWSTR *)&lpszConvertedW ); if ( FAILED( sc ) ) goto error;
lpPropValue[iProp].Value.lpszW = (LPWSTR)lpszConvertedW; lpszConvertedW = NULL;
// Fix up PropTag
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag, PT_UNICODE ); } } else if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_MV_STRING8 ) { //if ( !lpPropTagArray ||
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
{ ULONG j = 0; ULONG ulCount = lpPropValue[iProp].Value.MVszA.cValues; LPWSTR * lppszW = NULL;
if(sc = lpMapiAllocMore(sizeof(LPWSTR)*ulCount,lpPropValue, (LPVOID *)&lppszW)) goto error;
for(j=0;j<ulCount;j++) { sc = ScAnsiToWCMore(lpMapiAllocMore, lpPropValue, lpPropValue[iProp].Value.MVszA.lppszA[j], (LPWSTR *)&lpszConvertedW ); if ( FAILED( sc ) ) goto error; lppszW[j] = (LPWSTR)lpszConvertedW; lpszConvertedW = NULL;
// Fix up PropTag
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag, PT_MV_UNICODE ); } lpPropValue[iProp].Value.MVszW.lppszW = lppszW; } } }
error:
return ResultFromScode(sc); }
/*
- - ScConvertWPropsToA - * Takes in an SPropValue array and goes in and adds A versions of all strings * to replace the W versions * It's assumed that all the MAPIAllocations will take place off the root of the * SPropValue array * */ SCODE ScConvertWPropsToA(LPALLOCATEMORE lpMapiAllocMore, LPSPropValue lpPropValue, ULONG ulcProps, ULONG ulStart) { ULONG iProp = 0; SCODE sc = 0; LPSTR lpszConvertedA = NULL;
// There are 2 types of props we want to convert
// PT_STRING8 and
// PT_MV_STRING8
for ( iProp = ulStart; iProp < ulcProps; iProp++ ) { // Convert ANSI strings to UNICODE if required
if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_UNICODE ) { //if ( !lpPropTagArray ||
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
{ sc = ScWCToAnsiMore(lpMapiAllocMore, lpPropValue, lpPropValue[iProp].Value.lpszW, (LPSTR *)&lpszConvertedA ); if ( FAILED( sc ) ) goto error;
lpPropValue[iProp].Value.lpszA = (LPSTR)lpszConvertedA; lpszConvertedA = NULL;
// Fix up PropTag
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag, PT_STRING8 ); } } else if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_MV_UNICODE ) { //if ( !lpPropTagArray ||
// (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
{ ULONG j = 0; ULONG ulCount = lpPropValue[iProp].Value.MVszW.cValues; LPSTR * lppszA = NULL;
if(sc = lpMapiAllocMore(sizeof(LPSTR)*ulCount,lpPropValue, (LPVOID *)&lppszA)) goto error;
for(j=0;j<ulCount;j++) { sc = ScWCToAnsiMore(lpMapiAllocMore, lpPropValue, lpPropValue[iProp].Value.MVszW.lppszW[j], (LPSTR *)&lpszConvertedA ); if ( FAILED( sc ) ) goto error; lppszA[j] = (LPSTR)lpszConvertedA; lpszConvertedA = NULL;
// Fix up PropTag
lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag, PT_MV_STRING8 ); } lpPropValue[iProp].Value.MVszA.lppszA = lppszA; } } }
error:
return ResultFromScode(sc); }
|