GWREPORT.C
// --gwreport.c----------------------------------------------------------------- 
//  
//  Gateway report functions. 
//  
// Copyright (C) Microsoft Corp. 1986-1996.  All Rights Reserved. 
// ----------------------------------------------------------------------------- 
 
#include "edk.h" 
#include "gwreport.h" 
 
#define SZ_MTS_ID               "/c=XX/a=X/p=X/l=X" 
 
#define CENTRIES_FIRST  4 
#define CENTRIES_NEXT   32 
 
//$--HrCreateEmptyRecipList----------------------------------------------------- 
// 
//  Create an empty list of recipients. 
// 
// ----------------------------------------------------------------------------- 
static HRESULT HrCreateEmptyRecipList(      // RETURNS: return code 
    OUT    LPADRLIST*    lppAdrList)        // address list 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPRIVATE("HrCreateEmptyRecipList()\n"); 
 
    hr = HrMAPICreateSizedAddressList( 
        CENTRIES_FIRST, 
        lppAdrList); 
 
    if(FAILED(hr)) 
    { 
        goto cleanup; 
    } 
    else 
    { 
        (*lppAdrList)->cEntries = 0; 
    } 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrNDRCreateFailedRecipList------------------------------------------------- 
// 
//  Create an empty list of failed recipients. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrNDRCreateFailedRecipList(         // RETURNS: return code 
    OUT    LPADRLIST*    lppAdrList)        // address list 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrNDRCreateFailedRecipList()\n"); 
 
    hr = HrCreateEmptyRecipList(lppAdrList); 
 
    RETURN(hr); 
} 
 
//$--HrNDRGetFailedRecipList---------------------------------------------------- 
// 
//  Create a failed recipient entry. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrNDRGetFailedRecipList(            // RETURNS: return code 
    IN     LPADRENTRY    lpAdrEntry,        // address entry 
    IN     ULONG         cExtraProps,       // count of extra properties 
    IN     LPSPropValue  lpExtraProps,      // extra properties 
    OUT    ULONG*        lpcFailedProps,    // count of failed properties 
    OUT    LPSPropValue* lppFailedProps)    // failed properties 
{ 
    HRESULT      hr           = NOERROR; 
    FILETIME     ftReportTime = {0}; 
    ULONG        i            = 0; 
    SPropValue   rgProps[9]   = {0}; 
    ULONG        cValues      = 0; 
    LPSPropValue lpProps      = NULL; 
    ULONG        cNewValues   = 0; 
    LPSPropValue lpNewProps   = NULL; 
    LPSPropValue lpPropT      = NULL; 
 
    DEBUGPUBLIC("HrNDRGetFailedRecipList()\n"); 
 
    // 
    // Get the current time 
    // 
 
    if((cExtraProps > 0) && (lpExtraProps != NULL)) 
    { 
        hr = HrMAPIAppendSPropValues( 
            lpAdrEntry->cValues, 
            lpAdrEntry->rgPropVals, 
            cExtraProps, 
            lpExtraProps, 
            &cValues, 
            &lpProps); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
    else 
    { 
        cValues = lpAdrEntry->cValues; 
 
        hr = ScDupPropset( 
            lpAdrEntry->cValues, 
            lpAdrEntry->rgPropVals, 
    MAPIAllocateBuffer, 
            &lpProps); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
 
    // 
    // Default any missing properties. 
    // 
 
    lpPropT = LpValFindProp(PR_NDR_REASON_CODE, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_NDR_REASON_CODE)) 
    { 
        rgProps[i  ].ulPropTag = PR_NDR_REASON_CODE; 
        rgProps[i++].Value.l   = 0; 
    } 
 
    lpPropT = LpValFindProp(PR_NDR_DIAG_CODE, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_NDR_DIAG_CODE)) 
    { 
        rgProps[i  ].ulPropTag = PR_NDR_DIAG_CODE; 
        rgProps[i++].Value.l   = -1; 
    } 
 
    lpPropT = LpValFindProp(PR_REPORT_TIME, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_REPORT_TIME)) 
    { 
        GetSystemTimeAsFileTime( &ftReportTime); 
 
        rgProps[i  ].ulPropTag = PR_REPORT_TIME; 
        rgProps[i++].Value.ft  = ftReportTime; 
    } 
 
    lpPropT = LpValFindProp(PR_REPORT_TEXT, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_REPORT_TEXT)) 
    { 
        rgProps[i  ].ulPropTag  = PR_REPORT_TEXT; 
        rgProps[i++].Value.LPSZ = TEXT(" "); 
    } 
 
    lpPropT = LpValFindProp(PR_RECIPIENT_NUMBER, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_RECIPIENT_NUMBER)) 
    { 
        rgProps[i  ].ulPropTag = PR_RECIPIENT_NUMBER; 
        rgProps[i++].Value.l   = 1; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED; 
        rgProps[i++].Value.b   = TRUE; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED; 
        rgProps[i++].Value.b   = FALSE; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_READ_RECEIPT_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_READ_RECEIPT_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_READ_RECEIPT_REQUESTED; 
        rgProps[i++].Value.b   = FALSE; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_NON_RECEIPT_NOTIFICATION_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_NON_RECEIPT_NOTIFICATION_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_NON_RECEIPT_NOTIFICATION_REQUESTED; 
        rgProps[i++].Value.b   = FALSE; 
    } 
 
    if(i > 0) 
    { 
        hr = HrMAPIAppendSPropValues( 
            cValues, 
            lpProps, 
            i, 
            rgProps, 
            &cNewValues, 
            &lpNewProps); 
 
        MAPIFREEBUFFER(lpProps); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
 
        *lpcFailedProps = cNewValues; 
        *lppFailedProps = lpNewProps; 
    } 
    else 
    { 
        *lpcFailedProps = cValues; 
        *lppFailedProps = lpProps; 
    } 
 
