OOTID.C
/*********************************************************************** 
 * 
 *  OOTID.C 
 * 
 *  Sample Address Book OneOff Template ID object 
 *  This file contains the code for implementing the Sample AB 
 *  template ID for it's one-off. 
 * 
 *  The template ID for the Sample Address Book one-offs has only one 
 *  purpose.  When the SaveChanges() method gets called it recalculates 
 *  PR_EMAIL_ADDRESS_A and PR_SEARCH_KEY from data that was changed by the 
 *  user.  See how this interacts with the one-off user object implemented 
 *  in OOUSER.C. 
 * 
 *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved. 
 * 
 ***********************************************************************/ 
 
#include "abp.h" 
 
/* 
 *  Declaration of IMailUser object implementation 
 */ 
#undef  INTERFACE 
#define INTERFACE   struct _OOTID 
 
#undef  MAPIMETHOD_ 
#define MAPIMETHOD_(type, method)   MAPIMETHOD_DECLARE(type, method, OOTID_) 
        MAPI_IUNKNOWN_METHODS(IMPL) 
        MAPI_IMAPIPROP_METHODS(IMPL) 
#undef  MAPIMETHOD_ 
#define MAPIMETHOD_(type, method)   MAPIMETHOD_TYPEDEF(type, method, OOTID_) 
        MAPI_IUNKNOWN_METHODS(IMPL) 
        MAPI_IMAPIPROP_METHODS(IMPL) 
#undef  MAPIMETHOD_ 
#define MAPIMETHOD_(type, method)   STDMETHOD_(type, method) 
 
 
DECLARE_MAPI_INTERFACE(OOTID_) 
{ 
    MAPI_IUNKNOWN_METHODS(IMPL) 
    MAPI_IMAPIPROP_METHODS(IMPL) 
}; 
 
 
/* 
 *  The structure behind the 'this' pointer 
 */ 
typedef struct _OOTID { 
 
    const OOTID_Vtbl * lpVtbl; 
 
    SAB_Wrapped; 
     
} OOTID, *LPOOTID; 
 
/* 
 *  OOTID vtbl is filled in here. 
 */ 
 
static const OOTID_Vtbl vtblOOTID = 
{ 
    (OOTID_QueryInterface_METHOD *)     ABU_QueryInterface, 
    (OOTID_AddRef_METHOD *)             WRAP_AddRef, 
    (OOTID_Release_METHOD *)            WRAP_Release, 
    (OOTID_GetLastError_METHOD *)       WRAP_GetLastError, 
    OOTID_SaveChanges, 
    (OOTID_GetProps_METHOD *)           WRAP_GetProps, 
    (OOTID_GetPropList_METHOD *)        WRAP_GetPropList, 
    (OOTID_OpenProperty_METHOD *)       WRAP_OpenProperty, 
    (OOTID_SetProps_METHOD *)           WRAP_SetProps, 
    (OOTID_DeleteProps_METHOD *)        WRAP_DeleteProps, 
    (OOTID_CopyTo_METHOD *)             WRAP_CopyTo, 
    (OOTID_CopyProps_METHOD *)          WRAP_CopyProps, 
    (OOTID_GetNamesFromIDs_METHOD *)    WRAP_GetNamesFromIDs, 
    (OOTID_GetIDsFromNames_METHOD *)    WRAP_GetIDsFromNames, 
}; 
 
/************************************************************************* 
 * 
 -  NewOOTID 
 - 
 *  Creates the OOTID object associated with a mail user. 
 * 
 * 
 */ 
 
enum { 
    isptOOTIDFillPR_ADDRTYPE_A = 0, 
    isptOOTIDFillPR_TEMPLATEID, 
    isptOOTIDFillPR_DISPLAY_TYPE, 
    cmaxOOTIDFill 
}; 
 
