ITRACE.C
// --itrace.c------------------------------------------------------------------- 
//  
//  Module containing MAPI utility functions for message traces. 
//  
// Copyright (C) Microsoft Corp. 1986-1996.  All Rights Reserved. 
// ----------------------------------------------------------------------------- 
 
#include "edk.h" 
 
#include "itrace.chk" 
 
//$--HrTraceGetEntryListSize-------------------------------------------------- 
//  Get the size of the hop trace information in bytes. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceGetEntryListSize(      // RETURNS: return code 
    IN LPTRACEINFO lpTraceInfo,         // Pointer to hop trace address variable 
    OUT ULONG      *lpcbTraceInfo)      // Count of bytes in hop trace list 
{ 
    HRESULT hr         = NOERROR; 
    LPBYTE  lpbFirst   = NULL; 
    LPBYTE  lpbLast    = NULL; 
    ULONG   cBytes     = 0; 
    ULONG   cbExpected = 0; 
    ULONG   cEntries   = 0; 
 
    DEBUGPUBLIC("HrTraceGetEntryListSize()"); 
 
    hr = CHK_HrTraceGetEntryListSize( 
        lpTraceInfo, 
        lpcbTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    *lpcbTraceInfo = 0; 
 
    lpbFirst = (LPBYTE)lpTraceInfo; 
 
    cEntries = lpTraceInfo->cEntries; 
 
    lpbLast  = (LPBYTE)&(lpTraceInfo->rgtraceentry[cEntries]) - 1; 
 
    cBytes = ((lpbFirst <= lpbLast) ? (lpbLast-lpbFirst) : (lpbFirst-lpbLast)); 
 
    cBytes++; 
 
    cbExpected = CbTRACEINFO(lpTraceInfo); 
 
    if(cBytes != cbExpected) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    *lpcbTraceInfo = cBytes; 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrTraceGetEntryList----------------------------------------------------- 
//  Get the hop trace information for a given message. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceGetEntryList(         // RETURNS: return code 
    IN LPMESSAGE   lpMessage,           // Pointer to message. 
    OUT LPTRACEINFO *lppTraceInfo)      // Pointer to hop trace address variable 
{ 
    HRESULT hr         = NOERROR; 
    ULONG   cBytes     = 0; 
    ULONG   cbExpected = 0; 
 
    DEBUGPUBLIC("HrTraceGetEntryList()"); 
 
    hr = CHK_HrTraceGetEntryList( 
        lpMessage, 
        lppTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    *lppTraceInfo = NULL; 
 
    hr = HrMAPIGetPropBinary( 
        (LPMAPIPROP)lpMessage, 
        PR_TRACE_INFO, 
        &cBytes, 
        (LPVOID *)lppTraceInfo); 
 
    if(FAILED(hr)) 
    { 
        goto cleanup; 
    } 
 
    ASSERTERROR((*lppTraceInfo)->cEntries != 0, "ZERO cEntries variable"); 
 
    cbExpected = CbTRACEINFO((*lppTraceInfo)); 
 
    if(cBytes != cbExpected) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrTraceSetEntryList----------------------------------------------------- 
//  Set the hop trace information for a given message. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceSetEntryList(         // RETURNS: return code 
    IN LPMESSAGE   lpMessage,           // Pointer to message. 
    IN LPTRACEINFO lpTraceInfo)         // Pointer to hop trace address variable 
{ 
    HRESULT hr         = NOERROR; 
    ULONG   cBytes     = 0; 
    ULONG   cbExpected = 0; 
 
    DEBUGPUBLIC("HrTraceSetEntryList()"); 
 
    hr = CHK_HrTraceSetEntryList( 
        lpMessage, 
        lpTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    hr = HrTraceGetEntryListSize(lpTraceInfo, &cBytes); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    cbExpected = CbTRACEINFO(lpTraceInfo); 
 
    if(cBytes != cbExpected) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    hr = HrMAPISetPropBinary( 
        (LPMAPIPROP)lpMessage, 
        PR_TRACE_INFO, 
        cBytes, 
        (LPVOID *)lpTraceInfo); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrTraceCopyEntry-------------------------------------------------------- 
//  Copy trace entry information to a trace entry structure. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceCopyEntry(            // RETURNS: return code 
    IN LONG     lAction,                // The routing action the tracing site 
                                        // took. 
    IN FILETIME ftArrivalTime,          // The time at which the communique 
                                        // entered the tracing site. 
    IN FILETIME ftDeferredTime,         // The time are which the tracing site 
                                        // released the message. 
    IN LPSTR    lpszADMDName,           // ADMD Name 
    IN LPSTR    lpszCountryName,        // Country Name 
    IN LPSTR    lpszPRMDId,             // PRMD Identifier 
    IN LPSTR    lpszAttADMDName,        // Attempted ADMD Name 
    IN LPSTR    lpszAttCountryName,     // Attempted Country Name 
    IN LPSTR    lpszAttPRMDId,          // Attempted PRMD Identifier 
    OUT LPTRACEENTRY lpTraceEntry)      // Pointer to trace entry address 
                                        // variable. 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPRIVATE("HrTraceCopyEntry()"); 
 
    hr = CHK_HrTraceCopyEntry( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lpTraceEntry); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    lpTraceEntry->lAction = lAction; 
 
    lpTraceEntry->ftArrivalTime = ftArrivalTime; 
 
    lpTraceEntry->ftDeferredTime = ftDeferredTime; 
 
    if((lpszADMDName != NULL) && (strlen(lpszADMDName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchADMDName, lpszADMDName, MAX_ADMD_NAME_SIZ); 
        lpTraceEntry->rgchADMDName[MAX_ADMD_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszCountryName != NULL) && (strlen(lpszCountryName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchCountryName, lpszCountryName, MAX_COUNTRY_NAME_SIZ); 
        lpTraceEntry->rgchCountryName[MAX_COUNTRY_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszPRMDId != NULL) && (strlen(lpszPRMDId) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchPRMDId, lpszPRMDId, MAX_PRMD_NAME_SIZ); 
        lpTraceEntry->rgchPRMDId[MAX_PRMD_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszAttADMDName != NULL) && (strlen(lpszAttADMDName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttADMDName, lpszAttADMDName, MAX_ADMD_NAME_SIZ); 
        lpTraceEntry->rgchAttADMDName[MAX_ADMD_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszAttCountryName != NULL) && (strlen(lpszAttCountryName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttCountryName, lpszAttCountryName, MAX_COUNTRY_NAME_SIZ); 
        lpTraceEntry->rgchAttCountryName[MAX_COUNTRY_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszAttPRMDId != NULL) && (strlen(lpszAttPRMDId) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttPRMDId, lpszAttPRMDId, MAX_PRMD_NAME_SIZ); 
        lpTraceEntry->rgchAttPRMDId[MAX_PRMD_NAME_SIZ] = '\0'; 
    } 
 
    RETURN(hr); 
} 
 
//$--HrTraceCreateEntryList-------------------------------------------------- 
//  Create a hop trace information list. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceCreateEntryList(      // RETURNS: return code 
    IN LONG     lAction,                // The routing action the tracing site 
                                        // took. 
    IN FILETIME ftArrivalTime,          // The time at which the communique 
                                        // entered the tracing site. 
    IN FILETIME ftDeferredTime,         // The time are which the tracing site 
                                        // released the message. 
    IN LPSTR    lpszADMDName,           // ADMD Name 
    IN LPSTR    lpszCountryName,        // Country Name 
    IN LPSTR    lpszPRMDId,             // PRMD Identifier 
    IN LPSTR    lpszAttADMDName,        // Attempted ADMD Name 
    IN LPSTR    lpszAttCountryName,     // Attempted Country Name 
    IN LPSTR    lpszAttPRMDId,          // Attempted PRMD Identifier 
    OUT LPTRACEINFO *lppTraceInfo)      // Pointer to hop trace address variable 
{ 
    HRESULT     hr          = NOERROR; 
    ULONG       cBytes      = 0; 
    LPTRACEINFO lpTraceInfo = NULL; 
    SCODE       sc          = 0; 
 
    DEBUGPUBLIC("HrTraceCreateEntryList()"); 
 
    hr = CHK_HrTraceCreateEntryList( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lppTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    // Allocate a trace entry list 
 
    cBytes = CbNewTRACEINFO(1); 
 
    sc = MAPIAllocateBuffer(cBytes, (void **)lppTraceInfo); 
 
    if(FAILED(sc))                            
    {                                                    
        hr = HR_LOG(E_OUTOFMEMORY);                                  
        goto cleanup;                                 
    }                                                    
 
    // Initialize trace entry list 
    ZeroMemory(*lppTraceInfo, cBytes); 
 
    lpTraceInfo = *lppTraceInfo; 
 
    lpTraceInfo->cEntries = 1; 
 
    hr = HrTraceCopyEntry( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        &(lpTraceInfo->rgtraceentry[0])); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrTraceAppendEntryList-------------------------------------------------- 
//  Append to an existing hop trace information list. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceAppendEntryList(      // RETURNS: return code 
    IN LONG     lAction,                // The routing action the tracing site 
                                        // took. 
    IN FILETIME ftArrivalTime,          // The time at which the communique 
                                        // entered the tracing site. 
    IN FILETIME ftDeferredTime,         // The time are which the tracing site 
                                        // released the message. 
    IN LPSTR    lpszADMDName,           // ADMD Name 
    IN LPSTR    lpszCountryName,        // Country Name 
    IN LPSTR    lpszPRMDId,             // PRMD Identifier 
    IN LPSTR    lpszAttADMDName,        // Attempted ADMD Name 
    IN LPSTR    lpszAttCountryName,     // Attempted Country Name 
    IN LPSTR    lpszAttPRMDId,          // Attempted PRMD Identifier 
    IN OUT LPTRACEINFO *lppTraceInfo)   // Pointer to hop trace address variable 
{ 
    HRESULT      hr             = NOERROR; 
    ULONG        i              = 0; 
    ULONG        cBytes         = 0; 
    ULONG        cEntries       = 0; 
    LPTRACEINFO  lpTraceInfo    = NULL; 
    LPTRACEENTRY lpTraceEntry   = NULL; 
    LPTRACEINFO  lpNewTraceInfo = NULL; 
    SCODE        sc             = 0; 
 
    DEBUGPUBLIC("HrTraceAppendEntryList()"); 
 
    hr = CHK_HrTraceAppendEntryList( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lppTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    // Allocate a trace entry list 
 
    lpTraceInfo = *lppTraceInfo; 
 
    cEntries = lpTraceInfo->cEntries + 1; 
 
    cBytes = CbNewTRACEINFO(cEntries); 
 
    sc = MAPIAllocateBuffer(cBytes, (void **)&lpNewTraceInfo); 
 
    if(FAILED(sc))                            
    {                                                    
        hr = HR_LOG(E_OUTOFMEMORY);                                  
        goto cleanup;                                 
    }                                                    
 
    // Initialize trace entry list 
    ZeroMemory(lpNewTraceInfo, cBytes); 
 
    lpNewTraceInfo->cEntries = cEntries; 
 
    cEntries--; 
 
    for(i = 0; i < cEntries; i++) 
    { 
        lpTraceEntry = &(lpTraceInfo->rgtraceentry[i]); 
 
        hr = HrTraceCopyEntry( 
            lpTraceEntry->lAction, 
            lpTraceEntry->ftArrivalTime, 
            lpTraceEntry->ftDeferredTime, 
            lpTraceEntry->rgchADMDName, 
            lpTraceEntry->rgchCountryName, 
            lpTraceEntry->rgchPRMDId, 
            lpTraceEntry->rgchAttADMDName, 
            lpTraceEntry->rgchAttCountryName, 
            lpTraceEntry->rgchAttPRMDId, 
            &(lpNewTraceInfo->rgtraceentry[i])); 
 
        if(FAILED(hr)) 
        { 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
    } 
 
    hr = HrTraceCopyEntry( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        &(lpNewTraceInfo->rgtraceentry[cEntries])); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    MAPIFREEBUFFER(lpTraceInfo); 
 
    *lppTraceInfo = lpNewTraceInfo; 
 
cleanup: 
 
    if(FAILED(hr)) 
    { 
        MAPIFREEBUFFER(lpNewTraceInfo); 
    } 
 
    RETURN(hr); 
} 
 
//$--HrTraceGotoEntry-------------------------------------------------------- 
//  Goto the specified TRACEENTRY in a TRACEINFO 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceGotoEntry(            // RETURNS: return code 
    IN LPTRACEINFO lpTraceInfo,         // pointer to TRACEINFO 
    IN ULONG ulIndex,                   // index of TRACEENTRY in TRACEINFO 
    OUT LPTRACEENTRY *lppTraceEntry)    // pointer to TRACEENTRY 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrTraceGotoEntry()"); 
 
    hr = CHK_HrTraceGotoEntry( 
        lpTraceInfo, 
        ulIndex, 
        lppTraceEntry); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    *lppTraceEntry = NULL; 
 
    if(ulIndex < lpTraceInfo->cEntries) 
    { 
        *lppTraceEntry = &(lpTraceInfo->rgtraceentry[ulIndex]); 
    } 
    else 
    { 
        hr = HR_LOG(EDK_E_NOT_FOUND); 
    } 
 
    RETURN(hr); 
} 
 
//$--HrTraceGotoFirstEntry--------------------------------------------------- 
//  Goto the first TRACEENTRY in a TRACEINFO 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceGotoFirstEntry(       // RETURNS: return code 
    IN LPTRACEINFO lpTraceInfo,         // pointer to TRACEINFO 
    OUT ULONG *lpulIndex,               // index of TRACEENTRY in TRACEINFO 
    OUT LPTRACEENTRY *lppTraceEntry)    // pointer to TRACEENTRY 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrTraceGotoFirstEntry()"); 
 
    hr = CHK_HrTraceGotoFirstEntry( 
        lpTraceInfo, 
        lpulIndex, 
        lppTraceEntry); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    *lpulIndex = 0; 
 
    hr = HrTraceGotoEntry( 
        lpTraceInfo, 
        0, 
        lppTraceEntry); 
 
    RETURN(hr); 
} 
 
//$--HrTraceGotoNextEntry---------------------------------------------------- 
//  Goto the next TRACEENTRY in a TRACEINFO 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceGotoNextEntry(        // RETURNS: return code 
    IN LPTRACEINFO lpTraceInfo,         // pointer to TRACEINFO 
    IN OUT ULONG *lpulIndex,            // index of TRACEENTRY in TRACEINFO 
    OUT LPTRACEENTRY *lppTraceEntry)    // pointer to TRACEENTRY 
{ 
    HRESULT hr      = NOERROR; 
    ULONG   ulIndex = 0; 
 
    DEBUGPUBLIC("HrTraceGotoNextEntry()"); 
 
    hr = CHK_HrTraceGotoNextEntry( 
        lpTraceInfo, 
        lpulIndex, 
        lppTraceEntry); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    ulIndex = *lpulIndex; 
 
    ulIndex++; 
 
    *lpulIndex = ulIndex; 
 
    hr = HrTraceGotoEntry( 
        lpTraceInfo, 
        ulIndex, 
        lppTraceEntry); 
 
    RETURN(hr); 
} 
 
//$--HrTraceOpenEntry-------------------------------------------------------- 
//  Open a TRACEENTRY. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceOpenEntry(            // RETURNS: return code 
    IN LPTRACEENTRY lpTraceEntry,       // pointer to TRACEENTRY 
    OUT LONG     *plAction,             // The routing action the tracing site 
                                        // took. 
    OUT FILETIME *pftArrivalTime,       // The time at which the communique 
                                        // entered the tracing site. 
    OUT FILETIME *pftDeferredTime,      // The time are which the tracing site 
                                        // released the message. 
    OUT LPSTR    *lppszADMDName,        // ADMD Name 
    OUT LPSTR    *lppszCountryName,     // Country Name 
    OUT LPSTR    *lppszPRMDId,          // PRMD Identifier 
    OUT LPSTR    *lppszAttADMDName,     // Attempted ADMD Name 
    OUT LPSTR    *lppszAttCountryName,  // Attempted Country Name 
    OUT LPSTR    *lppszAttPRMDId)       // Attempted PRMD Identifier 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPUBLIC("HrTraceOpenEntry()"); 
 
    hr = CHK_HrTraceOpenEntry( 
        lpTraceEntry, 
        plAction, 
        pftArrivalTime, 
        pftDeferredTime, 
        lppszADMDName, 
        lppszCountryName, 
        lppszPRMDId, 
        lppszAttADMDName, 
        lppszAttCountryName, 
        lppszAttPRMDId); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    *plAction               = lpTraceEntry->lAction; 
    *pftArrivalTime         = lpTraceEntry->ftArrivalTime; 
    *pftDeferredTime        = lpTraceEntry->ftDeferredTime; 
    *lppszADMDName          = lpTraceEntry->rgchADMDName; 
    *lppszCountryName       = lpTraceEntry->rgchCountryName; 
    *lppszPRMDId            = lpTraceEntry->rgchPRMDId; 
    *lppszAttADMDName       = lpTraceEntry->rgchAttADMDName; 
    *lppszAttCountryName    = lpTraceEntry->rgchAttCountryName; 
    *lppszAttPRMDId         = lpTraceEntry->rgchAttPRMDId; 
 
    RETURN(hr); 
} 
 
//$--HrTraceSetInfo---------------------------------------------------------- 
//  Set the trace-info on a message. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceSetInfo(              // RETURNS: return code 
    IN LONG lAction,                    // pointer to action 
    IN FILETIME *lpftArrivalTime,       // pointer to arrival time 
    IN FILETIME *lpftDeferredTime,      // pointer to deferred time 
    IN LPSTR lpszCountry,               // pointer to country 
    IN LPSTR lpszADMD,                  // pointer to ADMD 
    IN LPSTR lpszPRMD,                  // pointer to PRMD 
    IN OUT LPMESSAGE lpMessage)         // pointer to message 
{ 
    HRESULT     hr          = NOERROR; 
    LPTRACEINFO lpTraceInfo = NULL; 
 
    DEBUGPUBLIC("HrTraceSetInfo()"); 
 
    hr = CHK_HrTraceSetInfo( 
        lAction, 
        lpftArrivalTime, 
        lpftDeferredTime, 
        lpszCountry, 
        lpszADMD, 
        lpszPRMD, 
        lpMessage); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    hr = HrTraceCreateEntryList( 
        lAction, 
        *lpftArrivalTime, 
        *lpftDeferredTime, 
        lpszADMD, 
        lpszCountry, 
        lpszPRMD, 
        NULL, 
        NULL, 
        NULL, 
        &lpTraceInfo); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    hr = HrTraceSetEntryList( 
        lpMessage, 
        lpTraceInfo); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
cleanup: 
 
    MAPIFREEBUFFER(lpTraceInfo); 
 
    RETURN(hr); 
} 
 