cleanup: 
 
    if(FAILED(hr)) 
    { 
        MAPIFREEBUFFER(lpProps); 
        MAPIFREEBUFFER(lpNewProps); 
 
        *lpcFailedProps = 0; 
        *lppFailedProps = NULL; 
    } 
 
    RETURN(hr); 
} 
 
//$--HrAddToRecipList----------------------------------------------------------- 
// 
//  Add a recipient entry to the list of recipients. 
// 
// ----------------------------------------------------------------------------- 
static HRESULT HrAddToRecipList(            // RETURNS: return code 
    IN     ULONG         cProps,            // count of properties 
    IN     LPSPropValue  lpProps,           // properties 
    IN OUT LPADRLIST*    lppAdrList)        // address list 
{ 
    HRESULT    hr          = NOERROR; 
    SCODE      sc          = 0; 
    ULONG      cOldEntries = 0; 
    ULONG      cEntries    = 0; 
    ULONG      cBytes      = 0; 
    ULONG      i           = 0; 
    LPADRENTRY lpAdrEntry  = NULL; 
    LPADRLIST  lpAdrList   = NULL; 
 
    DEBUGPRIVATE("HrAddToRecipList()\n"); 
 
    cEntries = (*lppAdrList)->cEntries; 
 
    cOldEntries = cEntries; 
 
    // 
    // Grow the address list if necessary. 
    // 
 
    if((cEntries == CENTRIES_FIRST) || 
       ((cEntries > CENTRIES_FIRST) && 
       (((cEntries - CENTRIES_FIRST) % CENTRIES_NEXT) == 0))) 
    { 
        cEntries += CENTRIES_NEXT; 
 
        cBytes = CbNewADRLIST(cEntries); 
 
        sc = MAPIAllocateBuffer(cBytes, (void **)&lpAdrList); 
 
        if(FAILED(sc))                            
        {                                                    
            hr = HR_LOG(E_OUTOFMEMORY);                                  
            goto cleanup; 
        }                                                    
 
        ZeroMemory(lpAdrList, cBytes); 
 
        lpAdrEntry = lpAdrList->aEntries; 
 
        // 
        // Copy existing address entries to the new address list. 
        // 
 
        for(i = 0; i < (*lppAdrList)->cEntries; i++) 
        { 
            lpAdrEntry[i].cValues = 
                (*lppAdrList)->aEntries[i].cValues; 
            lpAdrEntry[i].rgPropVals = 
                (*lppAdrList)->aEntries[i].rgPropVals; 
        } 
 
        MAPIFREEBUFFER(*lppAdrList); 
 
        *lppAdrList = lpAdrList; 
    } 
 
    // 
    // Add an address entry to the address list. 
    // 
 
    i = cOldEntries; 
 
    (*lppAdrList)->cEntries = ++i; 
 
    i--; 
 
    hr = HrMAPISetAddressList( 
        i, 
        cProps, 
        lpProps, 
        *lppAdrList); 
 
    if(FAILED(hr)) 
    { 
        goto cleanup; 
    } 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrNDRAddToFailedRecipList-------------------------------------------------- 
// 
//  Add a recipient entry to the list of failed recipients. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrNDRAddToFailedRecipList(          // RETURNS: return code 
    IN     ULONG         cFailedProps,      // count of failed properties 
    IN     LPSPropValue  lpFailedProps,     // failed properties 
    IN OUT LPADRLIST*    lppAdrList)        // address list 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrNDRAddToFailedRecipList()\n"); 
 
    hr = HrAddToRecipList(cFailedProps, lpFailedProps, lppAdrList); 
 
    RETURN(hr); 
} 
 