HRESULT 
HrNewOOTID( LPMAPIPROP *        lppMAPIPropNew, 
            ULONG               cbTemplateId, 
            LPENTRYID           lpTemplateId, 
            ULONG               ulTemplateFlags, 
            LPMAPIPROP          lpPropData, 
            LPABLOGON           lpABPLogon, 
            LPCIID              lpInterface, 
            HINSTANCE           hLibrary, 
            LPALLOCATEBUFFER    lpAllocBuff, 
            LPALLOCATEMORE      lpAllocMore, 
            LPFREEBUFFER        lpFreeBuff, 
            LPMALLOC            lpMalloc ) 
{ 
    LPOOTID lpOOTID = NULL; 
    SCODE sc; 
    HRESULT hResult = hrSuccess; 
 
    /* 
     *  Allocate space for the OOTID structure 
     */ 
    sc = lpAllocBuff( sizeof(OOTID), (LPVOID *) &lpOOTID ); 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto err; 
    } 
 
    /* 
     *  Initialize the OOTID structure 
     */ 
 
    lpOOTID->lpVtbl = &vtblOOTID; 
    lpOOTID->lcInit = 1; 
    lpOOTID->hResult = hrSuccess; 
    lpOOTID->idsLastError = 0; 
    lpOOTID->hLibrary = hLibrary; 
    lpOOTID->lpAllocBuff = lpAllocBuff; 
    lpOOTID->lpAllocMore = lpAllocMore; 
    lpOOTID->lpFreeBuff = lpFreeBuff; 
    lpOOTID->lpMalloc = lpMalloc; 
    lpOOTID->lpABLogon = lpABPLogon; 
    lpOOTID->lpPropData = lpPropData; 
 
    /* 
     *  Fill in the wrapped object if we're asked to. 
     */ 
    if (ulTemplateFlags & FILL_ENTRY) 
    { 
        SPropValue spv[cmaxOOTIDFill]; 
 
        spv[isptOOTIDFillPR_ADDRTYPE_A].ulPropTag = PR_ADDRTYPE_A; 
        spv[isptOOTIDFillPR_ADDRTYPE_A].Value.lpszA = lpszEMT; 
 
        spv[isptOOTIDFillPR_TEMPLATEID].ulPropTag = PR_TEMPLATEID; 
        spv[isptOOTIDFillPR_TEMPLATEID].Value.bin.lpb = (LPBYTE) lpTemplateId; 
        spv[isptOOTIDFillPR_TEMPLATEID].Value.bin.cb = cbTemplateId; 
 
        spv[isptOOTIDFillPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE; 
        spv[isptOOTIDFillPR_DISPLAY_TYPE].Value.l = DT_MAILUSER; 
 
        hResult = lpPropData->lpVtbl->SetProps( 
            lpPropData, 
            cmaxOOTIDFill, 
            spv, 
            NULL); 
         
        if (HR_FAILED(hResult)) 
        { 
            goto err; 
        } 
 
    } 
 
    /* 
     *  AddRef lpPropData so we can use it after we return 
     */ 
 
    (void)lpPropData->lpVtbl->AddRef(lpPropData); 
 
    InitializeCriticalSection(&lpOOTID->cs); 
     
    /*  We must AddRef the lpABPLogon object since we will be using it 
     */ 
    lpABPLogon->lpVtbl->AddRef(lpABPLogon); 
 
    *lppMAPIPropNew = (LPVOID) lpOOTID; 
 
out: 
 
    DebugTraceResult(HrNewOOTID, hResult); 
    return hResult; 
 
err: 
 
    lpFreeBuff(lpOOTID); 
    goto out; 
 
} 
 
 
/* 
 *  These properties are used and set by the one off dialog, and are 
 *  combined to make up a valid email address. 
 */ 
 
enum { 
    isptcontpropPR_SERVER_NAME = 0, 
    isptcontpropPR_SHARE_NAME, 
    isptcontpropPR_PATH_NAME, 
    cmaxcontprop 
};       
 
static const SizedSPropTagArray(cmaxcontprop, pta) = 
{ 
    cmaxcontprop, 
    { 
        PR_SERVER_NAME, 
        PR_SHARE_NAME, 
        PR_PATH_NAME, 
    } 
}; 
 
/* 
 *  These properties are computed by this function and saved back into the underlying 
 *  property storage. 
 */ 
enum { 
    isptcomppropsPR_EMAIL_ADDRESS_A = 0, 
    isptcomppropsPR_SEARCH_KEY, 
    cmaxcompprops 
}; 
 
 
/* 
 -  OOTID_SaveChanges 
 - 
 *  All this method does is build the PR_EMAIL_ADDRESS_A and PR_SEARCH_KEY from PR_SERVER_NAME, 
 *  PR_SHARE_NAME, and PR_PATH_NAME. 
 */ 
 