//$--HrTraceUpdateInfo------------------------------------------------------- 
//  Update the trace-info on a message. 
// ----------------------------------------------------------------------------- 
HRESULT HrTraceUpdateInfo(           // RETURNS: return code 
    IN LONG lAction,                    // pointer to action 
    IN FILETIME *lpftArrivalTime,       // pointer to arrival time 
    IN FILETIME *lpftDeferredTime,      // pointer to deferred time 
    IN LPSTR lpszCountry,               // pointer to country 
    IN LPSTR lpszADMD,                  // pointer to ADMD 
    IN LPSTR lpszPRMD,                  // pointer to PRMD 
    IN OUT LPMESSAGE lpMessage)         // pointer to message 
{ 
    HRESULT      hr                 = NOERROR; 
    LPTRACEINFO  lpTraceInfo        = NULL; 
    LPTRACEENTRY lpTraceEntry       = NULL; 
    ULONG        index              = 0; 
    LONG         lCurrAction        = 0; 
    FILETIME     ftCurrArrivalTime  = {0}; 
    FILETIME     ftCurrDeferredTime = {0}; 
    LPSTR       lpszCurrCountry    = NULL; 
    LPSTR       lpszCurrADMD       = NULL; 
    LPSTR       lpszCurrPRMD       = NULL; 
    LPSTR       lpszCurrAttCountry = NULL; 
    LPSTR       lpszCurrAttADMD    = NULL; 
    LPSTR       lpszCurrAttPRMD    = NULL; 
 
    DEBUGPUBLIC("HrTraceUpdateInfo()"); 
 
    hr = CHK_HrTraceUpdateInfo( 
        lAction, 
        lpftArrivalTime, 
        lpftDeferredTime, 
        lpszCountry, 
        lpszADMD, 
        lpszPRMD, 
        lpMessage); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    hr = HrTraceGetEntryList( 
        lpMessage, 
        &lpTraceInfo); 
 
    if(FAILED(hr)) 
    { 
        if(hr != EDK_E_NOT_FOUND) 
        { 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
    } 
 
    if(hr == EDK_E_NOT_FOUND) 
    { 
        hr = HrTraceCreateEntryList( 
            lAction, 
            *lpftArrivalTime, 
            *lpftDeferredTime, 
            lpszADMD, 
            lpszCountry, 
            lpszPRMD, 
            NULL, 
            NULL, 
            NULL, 
            &lpTraceInfo); 
 
        if(FAILED(hr)) 
        { 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
    } 
    else 
    { 
        hr = HrTraceGotoFirstEntry(lpTraceInfo, &index, &lpTraceEntry); 
 
        while(SUCCEEDED(hr)) 
        { 
 
            hr = HrTraceOpenEntry( 
                lpTraceEntry, 
                &lCurrAction, 
                &ftCurrArrivalTime, 
                &ftCurrDeferredTime, 
                &lpszCurrADMD, 
                &lpszCurrCountry, 
                &lpszCurrPRMD, 
                &lpszCurrAttADMD, 
                &lpszCurrAttCountry, 
                &lpszCurrAttPRMD); 
 
            if(FAILED(hr)) 
            { 
                hr = HR_LOG(E_FAIL); 
                goto cleanup; 
            } 
 
            if( (lstrcmpi(lpszADMD, lpszCurrADMD) == 0) && 
                (lstrcmpi(lpszPRMD, lpszCurrPRMD) == 0) && 
                (lstrcmpi(lpszCountry, lpszCurrCountry) == 0)) 
            { 
                hr = HR_LOG(EDK_E_ALREADY_EXISTS); 
                goto cleanup; 
 
            } 
 
            hr = HrTraceGotoNextEntry( 
                lpTraceInfo, 
                &index, 
                &lpTraceEntry); 
 
            if((FAILED(hr)) && (hr != EDK_E_NOT_FOUND)) 
            { 
                hr = HR_LOG(E_FAIL); 
                goto cleanup; 
            } 
        } 
 
        hr = HrTraceAppendEntryList( 
            lAction, 
            *lpftArrivalTime, 
            *lpftDeferredTime, 
            lpszADMD, 
            lpszCountry, 
            lpszPRMD, 
            NULL, 
            NULL, 
            NULL, 
            &lpTraceInfo); 
 
        if(FAILED(hr)) 
        { 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
    } 
 
    hr = HrTraceSetEntryList( 
        lpMessage, 
        lpTraceInfo); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
cleanup: 
 
    MAPIFREEBUFFER(lpTraceInfo); 
 
    RETURN(hr); 
} 
 
 
//------------------------------------------------------------------------------ 
// 
// INTERNAL TRACE INFORMATION FUNCTIONS 
// 
//------------------------------------------------------------------------------ 
 
//$--HrInternalTraceCopyEntry--------------------------------------------------- 
//  Copy internal trace entry information to an internal trace entry structure. 
// ----------------------------------------------------------------------------- 
HRESULT HrInternalTraceCopyEntry(       // RETURNS: return code 
    IN LONG     lAction,                // The routing action the tracing site 
                                        // took. 
    IN FILETIME ftArrivalTime,          // The time at which the communique 
                                        // entered the tracing site. 
    IN FILETIME ftDeferredTime,         // The time are which the tracing site 
                                        // released the message. 
    IN LPSTR    lpszADMDName,           // ADMD Name 
    IN LPSTR    lpszCountryName,        // Country Name 
    IN LPSTR    lpszPRMDId,             // PRMD Identifier 
    IN LPSTR    lpszMTAName,            // MTA Name 
    IN LPSTR    lpszAttADMDName,        // Attempted ADMD Name 
    IN LPSTR    lpszAttCountryName,     // Attempted Country Name 
    IN LPSTR    lpszAttPRMDId,          // Attempted PRMD Identifier 
    IN LPSTR    lpszAttMTAName,         // Attempted MTA Name 
    OUT PINTTRACEENTRY lpTraceEntry)    // Pointer to trace entry address 
                                        // variable. 
{ 
    HRESULT hr = NOERROR; 
 
    DEBUGPRIVATE("HrInternalTraceCopyEntry()"); 
 
    hr = CHK_HrInternalTraceCopyEntry( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszMTAName, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lpszAttMTAName, 
        lpTraceEntry); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    lpTraceEntry->lAction = lAction; 
 
    lpTraceEntry->ftArrivalTime = ftArrivalTime; 
 
    lpTraceEntry->ftDeferredTime = ftDeferredTime; 
 
    if((lpszADMDName != NULL) && (strlen(lpszADMDName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchADMDName, lpszADMDName, MAX_ADMD_NAME_SIZ); 
        lpTraceEntry->rgchADMDName[MAX_ADMD_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszCountryName != NULL) && (strlen(lpszCountryName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchCountryName, lpszCountryName, MAX_COUNTRY_NAME_SIZ); 
        lpTraceEntry->rgchCountryName[MAX_COUNTRY_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszPRMDId != NULL) && (strlen(lpszPRMDId) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchPRMDId, lpszPRMDId, MAX_PRMD_NAME_SIZ); 
        lpTraceEntry->rgchPRMDId[MAX_PRMD_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszMTAName != NULL) && (strlen(lpszMTAName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchMTAName, lpszMTAName, MAX_MTA_NAME_SIZ); 
        lpTraceEntry->rgchMTAName[MAX_MTA_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszAttADMDName != NULL) && (strlen(lpszAttADMDName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttADMDName, lpszAttADMDName, MAX_ADMD_NAME_SIZ); 
        lpTraceEntry->rgchAttADMDName[MAX_ADMD_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszAttCountryName != NULL) && (strlen(lpszAttCountryName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttCountryName, lpszAttCountryName, MAX_COUNTRY_NAME_SIZ); 
        lpTraceEntry->rgchAttCountryName[MAX_COUNTRY_NAME_SIZ-1] = '\0'; 
    } 
 
    if((lpszAttPRMDId != NULL) && (strlen(lpszAttPRMDId) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttPRMDId, lpszAttPRMDId, MAX_PRMD_NAME_SIZ); 
        lpTraceEntry->rgchAttPRMDId[MAX_PRMD_NAME_SIZ] = '\0'; 
    } 
 
    if((lpszAttMTAName != NULL) && (strlen(lpszAttMTAName) > 0)) 
    { 
        strncpy(lpTraceEntry->rgchAttMTAName, lpszAttMTAName, MAX_MTA_NAME_SIZ); 
        lpTraceEntry->rgchAttMTAName[MAX_MTA_NAME_SIZ-1] = '\0'; 
    } 
 
    RETURN(hr); 
} 
 
//$--HrInternalTraceCreateEntryList--------------------------------------------- 
//  Create a internal hop trace information list. 
// ----------------------------------------------------------------------------- 
HRESULT HrInternalTraceCreateEntryList( // RETURNS: return code 
    IN LONG     lAction,                // The routing action the tracing site 
                                        // took. 
    IN FILETIME ftArrivalTime,          // The time at which the communique 
                                        // entered the tracing site. 
    IN FILETIME ftDeferredTime,         // The time are which the tracing site 
                                        // released the message. 
    IN LPSTR    lpszADMDName,           // ADMD Name 
    IN LPSTR    lpszCountryName,        // Country Name 
    IN LPSTR    lpszPRMDId,             // PRMD Identifier 
    IN LPSTR    lpszMTAName,            // MTA Name 
IN LPSTR    lpszAttADMDName,        // Attempted ADMD Name 
    IN LPSTR    lpszAttCountryName,     // Attempted Country Name 
    IN LPSTR    lpszAttPRMDId,          // Attempted PRMD Identifier 
    IN LPSTR    lpszAttMTAName,         // Attempted MTA Name 
    OUT PINTTRACEINFO *lppTraceInfo)    // Pointer to hop trace address variable 
{ 
    HRESULT       hr          = NOERROR; 
    ULONG         cBytes      = 0; 
    PINTTRACEINFO lpTraceInfo = NULL; 
    SCODE         sc          = 0; 
 
    DEBUGPUBLIC("HrInternalTraceCreateEntryList()"); 
 
    hr = CHK_HrInternalTraceCreateEntryList( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszMTAName, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lpszAttMTAName, 
        lppTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    // Allocate a trace entry list 
 
    cBytes = CbNewINTTRACEINFO(1); 
 
    sc = MAPIAllocateBuffer(cBytes, (void **)lppTraceInfo); 
 
    if(FAILED(sc))                            
    {                                                    
        hr = HR_LOG(E_OUTOFMEMORY);                                  
        goto cleanup;                                 
    }                                                    
 
    // Initialize trace entry list 
    ZeroMemory(*lppTraceInfo, cBytes); 
 
    lpTraceInfo = *lppTraceInfo; 
 
    lpTraceInfo->cEntries = 1; 
 
    hr = HrInternalTraceCopyEntry( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszMTAName, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lpszAttMTAName, 
        &(lpTraceInfo->rgIntTraceEntry[0])); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
cleanup: 
 
    RETURN(hr); 
} 
 
//$--HrInternalTraceAppendEntryList--------------------------------------------- 
//  Append to an existing internal hop trace information list. 
// ----------------------------------------------------------------------------- 
HRESULT HrInternalTraceAppendEntryList( // RETURNS: return code 
    IN LONG     lAction,                // The routing action the tracing site 
                                        // took. 
    IN FILETIME ftArrivalTime,          // The time at which the communique 
                                        // entered the tracing site. 
    IN FILETIME ftDeferredTime,         // The time are which the tracing site 
                                        // released the message. 
    IN LPSTR    lpszADMDName,           // ADMD Name 
    IN LPSTR    lpszCountryName,        // Country Name 
    IN LPSTR    lpszPRMDId,             // PRMD Identifier 
    IN LPSTR    lpszMTAName,            // MTA Name 
    IN LPSTR    lpszAttADMDName,        // Attempted ADMD Name 
    IN LPSTR    lpszAttCountryName,     // Attempted Country Name 
    IN LPSTR    lpszAttPRMDId,          // Attempted PRMD Identifier 
    IN LPSTR    lpszAttMTAName,         // Attempted MTA Name 
    IN OUT PINTTRACEINFO *lppTraceInfo) // Pointer to hop trace address variable 
{ 
    HRESULT        hr             = NOERROR; 
    ULONG          i              = 0; 
    ULONG          cBytes         = 0; 
    ULONG          cEntries       = 0; 
    PINTTRACEINFO  lpTraceInfo    = NULL; 
    PINTTRACEENTRY lpTraceEntry   = NULL; 
    PINTTRACEINFO  lpNewTraceInfo = NULL; 
    SCODE          sc             = 0; 
 
    DEBUGPUBLIC("HrInternalTraceAppendEntryList()"); 
 
    hr = CHK_HrInternalTraceAppendEntryList( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszMTAName, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lpszAttMTAName, 
        lppTraceInfo); 
 
    if(FAILED(hr)) 
        RETURN(hr); 
 
    // Allocate a trace entry list 
 
    lpTraceInfo = *lppTraceInfo; 
 
    cEntries = lpTraceInfo->cEntries + 1; 
 
    cBytes = CbNewINTTRACEINFO(cEntries); 
 
    sc = MAPIAllocateBuffer(cBytes, (void **)&lpNewTraceInfo); 
 
    if(FAILED(sc))                            
    {                                                    
        hr = HR_LOG(E_OUTOFMEMORY);                                  
        goto cleanup;                                 
    }                                                    
 
    // Initialize trace entry list 
    ZeroMemory(lpNewTraceInfo, cBytes); 
 
    lpNewTraceInfo->cEntries = cEntries; 
 
    cEntries--; 
 
    for(i = 0; i < cEntries; i++) 
    { 
        lpTraceEntry = &(lpTraceInfo->rgIntTraceEntry[i]); 
 
        hr = HrInternalTraceCopyEntry( 
            lpTraceEntry->lAction, 
            lpTraceEntry->ftArrivalTime, 
            lpTraceEntry->ftDeferredTime, 
            lpTraceEntry->rgchADMDName, 
            lpTraceEntry->rgchCountryName, 
            lpTraceEntry->rgchPRMDId, 
            lpTraceEntry->rgchMTAName, 
            lpTraceEntry->rgchAttADMDName, 
            lpTraceEntry->rgchAttCountryName, 
            lpTraceEntry->rgchAttPRMDId, 
            lpTraceEntry->rgchAttMTAName, 
            &(lpNewTraceInfo->rgIntTraceEntry[i])); 
 
        if(FAILED(hr)) 
        { 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
    } 
 
    hr = HrInternalTraceCopyEntry( 
        lAction, 
        ftArrivalTime, 
        ftDeferredTime, 
        lpszADMDName, 
        lpszCountryName, 
        lpszPRMDId, 
        lpszMTAName, 
        lpszAttADMDName, 
        lpszAttCountryName, 
        lpszAttPRMDId, 
        lpszAttMTAName, 
        &(lpNewTraceInfo->rgIntTraceEntry[cEntries])); 
 
    if(FAILED(hr)) 
    { 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    MAPIFREEBUFFER(lpTraceInfo); 
 
    *lppTraceInfo = lpNewTraceInfo; 
 
cleanup: 
 
    if(FAILED(hr)) 
    { 
        MAPIFREEBUFFER(lpNewTraceInfo); 
    } 
 
    RETURN(hr); 
}