//$--HrExtractProps------------------------------------------------------------- 
// 
//  Get NDR/DR properties from the original message. 
// 
// ----------------------------------------------------------------------------- 
static HRESULT HrExtractProps(              // RETURNS: return code 
    IN     BOOL          IsNdr,             // report is an NDR, otherwise a DR 
    IN     LPMESSAGE     lpMessage,         // message 
    OUT    ULONG*        lpcProps,          // count of properties 
    OUT    LPSPropValue* lppProps)          // properties 
{ 
    HRESULT      hr                     = NOERROR; 
    SCODE        sc                     = 0; 
    ULONG        cBytes                 = 0; 
FILETIME     ftSubmitTime           = {0}; 
    ULONG        i                      = 0; 
    ULONG        cValues                = 0; 
    LPSPropValue lpProps                = NULL; 
    LPSTR       lpszMessageClass       = NULL; 
    LPSTR       lpszReportMessageClass = NULL; 
    LPSTR       lpsz                   = NULL; 
    ULONG        cch                    = 0; 
 
SizedSPropTagArray(18, rgMessagePropTags) = 
{ 
18, 
{ 
PR_MESSAGE_CLASS, 
            PR_SUBJECT, 
            PR_NORMALIZED_SUBJECT, 
PR_SUBJECT_PREFIX, 
PR_CLIENT_SUBMIT_TIME, 
            PR_MTS_ID, 
            PR_SENDER_NAME, 
            PR_SENDER_ENTRYID, 
            PR_DELETE_AFTER_SUBMIT, 
            PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED, 
            PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED, 
            PR_READ_RECEIPT_REQUESTED, 
            PR_NON_RECEIPT_NOTIFICATION_REQUESTED, 
            PR_CONTENT_RETURN_REQUESTED, 
            PR_PRIORITY, 
            PR_IMPORTANCE, 
            PR_REPORT_NAME, 
            PR_REPORT_ENTRYID 
        } 
    }; 
 
    DEBUGPRIVATE("HrExtractProps()\n"); 
 
    // 
    // Get report properties from the message. 
    // 
 
hr = MAPICALL(lpMessage)->GetProps( 
    lpMessage, 
(LPSPropTagArray)&rgMessagePropTags, 
fMapiUnicode, 
&cValues, 
&lpProps); 
 
if(FAILED(hr)) 
{ 
        lpProps = NULL; 
 
goto cleanup; 
} 
 
    // 
    // Create report message class 
    // 
 
    if(lpProps[0].ulPropTag == PR_MESSAGE_CLASS) 
    { 
        lpszMessageClass = lpProps[0].Value.LPSZ; 
    } 
 
    if(lpszMessageClass == NULL) 
    { 
        cch = 0; 
    } 
    else 
    { 
        cch = lstrlen(lpszMessageClass); 
    } 
 
    if(cch == 0) 
    { 
        lpszMessageClass = TEXT("IPM.NOTE"); 
        cch = lstrlen(lpszMessageClass); 
    } 
 
    cch += lstrlen(TEXT("REPORT.")); 
 
    if(IsNdr == TRUE) 
    { 
        cch += lstrlen(TEXT(".NDR")); 
    } 
    else 
    { 
        cch += lstrlen(TEXT(".DR")); 
    } 
 
    cch++; // terminating NULL character 
 
    cBytes = cch * sizeof(CHAR); 
 
    sc = MAPIAllocateMore(cBytes, lpProps, &lpszReportMessageClass); 
 
    if(FAILED(sc))                            
    {                                                    
        hr = HR_LOG(E_OUTOFMEMORY);                                  
        goto cleanup; 
    }                                                    
 
    lstrcpy(lpszReportMessageClass, TEXT("REPORT.")); 
    lstrcat(lpszReportMessageClass, lpszMessageClass); 
    if(IsNdr == TRUE) 
    { 
        lstrcat(lpszReportMessageClass, TEXT(".NDR")); 
    } 
    else 
    { 
        lstrcat(lpszReportMessageClass, TEXT(".DR")); 
    } 
 
    // 
    // PR_MESSAGE_CLASS 
    // 
 
lpProps[0].ulPropTag  = PR_MESSAGE_CLASS; 
    lpProps[0].Value.LPSZ = lpszReportMessageClass; 
 
    // 
    // PR_SUBJECT 
    // 
 
if(lpProps[1].ulPropTag != PR_SUBJECT) 
    { 
        cBytes = cbStrLen(""); 
 
        sc = MAPIAllocateMore(cBytes, lpProps, &lpsz); 
 
        if(FAILED(sc))                            
        {                                                    
            hr = HR_LOG(E_OUTOFMEMORY);                                  
            goto cleanup; 
        }                                                    
 
        lstrcpy(lpsz, TEXT("")); 
 
    lpProps[1].ulPropTag  = PR_SUBJECT; 
    lpProps[1].Value.LPSZ = lpsz; 
    } 
 
    // 
    // PR_NORMALIZED_SUBJECT 
    // 
 
if(lpProps[2].ulPropTag != PR_NORMALIZED_SUBJECT) 
    { 
        cBytes = cbStrLen(""); 
 
        sc = MAPIAllocateMore(cBytes, lpProps, &lpsz); 
 
        if(FAILED(sc))                            
        {                                                    
            hr = HR_LOG(E_OUTOFMEMORY);                                  
            goto cleanup; 
        }                                                    
 
        lstrcpy(lpsz, TEXT("")); 
 
    lpProps[2].ulPropTag  = PR_NORMALIZED_SUBJECT; 
    lpProps[2].Value.LPSZ = lpsz; 
    } 
 
    // 
    // PR_SUBJECT_PREFIX 
    // 
 
if(lpProps[3].ulPropTag != PR_SUBJECT_PREFIX) 
    { 
        cBytes = cbStrLen(""); 
 
        sc = MAPIAllocateMore(cBytes, lpProps, &lpsz); 
 
        if(FAILED(sc))                            
        {                                                    
            hr = HR_LOG(E_OUTOFMEMORY);                                  
            goto cleanup; 
        }                                                    
 
        lstrcpy(lpsz, TEXT("")); 
 
    lpProps[3].ulPropTag  = PR_SUBJECT_PREFIX; 
    lpProps[3].Value.LPSZ = lpsz; 
    } 
 
    // 
    // PR_CLIENT_SUBMIT_TIME 
    // 
 
if(lpProps[4].ulPropTag != PR_CLIENT_SUBMIT_TIME) 
    { 
    GetSystemTimeAsFileTime( &ftSubmitTime); 
 
    lpProps[4].ulPropTag = PR_CLIENT_SUBMIT_TIME; 
    lpProps[4].Value.ft  = ftSubmitTime; 
    } 
 
    // 
    // PR_MTS_SUBJECT_ID 
    // 
 
if(lpProps[5].ulPropTag != PR_MTS_ID) 
    { 
        cBytes = cbStrLen(SZ_MTS_ID); 
 
        sc = MAPIAllocateMore(cBytes, lpProps, &lpsz); 
 
        if(FAILED(sc))                            
        {                                                    
            hr = HR_LOG(E_OUTOFMEMORY);                                  
            goto cleanup; 
        }                                                    
 
        lstrcpy(lpsz, TEXT(SZ_MTS_ID)); 
 
    lpProps[5].ulPropTag     = PR_MTS_ID; 
    lpProps[5].Value.bin.cb  = cBytes; 
    lpProps[5].Value.bin.lpb = (LPBYTE) lpsz;  
    } 
 
    lpProps[5].ulPropTag         = PR_MTS_SUBJECT_ID; 
 
    if((lpProps[16].ulPropTag == PR_REPORT_NAME) && 
       (lpProps[17].ulPropTag == PR_REPORT_ENTRYID)) 
    { 
        lpProps[6].ulPropTag     = PR_SENDER_NAME; 
        lpProps[6].Value.LPSZ    = lpProps[16].Value.LPSZ; 
 
        lpProps[7].ulPropTag     = PR_SENDER_ENTRYID; 
        lpProps[7].Value.bin.cb  = lpProps[17].Value.bin.cb; 
        lpProps[7].Value.bin.lpb = lpProps[17].Value.bin.lpb; 
    } 
 
    // 
    // PR_REPORT_DESTINATION_NAME 
    // 
 
if(lpProps[6].ulPropTag != PR_SENDER_NAME) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    lpProps[6].ulPropTag         = PR_REPORT_DESTINATION_NAME; 
 
    // 
    // PR_REPORT_DESTINATION_ENTRYID 
    // 
 
if(lpProps[7].ulPropTag != PR_SENDER_ENTRYID) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    lpProps[7].ulPropTag         = PR_REPORT_DESTINATION_ENTRYID; 
 
    // 
    // PR_DELETE_AFTER_SUBMIT 
    // 
 
    lpProps[8].ulPropTag         = PR_DELETE_AFTER_SUBMIT; 
    lpProps[8].Value.b           = TRUE; 
 
    // 
    // PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED 
    // 
 
if(lpProps[9].ulPropTag != PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED) 
    { 
        lpProps[9].ulPropTag = PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED; 
        lpProps[9].Value.b   = TRUE; 
    } 
 
    // 
    // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED 
    // 
 
if(lpProps[10].ulPropTag != PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED) 
    { 
        lpProps[10].ulPropTag = PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED; 
        lpProps[10].Value.b   = FALSE; 
    } 
 
    // 
    // PR_READ_RECEIPT_REQUESTED 
    // 
 
if(lpProps[11].ulPropTag != PR_READ_RECEIPT_REQUESTED) 
    { 
        lpProps[11].ulPropTag = PR_READ_RECEIPT_REQUESTED; 
        lpProps[11].Value.b   = FALSE; 
    } 
 
    // 
    // PR_NON_RECEIPT_NOTIFICATION_REQUESTED 
    // 
 
if(lpProps[12].ulPropTag != PR_NON_RECEIPT_NOTIFICATION_REQUESTED) 
    { 
        lpProps[12].ulPropTag = PR_NON_RECEIPT_NOTIFICATION_REQUESTED; 
        lpProps[12].Value.b   = FALSE; 
    } 
 
    // 
    // PR_CONTENT_RETURN_REQUESTED 
    // 
 
if(lpProps[13].ulPropTag != PR_CONTENT_RETURN_REQUESTED) 
    { 
        lpProps[13].ulPropTag = PR_CONTENT_RETURN_REQUESTED; 
        lpProps[13].Value.b   = TRUE; 
    } 
 
    // 
    // PR_PRIORITY 
    // 
 
if(lpProps[14].ulPropTag != PR_PRIORITY) 
    { 
        lpProps[14].ulPropTag = PR_PRIORITY; 
        lpProps[14].Value.l   = PRIO_NORMAL; 
    } 
 
    // 
    // PR_IMPORTANCE 
    // 
 
if(lpProps[15].ulPropTag != PR_IMPORTANCE) 
    { 
        lpProps[15].ulPropTag = PR_IMPORTANCE; 
        lpProps[15].Value.l   = IMPORTANCE_NORMAL; 
    } 
 
    *lpcProps = cValues - 2; 
    *lppProps = lpProps; 
 
cleanup: 
 
    if(FAILED(hr)) 
    { 
        MAPIFREEBUFFER(lpProps); 
 
        *lpcProps = 0; 
        *lppProps = NULL; 
    } 
 
    RETURN(hr); 
} 
 