STDMETHODIMP 
OOTID_SaveChanges(LPOOTID lpOOTID, ULONG ulFlags) 
{ 
    HRESULT hResult; 
    /* 
     *  szEMA can be of the format: 
     * 
     *      \\SERVER_NAME\SHARE_NAME[\PATH]'\0' 
     */ 
    CHAR szEMA[ MAX_SERVER_NAME + 2 + MAX_SHARE_NAME + 1 + MAX_PATH + 2 ]; 
    LPSPropValue lpspv = NULL; 
    SPropValue rgspv[cmaxcompprops]; 
    ULONG ulcValues; 
    ULONG cbT = 0; 
    LPBYTE lpbT = NULL; 
    SCODE sc; 
 
    /* 
     *  Check to see if it is big enough to be my object 
     */ 
    if (IsBadReadPtr(lpOOTID, sizeof(OOTID))) 
    { 
        /* 
         *  Not big enough 
         */ 
        return MakeResult(E_INVALIDARG); 
    } 
 
    /* 
     *  Check to see that it's OOTIDs vtbl 
     */ 
    if (lpOOTID->lpVtbl != &vtblOOTID) 
    { 
        /* 
         *  vtbl not ours 
         */ 
        return MakeResult(E_INVALIDARG); 
    } 
 
 
    /* 
     *  Get the properties that make up the email address from the 
     *  mapiprop object 
     */ 
    hResult = lpOOTID->lpPropData->lpVtbl->GetProps( 
        lpOOTID->lpPropData, 
        (LPSPropTagArray) &pta, 
        0,      /* ansi */ 
        &ulcValues, 
        &lpspv); 
 
    if (HR_FAILED(hResult)) 
    { 
        goto out; 
    } 
 
    /* 
     *  Must have at least PR_SERVER_NAME and PR_SHARE_NAME to make a valid 
     *  email address 
     */ 
    if (lpspv[isptcontpropPR_SERVER_NAME].ulPropTag != PR_SERVER_NAME 
        || lpspv[isptcontpropPR_SHARE_NAME].ulPropTag != PR_SHARE_NAME) 
    { 
        /* 
         *  Without at least these two properties I cannot recalculate 
         *  anything.  So, just exit cleanly without changing anything. 
         */ 
        hResult = hrSuccess; /* to mask any warnings from above */ 
        goto out; 
    } 
 
    /* create the email address */ 
    wsprintfA(szEMA, "\\\\%s\\%s", 
        lpspv[isptcontpropPR_SERVER_NAME].Value.lpszA, lpspv[isptcontpropPR_SHARE_NAME].Value.lpszA); 
 
    /*  Did we also get a path??  If so append it on */ 
    if (lpspv[isptcontpropPR_PATH_NAME].ulPropTag == PR_PATH_NAME) 
    { 
        /*  But only if there's a value that make sense */ 
        if (*lpspv[isptcontpropPR_PATH_NAME].Value.lpszA)   /* i.e. !'\0' */ 
            wsprintfA(szEMA, "%s\\%s", szEMA, lpspv[isptcontpropPR_PATH_NAME].Value.lpszA); 
    } 
 
    /* initialize the email address prop value */ 
    rgspv[isptcomppropsPR_EMAIL_ADDRESS_A].ulPropTag = PR_EMAIL_ADDRESS_A; 
    rgspv[isptcomppropsPR_EMAIL_ADDRESS_A].Value.lpszA = szEMA; 
 
    /* 
     *  Generate the PR_SEARCH_KEY 
     */ 
    /*  Search keys for mailable recipients that have email addresses are 
     *  defined as "EmailType':'EmailAddress\0".  We do the +2 for the ':' and 
     *  '\0'. 
     */ 
    cbT = lstrlenA(szEMA) + lstrlenA(lpszEMT) + 2; 
 
    sc = lpOOTID->lpAllocBuff( cbT, (LPVOID *) &lpbT ); 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto out; 
    } 
    lstrcpyA((LPSTR) lpbT, lpszEMT); 
    lstrcatA((LPSTR) lpbT, ":"); 
    lstrcatA((LPSTR) lpbT, szEMA); 
    CharUpperBuffA((LPSTR) lpbT, (UINT) cbT); 
 
    rgspv[isptcomppropsPR_SEARCH_KEY].ulPropTag = PR_SEARCH_KEY; 
    rgspv[isptcomppropsPR_SEARCH_KEY].Value.bin.cb = cbT; 
    rgspv[isptcomppropsPR_SEARCH_KEY].Value.bin.lpb = lpbT; 
 
     
    /* 
     *  set the email address and search key properties 
     */ 
    hResult = lpOOTID->lpPropData->lpVtbl->SetProps( 
        lpOOTID->lpPropData, 
        cmaxcompprops, 
        rgspv, 
        NULL); 
 
    lpOOTID->lpFreeBuff(lpbT); 
 
    if (HR_FAILED(hResult)) 
    { 
        goto out; 
    } 
 
out: 
    // 
    //  If I'm leaving this routine and everything up to this point has been successful, 
    //  then pass on the SaveChanges to the underlying property storage. 
    // 
    if (!HR_FAILED(hResult)) 
    { 
        hResult = lpOOTID->lpPropData->lpVtbl->SaveChanges( 
            lpOOTID->lpPropData, 
            ulFlags); 
    } 
 
    /* free the buffer */ 
    lpOOTID->lpFreeBuff(lpspv); 
 
    DebugTraceResult(OOTID_SaveChanges, hResult); 
    return hResult; 
}