//$--HrNDRGetFailedProps---------------------------------------------------------- 
// 
//  Get NDR properties from the original message. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrNDRGetFailedProps(                  // RETURNS: return code 
    IN     LPMESSAGE     lpMessage,         // message 
    OUT    ULONG*        lpcProps,          // count of properties 
    OUT    LPSPropValue* lppProps)          // properties 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrNDRGetFailedProps()\n"); 
 
    hr = HrExtractProps(TRUE, lpMessage, lpcProps, lppProps); 
 
    RETURN(hr); 
} 
 
//$--HrXDRCreate---------------------------------------------------------------- 
// 
//  Create a non-delivery or delivery report. 
// 
// ----------------------------------------------------------------------------- 
static HRESULT HrXDRCreate(                 // RETURNS: return code 
    IN     LPADRBOOK     lpAdrBook,         // address book 
    IN     LPMAPIFOLDER  lpFolder,          // folder 
    IN     LPMESSAGE     lpMessage,         // message 
    IN     LPADRLIST     lpAdrList,         // address list 
    IN     ULONG         cProps,            // count of properties 
    IN     LPSPropValue  lpProps,           // properties 
    OUT    LPMESSAGE*    lppReport)         // report 
{ 
    HRESULT      hr              = NOERROR; 
    LPMESSAGE    lpReport        = NULL; 
    ULONG        ulAttachmentNum = 0; 
    LPATTACH     lpAttach        = NULL; 
    LPMESSAGE    lpContent       = NULL; 
    BOOL         fReturnContent  = FALSE; 
    SPropValue   rgProps[1]      = {0}; 
    LPSPropValue lpPropT         = NULL; 
 
    DEBUGPRIVATE("HrXDRCreate()\n"); 
 
    *lppReport = NULL; 
 
    // 
    // Create a message 
    // 
 
    hr = MAPICALL(lpFolder)->CreateMessage( 
        lpFolder, 
        NULL, 
        MAPI_DEFERRED_ERRORS, 
        &lpReport); 
 
    if(FAILED(hr)) 
    { 
        goto cleanup; 
    } 
 
    // 
    // Return content if available and requested. 
    // 
 
    lpPropT = LpValFindProp( 
        PR_CONTENT_RETURN_REQUESTED, cProps, lpProps); 
 
    if(lpPropT == NULL) 
    { 
        fReturnContent = TRUE; 
    } 
    else if(lpPropT->ulPropTag != PR_CONTENT_RETURN_REQUESTED) 
    { 
        lpPropT->ulPropTag = PR_CONTENT_RETURN_REQUESTED; 
        lpPropT->Value.b   = TRUE; 
    } 
    else 
    { 
        fReturnContent = lpPropT->Value.b; 
    } 
 
    if((lpMessage != NULL) && (fReturnContent == TRUE)) 
    { 
        // 
        // Create an embedded message 
        // 
 
        hr = MAPICALL(lpReport)->CreateAttach( 
            lpReport, 
            NULL, 
            (ULONG)0, 
            &ulAttachmentNum, 
            &lpAttach); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
 
        rgProps[0].ulPropTag = PR_ATTACH_METHOD; 
        rgProps[0].Value.ul  = ATTACH_EMBEDDED_MSG; 
 
        hr = MAPICALL(lpAttach)->SetProps( 
            lpAttach, 
            1, 
            rgProps, 
            NULL); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
 
        hr = MAPICALL(lpAttach)->OpenProperty( 
            lpAttach, 
            PR_ATTACH_DATA_OBJ, 
            (LPIID)&IID_IMessage, 
            0, 
            MAPI_CREATE|MAPI_MODIFY|MAPI_DEFERRED_ERRORS, 
            (LPUNKNOWN *)&lpContent); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
 
    if(lpAdrList != NULL) 
    { 
        hr = MAPICALL(lpReport)->ModifyRecipients( 
            lpReport, 
            0, 
            lpAdrList); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
 
    // 
    // Set envelope properties 
    // 
 
    if((cProps > 0) && (lpProps != NULL)) 
    { 
        hr = MAPICALL(lpReport)->SetProps( 
            lpReport, 
            cProps, 
            lpProps, 
            NULL); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
 
    if((lpMessage != NULL) && (fReturnContent == TRUE)) 
    { 
        hr = MAPICALL(lpMessage)->CopyTo( 
            lpMessage, 
            0, 
            NULL, 
            NULL, 
            0, 
            NULL, 
            (LPIID)&IID_IMessage, 
            lpContent, 
            0, 
            NULL); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
 
        if(hr == MAPI_W_ERRORS_RETURNED) 
        { 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
 
        hr = MAPICALL(lpContent)->SaveChanges(lpContent, KEEP_OPEN_READWRITE); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
 
        hr = MAPICALL(lpAttach)->SaveChanges(lpAttach, KEEP_OPEN_READWRITE); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
 
    hr = MAPICALL(lpReport)->SaveChanges(lpReport, KEEP_OPEN_READWRITE); 
 
    if(FAILED(hr)) 
    { 
        goto cleanup; 
    } 
 
    *lppReport = lpReport; 
 
cleanup: 
 
    ULRELEASE(lpContent); 
 
    ULRELEASE(lpAttach); 
 
    if(FAILED(hr)) 
    { 
        ULRELEASE(lpReport); 
 
        *lppReport = NULL; 
    } 
 
    RETURN(hr); 
} 
 
//$--HrNDRCreate---------------------------------------------------------------- 
// 
//  Create a non-delivery report. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrNDRCreate(                        // RETURNS: return code 
    IN     LPADRBOOK     lpAdrBook,         // address book 
    IN     LPMAPIFOLDER  lpFolder,          // folder 
    IN     LPMESSAGE     lpMessage,         // message 
    IN     LPADRLIST     lpAdrList,         // address list 
    IN     ULONG         cProps,            // count of properties 
    IN     LPSPropValue  lpProps,           // properties 
    OUT    LPMESSAGE*    lppReport)         // report 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrNDRCreate()\n"); 
 
    hr = HrXDRCreate( 
        lpAdrBook, 
        lpFolder, 
        lpMessage, 
        lpAdrList, 
        cProps, 
        lpProps, 
        lppReport); 
 
    RETURN(hr); 
} 
 
//$--HrDRCreateDeliveredRecipList----------------------------------------------- 
// 
//  Create an empty list of delivered recipients. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrDRCreateDeliveredRecipList(       // RETURNS: return code 
    OUT    LPADRLIST*    lppAdrList)        // address list 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrDRCreateDeliveredRecipList()\n"); 
 
    hr = HrCreateEmptyRecipList(lppAdrList); 
 
    RETURN(hr); 
} 
 
//$--HrDRGetDeliveredRecip-------------------------------------------------- 
// 
//  Create a delivered recipient entry. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrDRGetDeliveredRecip(          // RETURNS: return code 
    IN     LPADRENTRY    lpAdrEntry,        // address entry 
    IN     ULONG         cExtraProps,       // count of extra properties 
    IN     LPSPropValue  lpExtraProps,      // extra properties 
    OUT    ULONG*        lpcDeliveredProps, // count of delivered properties 
    OUT    LPSPropValue* lppDeliveredProps) // delivered properties 
{ 
    HRESULT      hr            = NOERROR; 
    FILETIME     ftReportTime  = {0}; 
    FILETIME     ftDeliverTime = {0}; 
    ULONG        i             = 0; 
    SPropValue   rgProps[9]    = {0}; 
    ULONG        cValues       = 0; 
    LPSPropValue lpProps       = NULL; 
    ULONG        cNewValues    = 0; 
    LPSPropValue lpNewProps    = NULL; 
    LPSPropValue lpPropT       = NULL; 
 
    DEBUGPUBLIC("HrDRGetDeliveredRecip()\n"); 
 
    if((cExtraProps > 0) && (lpExtraProps != NULL)) 
    { 
        hr = HrMAPIAppendSPropValues( 
            lpAdrEntry->cValues, 
            lpAdrEntry->rgPropVals, 
            cExtraProps, 
            lpExtraProps, 
            &cValues, 
            &lpProps); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
    else 
    { 
        cValues = lpAdrEntry->cValues; 
 
        hr = ScDupPropset( 
            lpAdrEntry->cValues, 
            lpAdrEntry->rgPropVals, 
    MAPIAllocateBuffer, 
            &lpProps); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
    } 
 
    // 
    // Default any missing properties. 
    // 
 
    lpPropT = LpValFindProp(PR_REPORT_TIME, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_REPORT_TIME)) 
    { 
        GetSystemTimeAsFileTime( &ftReportTime); 
 
        rgProps[i  ].ulPropTag = PR_REPORT_TIME; 
        rgProps[i++].Value.ft  = ftReportTime; 
    } 
 
    lpPropT = LpValFindProp(PR_REPORT_TEXT, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_REPORT_TEXT)) 
    { 
        rgProps[i  ].ulPropTag  = PR_REPORT_TEXT; 
        rgProps[i++].Value.LPSZ = TEXT(" "); 
    } 
 
    lpPropT = LpValFindProp(PR_DELIVER_TIME, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_DELIVER_TIME)) 
    { 
        GetSystemTimeAsFileTime( &ftDeliverTime); 
 
        rgProps[i  ].ulPropTag = PR_DELIVER_TIME; 
        rgProps[i++].Value.ft  = ftDeliverTime; 
    } 
 
    lpPropT = LpValFindProp(PR_REPORT_TEXT, cValues, lpProps); 
 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_REPORT_TEXT)) 
    { 
        rgProps[i  ].ulPropTag  = PR_REPORT_TEXT; 
        rgProps[i++].Value.LPSZ = TEXT(" "); 
    } 
 
    lpPropT = LpValFindProp(PR_RECIPIENT_NUMBER, cValues, lpProps); 
    if((lpPropT == NULL) || (lpPropT->ulPropTag != PR_RECIPIENT_NUMBER)) 
    { 
        rgProps[i  ].ulPropTag = PR_RECIPIENT_NUMBER; 
        rgProps[i++].Value.l   = 1; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED; 
        rgProps[i++].Value.b   = TRUE; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED; 
        rgProps[i++].Value.b   = FALSE; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_READ_RECEIPT_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_READ_RECEIPT_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_READ_RECEIPT_REQUESTED; 
        rgProps[i++].Value.b   = FALSE; 
    } 
 
    lpPropT = LpValFindProp( 
        PR_NON_RECEIPT_NOTIFICATION_REQUESTED, cValues, lpProps); 
 
    if((lpPropT == NULL) || 
       (lpPropT->ulPropTag != PR_NON_RECEIPT_NOTIFICATION_REQUESTED)) 
    { 
        rgProps[i  ].ulPropTag = PR_NON_RECEIPT_NOTIFICATION_REQUESTED; 
        rgProps[i++].Value.b   = FALSE; 
    } 
 
    if(i > 0) 
    { 
        hr = HrMAPIAppendSPropValues( 
            cValues, 
            lpProps, 
            i, 
            rgProps, 
            &cNewValues, 
            &lpNewProps); 
 
        MAPIFREEBUFFER(lpProps); 
 
        if(FAILED(hr)) 
        { 
            goto cleanup; 
        } 
 
        *lpcDeliveredProps = cNewValues; 
        *lppDeliveredProps = lpNewProps; 
    } 
    else 
    { 
        *lpcDeliveredProps = cValues; 
        *lppDeliveredProps = lpProps; 
    } 
 
cleanup: 
 
    if(FAILED(hr)) 
    { 
        MAPIFREEBUFFER(lpProps); 
        MAPIFREEBUFFER(lpNewProps); 
 
        *lpcDeliveredProps = 0; 
        *lppDeliveredProps = NULL; 
    } 
 
    RETURN(hr); 
} 
 
//$--HrDRAddToDeliveredRecipList------------------------------------------------ 
// 
//  Add a recipient entry to the list of delivered recipients. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrDRAddToDeliveredRecipList(        // RETURNS: return code 
    IN     ULONG         cDeliveredProps,   // count of delivered properties 
    IN     LPSPropValue  lpDeliveredProps,  // delivered properties 
    IN OUT LPADRLIST*    lppAdrList)        // address list 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrDRAddToDeliveredRecipList()\n"); 
 
    hr = HrAddToRecipList(cDeliveredProps, lpDeliveredProps, lppAdrList); 
 
    RETURN(hr); 
} 
 
//$--HrDRGetProps----------------------------------------------------------- 
// 
//  Get DR properties from the original message. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrDRGetProps(                   // RETURNS: return code 
    IN     LPMESSAGE     lpMessage,         // message 
    OUT    ULONG*        lpcProps,          // count of properties 
    OUT    LPSPropValue* lppProps)          // properties 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrDRGetProps()\n"); 
 
    hr = HrExtractProps(FALSE, lpMessage, lpcProps, lppProps); 
 
    RETURN(hr); 
} 
 
//$--HrDRCreate----------------------------------------------------------------- 
// 
//  Create a delivery report. 
// 
// ----------------------------------------------------------------------------- 
HRESULT HrDRCreate(                         // RETURNS: return code 
    IN     LPADRBOOK     lpAdrBook,         // address book 
    IN     LPMAPIFOLDER  lpFolder,          // folder 
    IN     LPMESSAGE     lpMessage,         // message 
    IN     LPADRLIST     lpAdrList,         // address list 
    IN     ULONG         cProps,            // count of properties 
    IN     LPSPropValue  lpProps,           // properties 
    OUT    LPMESSAGE*    lppReport)         // report 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrDRCreate()\n"); 
 
    hr = HrXDRCreate( 
        lpAdrBook, 
        lpFolder, 
        lpMessage, 
        lpAdrList, 
        cProps, 
        lpProps, 
        lppReport); 
 
    RETURN(hr); 
}