/**************************************************************************
*** COPYRIGHT (c) 2002 by TransNexus, Inc.                              ***
***                                                                     ***
*** This software is property of TransNexus, Inc.                       ***
*** This software is freely available under license from TransNexus.    ***
*** The license terms and conditions for free use of this software by   ***
*** third parties are defined in the OSP Toolkit Software License       ***
*** Agreement (LICENSE.txt).  Any use of this software by third         ***
*** parties, which does not comply with the terms and conditions of the ***
*** OSP Toolkit Software License Agreement is prohibited without        ***
*** the prior, express, written consent of TransNexus, Inc.             ***
***                                                                     ***
*** Thank you for using the OSP ToolKit(TM).  Please report any bugs,   ***
*** suggestions or feedback to support@transnexus.com                   ***
***                                                                     ***
**************************************************************************/

/* osptrans.cpp - Global functions for transaction object. */

#include "osp/osp.h"
#include "osp/osptrans.h"
#include "osp/ospprovider.h"
#include "osp/ospsecurity.h"
#include "osp/ospmime.h"
#include "osp/osputils.h"
#include "osp/ospmsgque.h"
#include "osp/ospmsginfo.h"
#include "osp/ospxml.h"
#include "osp/ospmsg.h"
#include "osp/ospcomm.h"
#include "osp/ospauthreq.h"
#include "osp/ospreauthreq.h"
#include "osp/ospauthcnf.h"
#include "osp/ospusagecnf.h"
#include "osp/ospfail.h"
#include "osp/ospaltinfo.h"

/* Build a Reauthorization Request and put in transaction */
int OSPPTransactionBuildReauthRequest(
    OSPTTRANS *ospvTrans,
    unsigned ospvDuration)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    OSPT_TOKEN *token = OSPC_OSNULL, *token1 = OSPC_OSNULL;
    OSPT_ALTINFO *altinfo = OSPC_OSNULL, *altinfo2 = OSPC_OSNULL;
    OSPTTIME timestamp = 0;

    if (ospvTrans == OSPC_OSNULL) {
        errorcode = OSPC_ERR_TRAN_TRANSACTION_NOT_FOUND;
    }

    if (ospvTrans->ReauthReq == OSPC_OSNULL) {
        ospvTrans->ReauthReq = OSPPReauthReqNew();

        if (ospvTrans->ReauthReq == OSPC_OSNULL) {
            errorcode = OSPC_ERR_TRAN_MALLOC_FAILED;
        }
    }

    /* Set Role = OSPC_SOURCE */
    if (errorcode == OSPC_ERR_NO_ERROR) {
        /* Set Timestamp */
        timestamp = time(NULL);
        OSPPReauthReqSetTimestamp(ospvTrans->ReauthReq, timestamp);

        OSPPReauthReqSetRole(ospvTrans->ReauthReq, OSPC_ROLE_SOURCE);

        /* Get Callid from trans->currdest->callid */
        if (ospvTrans->CurrentDest != OSPC_OSNULL) {

            if (OSPPDestHasCallId(ospvTrans->CurrentDest)) {

                OSPPReauthReqSetCallId(ospvTrans->ReauthReq, OSPPDestGetCallId(ospvTrans->CurrentDest));
            } else {
                errorcode = OSPC_ERR_TRAN_CALLID_NOT_FOUND;
                OSPM_DBGERRORLOG(errorcode, "Callid not found");
            }

            if (errorcode == OSPC_ERR_NO_ERROR) {
                /* Get token from trans->currdest->token */
                if (OSPPDestHasToken(ospvTrans->CurrentDest)) {

                    /* add any tokens */
                    for (token = (OSPT_TOKEN *)OSPPDestFirstToken(ospvTrans->CurrentDest);
                         (token != OSPC_OSNULL); token = (OSPT_TOKEN *)OSPPDestNextToken(ospvTrans->CurrentDest, token)) {

                        token1 = OSPPTokenNew(token->Length, token->Value);
                        if (token1 != OSPC_OSNULL) {
                            OSPPReauthReqAddToken(ospvTrans->ReauthReq, token1);
                        }
                        token = OSPC_OSNULL;
                        token1 = OSPC_OSNULL;
                    }
                } else {
                    errorcode = OSPC_ERR_TRAN_TOKEN_NOT_FOUND;
                    OSPM_DBGERRORLOG(errorcode, "Token not found");
                }
            }

            if (errorcode == OSPC_ERR_NO_ERROR) {
                /* Get Duration for UsageDetail */
                if (OSPPDestHasLimit(ospvTrans->CurrentDest)) {

                    OSPPReauthReqSetDuration(ospvTrans->ReauthReq, ospvDuration);
                }
            }
        } else {
            errorcode = OSPC_ERR_TRAN_DEST_NOT_FOUND;
        }
    }

    /* Get Calling number from trans->AuthReq->SourceNumber */
    if (errorcode == OSPC_ERR_NO_ERROR) {

        if (ospvTrans->AuthReq != OSPC_OSNULL) {
            if (OSPPAuthReqHasSourceNumber(ospvTrans->AuthReq)) {
                OSPPReauthReqSetSourceNumber(ospvTrans->ReauthReq, OSPPAuthReqGetSourceNumber(ospvTrans->AuthReq));
            } else {
                errorcode = OSPC_ERR_TRAN_SOURCE_NUMBER_NOT_FOUND;
            }
        } else {
            errorcode = OSPC_ERR_TRAN_AUTH_REQ_NOT_FOUND;
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            /* Get Called number from trans->AuthReq->DestinationNumber */
            if (OSPPAuthReqHasDestNumber(ospvTrans->AuthReq)) {
                OSPPReauthReqSetDestNumber(ospvTrans->ReauthReq, OSPPAuthReqGetDestNumber(ospvTrans->AuthReq));
            } else {
                errorcode = OSPC_ERR_TRAN_DEST_NUMBER_NOT_FOUND;
            }
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            /* Get device info from trans->AuthReq->DeviceInfo */
            if (ospvTrans->AuthReq->DeviceInfo != NULL) {
                for (altinfo = (OSPT_ALTINFO *)OSPPListFirst(&(ospvTrans->AuthReq->DeviceInfo));
                    altinfo != OSPC_OSNULL; altinfo = (OSPT_ALTINFO *)OSPPListNext(&(ospvTrans->AuthReq->DeviceInfo), altinfo))
                {
                    altinfo2 = OSPPAltInfoNew(OSPPAltInfoGetSize(altinfo), OSPPAltInfoGetValue(altinfo), OSPPAltInfoGetPart(altinfo));
                    if (altinfo2 != OSPC_OSNULL) {
                        OSPPListAppend(&(ospvTrans->ReauthReq->DeviceInfo), altinfo2);
                    }
                    altinfo = OSPC_OSNULL;
                    altinfo2 = OSPC_OSNULL;
                }
            }
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            /* Get SourceAlternates from trans->AuthReq->SourceAlternates */
            if (OSPPAuthReqHasSourceAlt(ospvTrans->AuthReq)) {
                for (altinfo = (OSPT_ALTINFO *)OSPPAuthReqFirstSourceAlt(ospvTrans->AuthReq);
                     altinfo != OSPC_OSNULL; altinfo = (OSPT_ALTINFO *)OSPPAuthReqNextSourceAlt(ospvTrans->AuthReq, altinfo)) {

                    altinfo2 = OSPPAltInfoNew(OSPPAltInfoGetSize(altinfo), OSPPAltInfoGetValue(altinfo), OSPPAltInfoGetPart(altinfo));

                    if (altinfo2 != OSPC_OSNULL) {
                        OSPPReauthReqAddSourceAlt(ospvTrans->ReauthReq, altinfo2);
                    }
                    altinfo = OSPC_OSNULL;
                    altinfo2 = OSPC_OSNULL;
                }
            }
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            /* Get DestinationAlternates from trans->AuthReq->DestinationAlternates */
            if (OSPPAuthReqHasDestinationAlt(ospvTrans->AuthReq)) {
                for (altinfo = (OSPT_ALTINFO *)OSPPAuthReqFirstDestinationAlt(ospvTrans->AuthReq);
                    altinfo != OSPC_OSNULL; altinfo = (OSPT_ALTINFO *)OSPPAuthReqNextDestinationAlt(ospvTrans->AuthReq, altinfo))
                {
                    altinfo2 = OSPPAltInfoNew(OSPPAltInfoGetSize(altinfo), OSPPAltInfoGetValue(altinfo), OSPPAltInfoGetPart(altinfo));
                    if (altinfo2 != OSPC_OSNULL) {
                        OSPPReauthReqAddDestinationAlt(ospvTrans->ReauthReq, altinfo2);
                    }
                    altinfo = OSPC_OSNULL;
                    altinfo2 = OSPC_OSNULL;
                }
            }
        }
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        /* Get Transaction ID from trans->transactionID */
        OSPPReauthReqSetTrxId(ospvTrans->ReauthReq, ospvTrans->TransactionID);
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        /* Get CustId from trans->provider->custid */
        OSPPReauthReqSetCustId(ospvTrans->ReauthReq, OSPPProviderGetCustId(ospvTrans->Provider));

        /* Get TNDeviceID from trans->provider->tndeviceid */
        OSPPReauthReqSetDeviceId(ospvTrans->ReauthReq, OSPPProviderGetDeviceId(ospvTrans->Provider));
    }

    return errorcode;
}

/*
 * Build a Usage Indication list
 */
int OSPPTransactionBuildUsage(
    OSPTTRANS *ospvTrans,       /* In - Pointer to transaction context */
    OSPT_USAGE_IND **ospvUsage, /* In - Pointer to usage to be initialized */
    OSPT_DEST *ospvDest,        /* In - Pointer to dest associated w/usage */
    OSPE_MESSAGE ospvType)      /* In - Indicates what usage to build */
{
    int errcode = OSPC_ERR_NO_ERROR;
    const char *dest = OSPC_OSNULL;
    OSPT_ALTINFO *altinfo = OSPC_OSNULL;
    OSPE_ROLE role;
    OSPE_PROTOCOL_NAME protocol;
    int cnt;

    *ospvUsage = OSPPUsageIndNew();

    if (*ospvUsage != OSPC_OSNULL) {
        if (ospvType == OSPC_MSG_ARESP) {
            /* Originating */
            if ((ospvTrans->AuthRsp != OSPC_OSNULL) && OSPPAuthRspHasRole(ospvTrans->AuthRsp)) {
                OSPPUsageIndSetRole(*ospvUsage, OSPPAuthRspGetRole(ospvTrans->AuthRsp));
            } else {
                OSPPUsageIndSetRole(*ospvUsage, OSPC_ROLE_SOURCE);
            }

            /* Get CallId */
            if (OSPPDestHasCallId(ospvDest)) {
                OSPPUsageIndSetCallId(*ospvUsage, OSPPDestGetCallId(ospvDest));
            } else {
                errcode = OSPC_ERR_TRAN_CALLID_NOT_FOUND;
                OSPM_DBGERRORLOG(errcode, "Callid not found");
            }

            if (errcode == OSPC_ERR_NO_ERROR) {
                /* Get Source Number (Calling) */
#if 0 /* Change the logic for reporting calling#. Report original calling# instead of authorized calling# */
                if (OSPPDestHasSrcNumber(ospvDest)) {
                    OSPPUsageIndSetSourceNumber(*ospvUsage, OSPPDestGetSrcNumber(ospvDest));
                } else {
                    /*
                     * It is now acceptable to report source usage indications w/o calling number
                     * errorcode = OSPC_ERR_TRAN_SOURCE_NUMBER_NOT_FOUND;
                     * OSPM_DBGERRORLOG(errcode, "Source number not found");
                     */
                    if (OSPPAuthReqHasSourceNumber(ospvTrans->AuthReq)) {3yy
                        OSPPUsageIndSetSourceNumber(*ospvUsage, OSPPAuthReqGetSourceNumber(ospvTrans->AuthReq));
                    }
                }
#endif
                if (OSPPAuthReqHasSourceNumber(ospvTrans->AuthReq)) {
                    OSPPUsageIndSetSourceNumber(*ospvUsage, OSPPAuthReqGetSourceNumber(ospvTrans->AuthReq));
                }
            }

            /* Get Source Alternates (copying a pointer) */
            /* If the dest has a list of SrcAlt, use that list
             * because that is the updated list.
             * else, use the one in the AuthReq
             */
            if (errcode == OSPC_ERR_NO_ERROR) {
                if (OSPPListFirst(&(ospvDest->UpdatedSourceAddr)) != NULL) {
                    OSPPUsageIndMergeSourceAlt(*ospvUsage, &(ospvTrans->AuthReq->SourceAlternate), &(ospvDest->UpdatedSourceAddr));
                } else if (OSPPAuthReqHasSourceAlt(ospvTrans->AuthReq)) {
                    OSPPUsageIndCopySourceAlt(*ospvUsage, &(ospvTrans->AuthReq->SourceAlternate));
                }
            }

            /* Get Device Info (copying a pointer) */
            /* If the dest has a list of DevInfo, use that list
             * because that is the updated list.
             * else, use the one in the AuthReq
             */
            if (errcode == OSPC_ERR_NO_ERROR) {
                if (OSPPListFirst(&(ospvDest->UpdatedDeviceInfo)) != NULL) {
                    OSPPUsageIndCopyDeviceInfo(*ospvUsage, &(ospvDest->UpdatedDeviceInfo));
                } else if (ospvTrans->AuthReq->DeviceInfo != NULL) {
                    OSPPUsageIndCopyDeviceInfo(*ospvUsage, &(ospvTrans->AuthReq->DeviceInfo));
                }
            }

            /* Get Destination Number (Called) */
            if (errcode == OSPC_ERR_NO_ERROR) {
                if (OSPPAuthReqHasDestNumber(ospvTrans->AuthReq)) {
                    OSPPUsageIndSetDestNumber(*ospvUsage, OSPPAuthReqGetDestNumber(ospvTrans->AuthReq));
                } else {
                    errcode = OSPC_ERR_TRAN_DEST_NUMBER_NOT_FOUND;
                    OSPM_DBGERRORLOG(errcode, "Dest number not found");
                }
            }

            /* add DestinationSignalAddress to DestinationAlternates for Usage */
            if ((errcode == OSPC_ERR_NO_ERROR) && OSPPDestHasAddr(ospvDest)) {
                dest = OSPPDestGetAddr(ospvDest);
                altinfo = OSPPAltInfoNew(OSPM_STRLEN(dest), dest, OSPC_ALTINFO_TRANSPORT);
                OSPPUsageIndAddDestinationAlt(*ospvUsage, altinfo);
                altinfo = OSPC_OSNULL;
                dest = NULL;
            }
            if ((errcode == OSPC_ERR_NO_ERROR) && OSPPDestDevHasAddr(ospvDest)) {
                dest = OSPPDestDevGetAddr(ospvDest);
                altinfo = OSPPAltInfoNew(OSPM_STRLEN(dest), dest, OSPC_ALTINFO_H323);
                OSPPUsageIndAddDestinationAlt(*ospvUsage, altinfo);
                altinfo = OSPC_OSNULL;
            }
            if ((errcode == OSPC_ERR_NO_ERROR) && OSPPDestHasNetworkAddr(ospvDest)) {
                dest = OSPPDestGetNetworkAddr(ospvDest);
                altinfo = OSPPAltInfoNew(OSPM_STRLEN(dest), dest, OSPC_ALTINFO_NETWORK);
                OSPPUsageIndAddDestinationAlt(*ospvUsage, altinfo);
                altinfo = OSPC_OSNULL;
            }
            if ((errcode == OSPC_ERR_NO_ERROR) && (ospvDest->SwitchId[0] != '\0')) {
                dest = ospvDest->SwitchId;
                altinfo = OSPPAltInfoNew(OSPM_STRLEN(dest), dest, OSPC_ALTINFO_SWITCHID);
                OSPPUsageIndAddDestinationAlt(*ospvUsage, altinfo);
                altinfo = OSPC_OSNULL;
            }

            /* Get Destination Alternates */
            if ((errcode == OSPC_ERR_NO_ERROR) && OSPPAuthReqHasDestinationAlt(ospvTrans->AuthReq)) {
                OSPPUsageIndMoveDestinationAlt(*ospvUsage, &(ospvTrans->AuthReq->DestinationAlternate));
                /* Function above may be patterned after OSPPUsageIndMoveDestinationAlt */
            }

            /* Move pricing information to Usage Ind structure */
            if ((errcode == OSPC_ERR_NO_ERROR) && (ospvTrans->HasPricingInfo)) {
                (*ospvUsage)->PricingInfo.amount = ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].amount;
                (*ospvUsage)->PricingInfo.increment = ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].increment;
                OSPM_STRCPY((*ospvUsage)->PricingInfo.unit,
                            (const char *)ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].unit);
                OSPM_STRCPY((*ospvUsage)->PricingInfo.currency,
                            (const char *)ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].currency);

                /*
                 * Now increment the current pointer so that it points
                 * to the next value
                 */
                ospvTrans->CurrentPricingInfoElement++;
                (*ospvUsage)->HasPricingInfo = OSPC_TRUE;
            }

            /* Move protocols to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                for (cnt = OSPC_PROTTYPE_START; cnt < OSPC_PROTTYPE_NUMBER; cnt++) {
                    if (cnt == OSPC_PROTTYPE_DESTINATION) {
                        protocol = ospvDest->Protocol;
                    } else {
                        protocol = ospvTrans->Protocol[cnt];
                    }
                    if ((protocol >= OSPC_PROTNAME_START) && (protocol < OSPC_PROTNAME_NUMBER)) {
                        OSPPUsageIndSetProtocol(*ospvUsage, cnt, protocol);
                    } else {
                        OSPPUsageIndSetProtocol(*ospvUsage, cnt, OSPC_PROTNAME_UNKNOWN);
                    }
                }
            }

            /* Move Service Info to the usage structure */
            if ((errcode == OSPC_ERR_NO_ERROR) && (ospvTrans->HasServiceInfo)) {
                (*ospvUsage)->ServiceType = ospvTrans->ServiceType;
                (*ospvUsage)->HasServiceInfo = OSPC_TRUE;
            }

            /* Move role info to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                if ((ospvDest->RoleState >= OSPC_RSTATE_START) && (ospvDest->RoleState < OSPC_RSTATE_NUMBER)) {
                    (*ospvUsage)->RoleState = ospvDest->RoleState;
                } else {
                    (*ospvUsage)->RoleState = ospvTrans->RoleState;
                }

                if ((ospvDest->RoleFormat >= OSPC_RFORMAT_START) && (ospvDest->RoleFormat < OSPC_RFORMAT_NUMBER)) {
                    (*ospvUsage)->RoleFormat = ospvDest->RoleFormat;
                } else {
                    (*ospvUsage)->RoleFormat = ospvTrans->RoleFormat;
                }

                if ((ospvDest->RoleVendor >= OSPC_RVENDOR_START) && (ospvDest->RoleVendor < OSPC_RVENDOR_NUMBER)) {
                    (*ospvUsage)->RoleVendor = ospvDest->RoleVendor;
                } else {
                    (*ospvUsage)->RoleVendor = ospvTrans->RoleVendor;
                }
            }

            /* Move calling party info to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPT_CALL_PARTY *calling = &((*ospvUsage)->CallParty[OSPC_CPARTY_SOURCE]);
                OSPM_STRNCPY(calling->UserName, ospvTrans->CallingParty.UserName, sizeof(calling->UserName));
                OSPM_STRNCPY(calling->UserId, ospvTrans->CallingParty.UserId, sizeof(calling->UserId));
                OSPM_STRNCPY(calling->UserGroup, ospvTrans->CallingParty.UserGroup, sizeof(calling->UserGroup));
            }

            /* Move called party info to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPT_CALL_PARTY *called = &((*ospvUsage)->CallParty[OSPC_CPARTY_DESTINATION]);
                OSPM_STRNCPY(called->UserName, ospvDest->CalledParty.UserName, sizeof(called->UserName));
                OSPM_STRNCPY(called->UserId, ospvDest->CalledParty.UserId, sizeof(called->UserId));
                OSPM_STRNCPY(called->UserGroup, ospvDest->CalledParty.UserGroup, sizeof(called->UserGroup));
            }

            /* Move transfer id and status to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->TransferId, ospvDest->TransferId, sizeof((*ospvUsage)->TransferId));

                (*ospvUsage)->TransferStatus = ospvDest->TransferStatus;
            }

            /* Move destination audio address to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->DestAudioAddr, ospvDest->DestAudioAddr, sizeof((*ospvUsage)->DestAudioAddr));
            }

            /* Move destination video address to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->DestVideoAddr, ospvDest->DestVideoAddr, sizeof((*ospvUsage)->DestVideoAddr));
            }

            /* Move provider post dial delay to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                (*ospvUsage)->ProviderPDD = ospvDest->ProviderPDD;
            }

            /* Move call type to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->CallType, ospvDest->CallType, sizeof((*ospvUsage)->CallType));
            }

            /* Move call category to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->CallCategory, ospvDest->CallCategory, sizeof((*ospvUsage)->CallCategory));
            }

            /* Move network type to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->NetworkType, ospvDest->NetworkType, sizeof((*ospvUsage)->NetworkType));
            }

            /* Move destination service provider to the usage structure */
            if (errcode == OSPC_ERR_NO_ERROR) {
                OSPM_STRNCPY((*ospvUsage)->DestServiceProvider, ospvDest->DestServiceProvider, sizeof((*ospvUsage)->DestServiceProvider));
            }
        } else if (ospvType == OSPC_MSG_AIND) {
            /* Terminating */
            if ((ospvTrans->AuthInd != OSPC_OSNULL) &&
                (OSPPAuthIndHasRole(ospvTrans->AuthInd)) && ((role = OSPPAuthIndGetRole(ospvTrans->AuthInd)) != OSPC_ROLE_DESTINATION))
            {
                OSPPUsageIndSetRole(*ospvUsage, role);
            } else if (ospvTrans->WasLookAheadInfoGivenToApp == OSPC_TRUE) {
                OSPPUsageIndSetRole(*ospvUsage, OSPC_ROLE_OTHER);
            } else {
                OSPPUsageIndSetRole(*ospvUsage, OSPC_ROLE_DESTINATION);
            }

            /* Get CallId */
            if (OSPPAuthIndHasCallId(ospvTrans->AuthInd)) {
                OSPPUsageIndSetCallId(*ospvUsage, OSPPAuthIndGetCallId(ospvTrans->AuthInd));
            }

            /* Source Number (Calling) */
            if (errcode == OSPC_ERR_NO_ERROR) {
                if (OSPPAuthIndHasSourceNumber(ospvTrans->AuthInd)) {
                    OSPPUsageIndSetSourceNumber(*ospvUsage, OSPPAuthIndGetSourceNumber(ospvTrans->AuthInd));
                } else {
                    /*
                     * It is now acceptable to report dest usage indications w/o calling number
                     * errorcode = OSPC_ERR_TRAN_SOURCE_NUMBER_NOT_FOUND;
                     * OSPM_DBGERRORLOG(errorcode, "Source number not found");
                     */
                }
            }

            /* Get Source Alternates */
            if ((errcode == OSPC_ERR_NO_ERROR) && OSPPAuthIndHasSourceAlt(ospvTrans->AuthInd)) {
                OSPPUsageIndMoveSourceAlt(*ospvUsage, &(ospvTrans->AuthInd->SourceAlternate));
            }

            /* Get Device Info (copying a pointer) */
            if ((errcode == OSPC_ERR_NO_ERROR) && (ospvTrans->AuthInd->DeviceInfo != NULL)) {
                OSPPUsageIndMoveDeviceInfo(*ospvUsage, &(ospvTrans->AuthInd->DeviceInfo));
            }

            /* Destination Number (CALLED) */
            if (errcode == OSPC_ERR_NO_ERROR) {
                if (OSPPAuthIndHasDestNumber(ospvTrans->AuthInd)) {
                    OSPPUsageIndSetDestNumber(*ospvUsage, OSPPAuthIndGetDestNumber(ospvTrans->AuthInd));
                } else {
                    errcode = OSPC_ERR_TRAN_DEST_NUMBER_NOT_FOUND;
                    OSPM_DBGERRORLOG(errcode, "Dest number not found");
                }
            }

            /* Get Destination Alternates */
            if ((errcode == OSPC_ERR_NO_ERROR) && OSPPAuthIndHasDestinationAlt(ospvTrans->AuthInd)) {
                OSPPUsageIndMoveDestinationAlt(*ospvUsage, &(ospvTrans->AuthInd->DestinationAlternate));
            }

            /* Move pricing information to Usage Ind structure */
            if ((errcode == OSPC_ERR_NO_ERROR) && (ospvTrans->HasPricingInfo)) {
                (*ospvUsage)->PricingInfo.amount = ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].amount;
                (*ospvUsage)->PricingInfo.increment = ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].increment;
                OSPM_STRCPY((char *)(*ospvUsage)->PricingInfo.unit,
                            (const char *)ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].unit);
                OSPM_STRCPY((char *)(*ospvUsage)->PricingInfo.currency,
                            (const char *)ospvTrans->PricingInfo[ospvTrans->CurrentPricingInfoElement].currency);

                /*
                 * Now increment the current pointer so that it points
                 * to the next value
                 */
                ospvTrans->CurrentPricingInfoElement++;
                (*ospvUsage)->HasPricingInfo = OSPC_TRUE;
            }

            /* Move Service Info to the usage structure */
            if ((errcode == OSPC_ERR_NO_ERROR) && (ospvTrans->HasServiceInfo)) {
                (*ospvUsage)->ServiceType = ospvTrans->ServiceType;
                (*ospvUsage)->HasServiceInfo = OSPC_TRUE;
            }
        } else {
            errcode = OSPC_ERR_TRAN_INVALID_ENTRY;
            OSPM_DBGERRORLOG(errcode, "Usage type not found.");
        }
    } else {
        errcode = OSPC_ERR_TRAN_MALLOC_FAILED;
        OSPM_DBGERRORLOG(errcode, "Malloc failed for usage");
    }

    /* set timestamp */
    if (errcode == OSPC_ERR_NO_ERROR) {
        OSPPUsageIndSetTimestamp(*ospvUsage, time(OSPC_OSNULL));

        /* Get Transaction ID */
        if (ospvTrans->HasTransactionID != OSPC_FALSE) {
            OSPPUsageIndSetTransactionId(*ospvUsage, ospvTrans->TransactionID);

            /* Set ComponentID */
            errcode = OSPPUtilBuildString(ospvTrans->TransactionID,
                 OSPPTransactionGetCounter(ospvTrans), (char **)&((*ospvUsage)->ComponentId));

            /* Update the componentId Unique counter */
            OSPPTransactionUpdateCounter(ospvTrans);

            /* Set MessageId */
            if (errcode == OSPC_ERR_NO_ERROR) {
                errcode = OSPPUtilBuildString(ospvTrans->TransactionID,
                    OSPPTransactionGetCounter(ospvTrans), (char **)&((*ospvUsage)->MessageId));
            }

            /* Update the ComponentId Unique counter again to
             * keep the MessageId and ComponentId values unique
             */
            OSPPTransactionUpdateCounter(ospvTrans);
        } else {
            errcode = OSPC_ERR_TRAN_TXID_NOT_FOUND;
            OSPM_DBGERRORLOG(errcode, "Transaction id not found");
        }
    }

    /* TransNexus extensions */
    if (errcode == OSPC_ERR_NO_ERROR) {
        /* set Customer Id */
        OSPPUsageIndSetCustId(*ospvUsage, OSPPProviderGetCustId(ospvTrans->Provider));
        /* set Device Id */
        OSPPUsageIndSetDeviceId(*ospvUsage, OSPPProviderGetDeviceId(ospvTrans->Provider));
        /* set Fail Reason */
        OSPPUsageIndCopyTermCause(*ospvUsage, OSPPDestGetTermCause(ospvDest));
    } else {
        /* Some error occurred. Get rid of this usage */
        if (ospvUsage != OSPC_OSNULL) {
            OSPPUsageIndDelete(ospvUsage);
        }
    }

    return errcode;
}

/*
 * get pointer to transaction indicated by index.
 *
 * returns OSPTTRANS pointer or OSPC_OSNULL if unsuccessful.
 */
OSPTTRANS *OSPPTransactionCollectionGetItem(
    OSPTTRANCOLLECTION *ospvTranColl,   /* In - Transaction Collection pointer */
    OSPTCOLLECTIONINDEX tranindex)      /* In - Index of needed item */
{
    OSPTTRANS *tmptrans = OSPC_OSNULL;

    if (ospvTranColl->Trans[tranindex.Index] != OSPC_OSNULL)
        tmptrans = ospvTranColl->Trans[tranindex.Index];

    return tmptrans;
}

/*
 * gets handle for new transaction.
 *
 * returns valid OSPTTRANHANDLE if successful,
 *     OSPC_TRAN_HANDLE_INVALID (-1) otherwise
 */
OSPTTRANHANDLE OSPPTransactionCollectionGetNewItem(
    OSPTPROVHANDLE ospvProvider,        /* In - Provider handle */
    OSPTTRANCOLLECTION *ospvTranColl,   /* In - Transaction collection pointer */
    int *ospvError)                     /* In - Error object pointer */
{
    int count = 0;
    OSPTTRANHANDLE tmptranhandle = OSPC_TRAN_HANDLE_INVALID;

    /*
     * go through transaction collection til we find one that is set to
     * OSPC_OSNULL
     */

    for (count = 0; count < OSPC_MAX_TRANS; count++) {
        if (ospvTranColl->Trans[count] == OSPC_OSNULL)
            break;
    }

    /* we looked at all of them and there is no empty slot */
    if (count == OSPC_MAX_TRANS) {
        *ospvError = OSPC_ERR_TRAN_NO_TRANS_SPACE;
        OSPM_DBGERRORLOG(*ospvError, "no empty slot for new transaction.");
    } else {
        OSPM_MALLOC(ospvTranColl->Trans[count], OSPTTRANS, sizeof(OSPTTRANS));

        if (ospvTranColl->Trans[count] != OSPC_OSNULL) {
            OSPM_MEMSET(ospvTranColl->Trans[count], 0, sizeof(OSPTTRANS));

            /* Set up transaction handle */
            tmptranhandle = (count | (ospvProvider << OSPC_PROV_SHIFT));
        } else {
            /* Set to generic malloc failure with this module identifier */
            *ospvError = OSPC_ERR_TRAN_MALLOC_FAILED;
            OSPM_DBGERRORLOG(*ospvError, "malloc new transaction failed.");
        }
    }

    return tmptranhandle;
}

/*
 * set indicated transaction pointer to OSPC_OSNULL.
 *
 * returns void.
 */
void OSPPTransactionCollectionRemoveItem(
    OSPTTRANCOLLECTION *ospvTranColl,   /* In - Transaction collection ptr  */
    OSPTCOLLECTIONINDEX ospvTranIndex)  /* In - Index of item to be removed */
{
    ospvTranColl->Trans[ospvTranIndex.Index] = OSPC_OSNULL;
    ospvTranColl->NumberOfTrans--;
}

/* delete authcnf structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteAuthCnf(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPAuthCnfDelete(&(ospvTrans)->AuthCnf);
    ospvTrans->AuthCnf = OSPC_OSNULL;
}

/* delete authind structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteAuthInd(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPAuthIndDelete(&(ospvTrans)->AuthInd);
    ospvTrans->AuthInd = OSPC_OSNULL;
}

/* delete reauthrequest structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteReauthReq(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPReauthReqDelete(&(ospvTrans)->ReauthReq);
    ospvTrans->ReauthReq = OSPC_OSNULL;
}

/* delete reauthresponse structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteReauthRsp(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPReauthRspDelete(&(ospvTrans)->ReauthRsp);
    ospvTrans->ReauthRsp = OSPC_OSNULL;
}

/* delete request structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteRequest(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPAuthReqDelete(&(ospvTrans)->AuthReq);
    ospvTrans->AuthReq = OSPC_OSNULL;
}

/*
 * delete response structure and all associated structures and pointers.
 *
 * returns void.
 */
void OSPPTransactionDeleteResponse(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPAuthRspDelete(&(ospvTrans)->AuthRsp);
    ospvTrans->AuthRsp = OSPC_OSNULL;
}

/*
 * delete statistics structure and all associated structures and pointers.
 *
 * returns void.
 */
void OSPPTransactionDeleteStatistics(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPStatsDelete(&ospvTrans->Statistics);
    ospvTrans->Statistics = OSPC_OSNULL;
}

/* delete usagecnf structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteUsageCnf(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPUsageCnfDelete(&(ospvTrans)->UsageCnf);
    ospvTrans->UsageCnf = OSPC_OSNULL;
}

/* delete usageind structure and all associated structures and pointers.
 *
 * returns void
 */
void OSPPTransactionDeleteUsageInd(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPT_USAGE_IND *usage = OSPC_OSNULL;

    if ((ospvTrans != OSPC_OSNULL) && (ospvTrans->UsageInd != OSPC_OSNULL)) {
        while (!OSPPListEmpty(&((ospvTrans)->UsageInd))) {

            usage = (OSPT_USAGE_IND *)OSPPListRemove(&((ospvTrans)->UsageInd));

            if (usage != OSPC_OSNULL) {

                OSPPUsageIndDelete(&(usage));
            }
        }

        OSPPListDelete(&((ospvTrans)->UsageInd));
    }
}

/*
 * If the transaction has a CapCnf component, it will be deleted
 * and the pointer set to NULL
 */
void OSPPTransactionDeleteCapCnf(
    OSPTTRANS *ospvTrans)   /* In - Pointer to transaction */
{
    OSPPCapCnfDelete(&(ospvTrans->CapCnf));
}

/*
 *  Make sure accumulation is allowed in this state
 */
void OSPPTransactionGetAccumAllowed(
    OSPTTRANS *ospvTrans,
    OSPTBOOL *ospvAccumAllowed)
{
    switch (ospvTrans->State) {
    case OSPC_TRANSNEW:
    case OSPC_AUTH_REQUEST_FAIL:
    case OSPC_AUTH_REQUEST_SUCCESS:
    case OSPC_GET_DEST_FAIL:
    case OSPC_REPORT_USAGE_BLOCK:
    case OSPC_REPORT_USAGE_SUCCESS:
    case OSPC_VALIDATE_AUTH_FAIL:
    case OSPC_INITIALIZE_FAIL:
    case OSPC_REINITIALIZE_FAIL:
    case OSPC_AUTH_REQUEST_BLOCK:
    case OSPC_REPORT_USAGE_FAIL:
        *ospvAccumAllowed = OSPC_FALSE;
        break;

    case OSPC_INITIALIZE_SUCCESS:
    case OSPC_REINITIALIZE_SUCCESS:
    case OSPC_VALIDATE_AUTH_SUCCESS:
    case OSPC_GET_DEST_SUCCESS:
    case OSPC_ACCUMULATE_SUCCESS:
    case OSPC_ACCUMULATE_FAIL:
        *ospvAccumAllowed = OSPC_TRUE;
        break;

    default:
        /* unknown state */
        *ospvAccumAllowed = OSPC_FALSE;
        break;
    }
}

/*
 * Get the value of the counter in the transaction structure.
 * Returns stored value as int.
 */
int OSPPTransactionGetCounter(
    OSPTTRANS *ospvTransaction) /* In - Transaction handle */
{
    int returnval = 0;

    if (ospvTransaction != OSPC_OSNULL) {
        returnval = ospvTransaction->Counter;
    }

    return returnval;
}

/*
 * gets pointer to transaction structure.
 *
 * returns pointer if successful, else OSPC_OSNULL.
 */
OSPTTRANS *OSPPTransactionGetContext(
    OSPTTRANHANDLE ospvTransaction, /* In - Transaction handle */
    int *ospvError)                 /* Out - Error return pointer */
{
    OSPTTRANS *transctxt = OSPC_OSNULL;
    OSPTTRANCOLLECTION *trancoll = OSPC_OSNULL;
    OSPTCOLLECTIONINDEX tranindex;
    OSPTTRANHANDLE trans = OSPC_TRAN_HANDLE_INVALID;
    OSPTPROVHANDLE provider = OSPC_TRAN_HANDLE_INVALID;
    OSPTPROVIDER *prov = OSPC_OSNULL;

    OSPM_MEMSET(&tranindex, 0, sizeof(tranindex));

    if (*ospvError == OSPC_ERR_NO_ERROR) {
        /* Get transaction index. Mask off provider bits */
        trans = OSPM_GET_TRANSACTION_INDEX(ospvTransaction);

        if (trans != OSPC_TRAN_HANDLE_INVALID) {
            /* Get provider index. Top 8 bits of transaction handle. */
            provider = OSPM_GET_PROV_INDEX_FM_TRANS_HANDLE(ospvTransaction);
        } else {
            *ospvError = OSPC_ERR_TRAN_HANDLE_INVALID;
            OSPM_DBGERRORLOG(*ospvError, "can't get valid transaction handle.");
        }

        if (provider != OSPC_TRAN_HANDLE_INVALID) {
            /* Get provider context pointer */
            prov = OSPPProviderGetContext(provider, ospvError);
        } else {
            *ospvError = OSPC_ERR_TRAN_HANDLE_INVALID;
            OSPM_DBGERRORLOG(*ospvError, "can't get valid provider handle.");
        }

        if (*ospvError == OSPC_ERR_NO_ERROR) {
            /* Get transaction collection pointer */
            *ospvError = OSPPProviderGetTransactionCollection(prov, &trancoll);
        }

        if (*ospvError == OSPC_ERR_NO_ERROR) {
            tranindex.Index = OSPM_GET_TRANSACTION_INDEX(trans);
            transctxt = OSPPTransactionCollectionGetItem(trancoll, tranindex);
        }

        if (transctxt == OSPC_OSNULL) {
            *ospvError = OSPC_ERR_TRAN_TRANSACTION_NOT_FOUND;
            OSPM_DBGERRORLOG(*ospvError, "transaction not found.");

        }
    }

    return transctxt;
}

/*
 * determine if modification of device identifiers is allowed or not
 * depending on transaction state.
 *
 * returns void.
 */
void OSPPTransactionGetIsModifyDeviceIdAllowed(
    OSPTTRANS *ospvTrans,           /* In - Pointer to transaction */
    OSPTBOOL *ospvModifyAllowed)    /* Out - Indicates permission to modify */
{
    switch (ospvTrans->State) {
    case OSPC_GET_DEST_SUCCESS:
    case OSPC_VALIDATE_AUTH_SUCCESS:
    case OSPC_INITIALIZE_SUCCESS:
    case OSPC_REINITIALIZE_SUCCESS:
        *ospvModifyAllowed = OSPC_TRUE;
        break;

    default:
        /* For all other states, set it to FALSE */
        *ospvModifyAllowed = OSPC_FALSE;
        break;
    }
}


/*
 * determine if delete is allowed or not depending on transaction state.
 *
 * returns void.
 */
void OSPPTransactionGetDeleteAllowed(
    OSPTTRANS *ospvTrans,           /* In - Pointer to transaction */
    OSPTBOOL *ospvDeleteAllowed)    /* Out - Indicates permission to delete */
{
#ifdef OSPC_GK_SIM
    extern char *OSPVDeleteAllowed;
    if (OSPVDeleteAllowed != OSPC_OSNULL) {
        *ospvDeleteAllowed = OSPC_TRUE;
        return;
    }
#endif

    /* If NO_DELETE_CHECK is defined, delete will always be allowed */
#ifndef OSP_NO_DELETE_CHECK

    switch (ospvTrans->State) {
    case OSPC_TRANSNEW:
    case OSPC_AUTH_REQUEST_FAIL:
    case OSPC_AUTH_REQUEST_SUCCESS:
    case OSPC_REPORT_USAGE_SUCCESS:
    case OSPC_VALIDATE_AUTH_FAIL:
    case OSPC_INITIALIZE_FAIL:
    case OSPC_REINITIALIZE_FAIL:
    case OSPC_REPORT_USAGE_FAIL:
    case OSPC_CAP_IND_FAIL:
    case OSPC_CAP_IND_SUCCESS:

        *ospvDeleteAllowed = OSPC_TRUE;
        break;

    case OSPC_REPORT_USAGE_BLOCK:
    case OSPC_AUTH_REQUEST_BLOCK:
    case OSPC_VALIDATE_AUTH_SUCCESS:
    case OSPC_GET_DEST_SUCCESS:
    case OSPC_INITIALIZE_SUCCESS:
    case OSPC_REINITIALIZE_SUCCESS:
    case OSPC_ACCUMULATE_SUCCESS:
    case OSPC_ACCUMULATE_FAIL:
        *ospvDeleteAllowed = OSPC_FALSE;
        break;

    case OSPC_GET_DEST_FAIL:
        if (ospvTrans->HasGetDestSucceeded == OSPC_TRUE)
            *ospvDeleteAllowed = OSPC_FALSE;
        else
            *ospvDeleteAllowed = OSPC_TRUE;
        break;

    default:
        /* unknown state */
        *ospvDeleteAllowed = OSPC_FALSE;
        break;
    }
#else
    *ospvDeleteAllowed = OSPC_TRUE;
#endif /* OSP_NO_DELETE_CHECK */
}

/* Dests only available in approved states */
int OSPPTransactionGetDestAllowed(
    OSPTTRANS *ospvTrans)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    switch (ospvTrans->State) {
    case OSPC_AUTH_REQUEST_SUCCESS:
    case OSPC_GET_DEST_FAIL:
    case OSPC_GET_DEST_SUCCESS:
    case OSPC_ACCUMULATE_FAIL:
        break;

    case OSPC_TRANSNEW:
    case OSPC_INVALID_STATE:
    case OSPC_AUTH_REQUEST_BLOCK:
    case OSPC_AUTH_REQUEST_FAIL:
    case OSPC_INITIALIZE_SUCCESS:
    case OSPC_INITIALIZE_FAIL:
    case OSPC_REINITIALIZE_SUCCESS:
    case OSPC_REINITIALIZE_FAIL:
    case OSPC_VALIDATE_AUTH_SUCCESS:
    case OSPC_VALIDATE_AUTH_FAIL:
    case OSPC_REPORT_USAGE_BLOCK:
    case OSPC_REPORT_USAGE_FAIL:
    case OSPC_REPORT_USAGE_SUCCESS:
    case OSPC_ACCUMULATE_SUCCESS:
        errorcode = OSPC_ERR_TRAN_GET_DEST_NOT_ALLOWED;
        break;

    default:
        /* unknown state */
        errorcode = OSPC_ERR_TRAN_GET_DEST_NOT_ALLOWED;
        break;
    }

    return errorcode;
}

int OSPPTransactionGetDestination(
    OSPTTRANS *ospvTrans,                   /* In  - Transaction pointer */
    OSPEFAILREASON ospvFailureReason,       /* In  - Failure Reason for prev dest req */
    unsigned ospvSizeOfTimestamp,           /* In  - Max size for timestamp string */
    char *ospvValidAfter,                   /* Out - Valid After time in string format */
    char *ospvValidUntil,                   /* Out - Valid Until time in string format */
    unsigned *ospvTimeLimit,                /* Out - Number of seconds call is authorised for */
    unsigned *ospvSizeOfCallId,             /* In/Out - Max size for CallId string Actual size of CallId string */
    void *ospvCallId,                       /* Out - Call Id string */
    unsigned ospvSizeOfCalledNumber,        /* In - Max size of called number */
    char *ospvCalledNumber,                 /* Out - Called number string */
    unsigned ospvSizeOfCallingNumber,       /* In - Max size of calling number */
    char *ospvCallingNumber,                /* Out - Calling number string */
    unsigned ospvSizeOfDestination,         /* In - Max size of destination string */
    char *ospvDestination,                  /* Out - Destination string */
    unsigned ospvSizeOfDestinationDevice,   /* In - Max size of destination device string */
    char *ospvDestinationDevice,            /* Out - DestinationDevice string */
    unsigned *ospvSizeOfToken,              /* In/Out - Max size of token string Actual size of token string */
    void *ospvToken)                        /* Out - Token string */
{
    int errcode = OSPC_ERR_NO_ERROR;
    OSPT_CALL_ID *callid = OSPC_OSNULL;
    OSPT_DEST *dest = OSPC_OSNULL;
    OSPT_STATUS *status = OSPC_OSNULL;
    OSPTTIME validtime = 0;
    const char *callednum = OSPC_OSNULL;
    const char *callingnum = '\0';
    const char *sigaddr = OSPC_OSNULL;
    OSPT_TOKEN *token = OSPC_OSNULL;

    if (errcode == OSPC_ERR_NO_ERROR) {
        /* We set this in getFirst and check it in getNext, so if it gets here, it IS getFirst calling */
        if (ospvFailureReason == OSPC_FAIL_NONE) {
            /* Get the status code for first time calls. If the status code < 200 or > 299 then there is no use in continuing. */
            if (OSPPAuthRspHasStatus(ospvTrans->AuthRsp) == OSPC_FALSE) {
                errcode = OSPC_ERR_TRAN_STATUS_INVALID;
                OSPM_DBGERRORLOG(errcode, "status not found");
            } else {
                if ((status = OSPPAuthRspGetStatus(ospvTrans->AuthRsp)) != OSPC_OSNULL) {
                    if (!OSPM_STATUSCODE_SUCCESSFUL(status->Code)) {
                        errcode = status->Code;
                        OSPM_DBGERRORLOG(errcode, "server returned a status error");
                    }
                } else {
                    errcode = OSPC_ERR_TRAN_STATUS_NOT_FOUND;
                    OSPM_DBGERRORLOG(errcode, "status not found");
                }
            }

            if (errcode == OSPC_ERR_NO_ERROR) {
                dest = OSPPAuthRspFirstDest(ospvTrans->AuthRsp);
                ospvTrans->CurrentDest = dest;
            }
        } else {
            /* looking for next destination */
            if (ospvTrans->CurrentDest != OSPC_OSNULL) {
                dest = OSPPAuthRspNextDest(ospvTrans->AuthRsp, ospvTrans->CurrentDest);
                /* are we at the end? */
                if (dest != OSPC_OSNULL) {
                    /* put the failure reason into the destination failure code field and move current destination pointer to next dest */
                    /*
                     * We had set the ospvFailureReason parameter to DEFAULT_GETNEXTDEST_NO_ERROR when
                     * we had received the application had passed OSPC_FAIL_NONE in the ospvFailureReason.
                     * This was done to identify the parent calling function as GetNext rather than Getfirst
                     * Having done that, now we need to log the FailReason as the actual value thatwas passed.
                     * So, change it back to NONE
                     */
                    if (ospvFailureReason == DEFAULT_GETNEXTDEST_NO_ERROR) {
                        ospvFailureReason = OSPC_FAIL_NONE;
                    }

                    OSPPDestSetTermCause(ospvTrans->CurrentDest, OSPC_TCAUSE_Q850, ospvFailureReason, OSPC_OSNULL);
                    ospvTrans->CurrentDest = dest;
                }
            }
        }
    }

    /* if no errors have occurred, get the destination information */
    if (errcode == OSPC_ERR_NO_ERROR) {
        if (dest == OSPC_OSNULL) {
            errcode = OSPC_ERR_TRAN_DEST_INVALID;
            OSPM_DBGERRORLOG(errcode, "destination not found");
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if (ospvSizeOfTimestamp > 0) {
            /* Make sure there is enough space for the timestamp copies. */
            if (ospvSizeOfTimestamp < OSPC_SIZE_TIMESTRING) {
                errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                OSPM_DBGERRORLOG(errcode, "Not enough space for timestrings.");
            } else {
                if (ospvValidAfter != OSPC_OSNULL) {
                    if (OSPPDestHasValidAfter(dest)) {
                        validtime = OSPPDestGetValidAfter(dest);
                        errcode = OSPPOSTimeCalToString(validtime, ospvValidAfter);
                    } else {
                        validtime = OSPC_TIMEMIN;
                        errcode = OSPPOSTimeCalToString(validtime, ospvValidAfter);
                    }
                }

                if (errcode == OSPC_ERR_NO_ERROR) {
                    if (ospvValidUntil != OSPC_OSNULL) {
                        if (OSPPDestHasValidUntil(dest)) {
                            validtime = OSPPDestGetValidUntil(dest);
                            errcode = OSPPOSTimeCalToString(validtime, ospvValidUntil);
                        } else {
                            validtime = OSPC_TIMEMAX;
                            errcode = OSPPOSTimeCalToString(validtime, ospvValidUntil);
                        }
                    }
                }
            }
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if (ospvTimeLimit != OSPC_OSNULL) {
            if (OSPPDestHasLimit(dest)) {
                *ospvTimeLimit = OSPPDestGetLimit(dest);
            } else {
                *ospvTimeLimit = 0;
            }
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if ((*ospvSizeOfCallId > 0) && (ospvCallId != OSPC_OSNULL)) {
            if (OSPPDestHasCallId(dest)) {
                callid = OSPPDestGetCallId(dest);
                if (OSPPCallIdGetSize(callid) > *ospvSizeOfCallId) {
                    errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                    OSPM_DBGERRORLOG(errcode, "not enough space for callid");
                } else {
                    /* Get call id */
                    OSPM_MEMCPY(ospvCallId, OSPPCallIdGetValue(callid), OSPPCallIdGetSize(callid));
                    *ospvSizeOfCallId = OSPPCallIdGetSize(callid);
                }
            } else {
                errcode = OSPC_ERR_TRAN_CALL_ID_INVALID;
                OSPM_DBGERRORLOG(errcode, "null pointer for callid");
            }
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if ((ospvSizeOfCalledNumber > 0 ) && (ospvCalledNumber != OSPC_OSNULL)) {
            if (!OSPPDestHasNumber(dest)) {
                /* get dest number from authreq */
                if (OSPPAuthReqHasDestNumber(ospvTrans->AuthReq)) {
                    callednum = OSPPAuthReqGetDestNumber(ospvTrans->AuthReq);
                }
            } else {
                callednum = OSPPDestGetNumber(dest);
            }

            if (callednum == OSPC_OSNULL) {
                errcode = OSPC_ERR_TRAN_DEST_INVALID;
                OSPM_DBGERRORLOG(errcode, "null pointer for dest number.");
            } else {
                if (ospvSizeOfCalledNumber < OSPM_STRLEN(callednum) + 1) {
                    errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                    OSPM_DBGERRORLOG(errcode, "not enough space for called number");
                } else {
                    /* Get the destination number */
                    OSPM_STRCPY(ospvCalledNumber, callednum);
                }
            }
        }
    }

    /* Get the calling number now */
    if (errcode == OSPC_ERR_NO_ERROR) {
        if ((ospvSizeOfCallingNumber > 0) && (ospvCallingNumber != OSPC_OSNULL)) {
            if (!OSPPDestHasSrcNumber(dest)) {
                /* The source number is not present in the destination. See if it was present in the AuthReq. */
                if (OSPPAuthReqHasDestNumber(ospvTrans->AuthReq)) {
                    callingnum = OSPPAuthReqGetSourceNumber(ospvTrans->AuthReq);
                } else {
                    /* If neither the destination nor the AuthReq had calling number we will return back an empty string. */
                }
            } else {
                callingnum = OSPPDestGetSrcNumber(dest);
            }

            if (ospvSizeOfCallingNumber < OSPM_STRLEN(callingnum) + 1) {
                errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                OSPM_DBGERRORLOG(errcode, "not enough space for calling number");
            } else {
                /* Get the calling number */
                OSPM_STRCPY(ospvCallingNumber, callingnum);
            }
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if ((ospvSizeOfDestination > 0) && (ospvDestination != OSPC_OSNULL)) {
            if (OSPPDestHasAddr(dest)) {
                if ((sigaddr = OSPPDestGetAddr(dest)) == OSPC_OSNULL) {
                    errcode = OSPC_ERR_TRAN_SIGADDR_INVALID;
                    OSPM_DBGERRORLOG(errcode, "null pointer for signal address.");
                } else {
                    if (ospvSizeOfDestination < OSPM_STRLEN(sigaddr) + 1) {
                        errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                        OSPM_DBGERRORLOG(errcode, "not enough space for signal addr");
                    } else {
                        /* Get the signal address (Destination) */
                        OSPM_STRCPY(ospvDestination, sigaddr);
                    }
                }
            } else {
                if ((dest->ServiceType == OSPC_SERVICE_NPQUERY) || (dest->ServiceType == OSPC_SERVICE_CNAMQUERY)) {
                    ospvDestination[0] = '\0';
                } else {
                    errcode = OSPC_ERR_TRAN_SIGADDR_INVALID;
                    OSPM_DBGERRORLOG(errcode, "null pointer for signal address.");
                }
            }
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if ((ospvSizeOfDestinationDevice > 0) && (ospvDestinationDevice != OSPC_OSNULL)) {
            if (OSPPDestDevHasAddr(dest)) {
                sigaddr = OSPPDestDevGetAddr(dest);
                if (sigaddr == OSPC_OSNULL) {
                    errcode = OSPC_ERR_TRAN_SIGADDR_INVALID;
                    OSPM_DBGERRORLOG(errcode, "null pointer for device address.");
                } else {
                    if (ospvSizeOfDestinationDevice < OSPM_STRLEN(sigaddr) + 1) {
                        errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                        OSPM_DBGERRORLOG(errcode, "not enough space for device addr");
                    } else {
                        /* Get the signal address (DestinationDevice) */
                        OSPM_STRCPY(ospvDestinationDevice, sigaddr);
                    }
                }
            } else {
                ospvDestinationDevice[0] = '\0';
            }
        }
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        if ((*ospvSizeOfToken > 0) && (ospvToken != OSPC_OSNULL)) {
            if (OSPPDestHasToken(dest)) {
                if ((token = OSPPDestFirstToken(dest))== OSPC_OSNULL) {
                    errcode = OSPC_ERR_TRAN_TOKEN_INVALID;
                    OSPM_DBGERRORLOG(errcode, "null pointer for token.");
                } else {
                    if (*ospvSizeOfToken < OSPPTokenGetSize(token)) {
                        errcode = OSPC_ERR_TRAN_NOT_ENOUGH_SPACE_FOR_COPY;
                        OSPM_DBGERRORLOG(errcode, "not enough space for token");
                    } else {
                        /* Get the token */
                        *ospvSizeOfToken = OSPPTokenGetSize(token);
                        OSPM_MEMCPY(ospvToken, OSPPTokenGetValue(token), *ospvSizeOfToken);
                    }
                }
            } else {
                if ((dest->ServiceType == OSPC_SERVICE_NPQUERY) || (dest->ServiceType == OSPC_SERVICE_CNAMQUERY)) {
                    OSPM_MEMSET(ospvToken, 0, *ospvSizeOfToken);
                    *ospvSizeOfToken = 0;
                } else {
                    errcode = OSPC_ERR_TRAN_TOKEN_INVALID;
                    OSPM_DBGERRORLOG(errcode, "null pointer for token.");
                }
            }
        }
    }

    return errcode;
}

/*
 * get new transaction handle.
 *
 * returns OSPC_ERR_NO_ERROR if successful, otherwise error code.
 */
int OSPPTransactionGetNewContext(
    OSPTPROVHANDLE ospvProvider,    /* In - Provider handle */
    OSPTTRANHANDLE *ospvTransaction)/* Out - Transaction handle */
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned char transallowed = OSPC_FALSE;
    OSPTPROVIDER *prov = OSPC_OSNULL;
    OSPTTRANCOLLECTION *trancoll = OSPC_OSNULL;

    prov = OSPPProviderGetContext(ospvProvider, &errorcode);

    if (prov != OSPC_OSNULL) {
        OSPPProviderGetNewTransactionAllowed(prov, &transallowed);

        if (transallowed == OSPC_TRUE) {
            errorcode = OSPPProviderGetTransactionCollection(prov, &trancoll);
            if (errorcode == OSPC_ERR_NO_ERROR) {
                OSPM_MUTEX_LOCK(trancoll->TransactionMutex, errorcode);
                if (errorcode == OSPC_ERR_NO_ERROR) {
                    *ospvTransaction = OSPPTransactionCollectionGetNewItem(ospvProvider, trancoll, &errorcode);
                    if (errorcode == OSPC_ERR_NO_ERROR)
                        trancoll->NumberOfTrans++;
                    OSPM_MUTEX_UNLOCK(trancoll->TransactionMutex, errorcode);
                }
            }
        } else {
            errorcode = OSPC_ERR_TRAN_TRANSACTION_NOT_ALLOWED;
            OSPM_DBGERRORLOG(errorcode, "new transaction not allowed.");
        }

        if ((errorcode == OSPC_ERR_NO_ERROR) && (*ospvTransaction == OSPC_TRAN_HANDLE_INVALID)) {
            errorcode = OSPC_ERR_TRAN_HANDLE_INVALID;
            OSPM_DBGERRORLOG(errorcode, "new transaction handle not found.");
        }
    }
    return errorcode;
}

void OSPPTransactionGetReportUsageAllowed(
    OSPTTRANS *ospvTrans,
    OSPTBOOL *ospvReportUsageAllowed)
{
    switch (ospvTrans->State) {
    case OSPC_REPORT_USAGE_SUCCESS:
        *ospvReportUsageAllowed = OSPC_FALSE;
        break;

    case OSPC_TRANSNEW:
    case OSPC_AUTH_REQUEST_FAIL:
    case OSPC_AUTH_REQUEST_SUCCESS:
    case OSPC_GET_DEST_FAIL:
    case OSPC_REPORT_USAGE_BLOCK:
    case OSPC_VALIDATE_AUTH_FAIL:
    case OSPC_INITIALIZE_FAIL:
    case OSPC_REINITIALIZE_FAIL:
    case OSPC_AUTH_REQUEST_BLOCK:
    case OSPC_VALIDATE_AUTH_SUCCESS:
    case OSPC_GET_DEST_SUCCESS:
    case OSPC_REPORT_USAGE_FAIL:
    case OSPC_INITIALIZE_SUCCESS:
    case OSPC_REINITIALIZE_SUCCESS:
    case OSPC_ACCUMULATE_SUCCESS:
    case OSPC_ACCUMULATE_FAIL:
        *ospvReportUsageAllowed = OSPC_TRUE;
        break;

    default:
        /* unknown state */
        *ospvReportUsageAllowed = OSPC_FALSE;
        break;
    }
}

/*
 * get transaction state.
 *
 * returns void.
 */
void OSPPTransactionGetState(
    OSPTTRANS *ospvTrans,           /* In - Transaction pointer */
    OSPE_TRANS_STATE *ospvState)    /* Out - State pointer */
{
    if (ospvTrans != OSPC_OSNULL) {

        *ospvState = ospvTrans->State;
    }
}

/* Get copy of stats from transaction. */
void OSPPTransactionGetStatistics(
    OSPTTRANS *ospvTrans,   /* In- pointer to transaction */
    OSPT_STATS *ospvStats)  /* In - pointer to stats struct */
{
    if ((ospvTrans != OSPC_OSNULL) && (ospvStats != OSPC_OSNULL)) {
        if (OSPPTransactionHasStatistics(ospvTrans)) {
            OSPM_MEMCPY(ospvStats, ospvTrans->Statistics, sizeof(OSPT_STATS));
        }
    }
}

/* Does transaction have statistics? */
OSPTBOOL OSPPTransactionHasStatistics(
    OSPTTRANS *ospvTrans)
{
    OSPTBOOL hasstats = OSPC_FALSE;

    if (ospvTrans != OSPC_OSNULL) {
        if (ospvTrans->Statistics != OSPC_OSNULL) {
            hasstats = OSPC_TRUE;
        }
    }

    return hasstats;
}

/*
 * get message ready to go out and place on queue.
 *
 * If new transactions allowed for this Provider, create the SMIME signature,
 * create the MIME multipart message, put into msginfo structure and place
 * msginfo structure on queue.
 *
 * returns OSPC_ERR_NO_ERROR if successful, otherwise error code.
 */
int OSPPTransactionPrepareAndQueMessage(
    OSPTTRANS *ospvTrans,           /* In - Pointer to transaction structure */
    unsigned char *ospvXMLDoc,      /* In - Pointer to form data */
    unsigned ospvSizeOfXMLDoc,      /* In - Size of form data */
    OSPT_MSG_INFO **ospvMsgInfo)    /* In - Pointer to msginfo structure */
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned char *signature = OSPC_OSNULL;
    unsigned sizeofsignature = 0;
    unsigned char *outgoingmessage = OSPC_OSNULL;
    unsigned sizeofoutmsg = 0;
    OSPTSEC *security = OSPC_OSNULL;
    OSPTPROVIDER *provider = OSPC_OSNULL;
    OSPTCOMM *commManager = OSPC_OSNULL;

    errorcode = OSPPTransactionGetProvider(ospvTrans, &provider);

    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPProviderGetSecurity(provider, &security);
    }
#ifdef ENABLESMIME
    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPSecSignatureCreate(security, ospvXMLDoc, ospvSizeOfXMLDoc, &signature, &sizeofsignature, OSPC_SEC_SIGNATURE_ONLY);

        if ((errorcode == OSPC_ERR_NO_ERROR) && (signature == OSPC_OSNULL)) {
            OSPM_MALLOC(signature, unsigned char, 64);
            if (signature != OSPC_OSNULL) {
                OSPM_STRCPY((char *)signature, "Signature placeholder");
                sizeofsignature = OSPM_STRLEN((char *)signature);
            } else {
                errorcode = OSPC_ERR_SEC_NO_MEMORY;
            }
        }
    }
#endif

    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPMimeMessageCreate(ospvXMLDoc, ospvSizeOfXMLDoc,
            signature, sizeofsignature, (unsigned char **)&outgoingmessage, &sizeofoutmsg);

        if (errorcode == OSPC_ERR_NO_ERROR) {
            if (*ospvMsgInfo != OSPC_OSNULL) {

                /* set the content type depending on the presence
                 * or absence of a signature
                 */
                if (signature != OSPC_OSNULL) {
                    OSPM_MALLOC((*ospvMsgInfo)->ContentType, unsigned char, OSPM_STRLEN(OSPC_COMM_MULTI_MSG) + 1);
                    if ((*ospvMsgInfo)->ContentType != OSPC_OSNULL) {
                        OSPM_MEMSET((*ospvMsgInfo)->ContentType, 0, OSPM_STRLEN(OSPC_COMM_MULTI_MSG) + 1);

                        OSPM_MEMCPY((*ospvMsgInfo)->ContentType, OSPC_COMM_MULTI_MSG, OSPM_STRLEN(OSPC_COMM_MULTI_MSG));
                    }
                } else {
                    OSPM_MALLOC((*ospvMsgInfo)->ContentType, unsigned char, OSPM_STRLEN(OSPC_COMM_TEXT_MSG) + 1);
                    if ((*ospvMsgInfo)->ContentType != OSPC_OSNULL) {
                        OSPM_MEMSET((*ospvMsgInfo)->ContentType, 0, OSPM_STRLEN(OSPC_COMM_TEXT_MSG) + 1);

                        OSPM_MEMCPY((*ospvMsgInfo)->ContentType, OSPC_COMM_TEXT_MSG, OSPM_STRLEN(OSPC_COMM_TEXT_MSG));
                    }
                }


            } else {
                errorcode = OSPC_ERR_TRAN_INVALID_ENTRY;
            }
        } else {
            fprintf(stderr, "Create Mime failed\n");
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            OSPPMsgInfoAssignRequestMsg(*ospvMsgInfo, outgoingmessage, sizeofoutmsg);

            /*
             * Decide which manager to handof the message too.
             * Assign CapabilitiesIndication to the new CommForCapabilities
             * manager.  For all other types of messages, preserver the original
             * behaviour and assign the messages to the main manager - Comm
             */
            if (OSPC_CAP_IND_BLOCK == ospvTrans->State) {
                commManager = ospvTrans->Provider->CommForCapabilities;
            } else {
                commManager = ospvTrans->Provider->Comm;
            }

            errorcode = OSPPCommAddTransaction(commManager, *ospvMsgInfo);

            if (errorcode == OSPC_ERR_NO_ERROR) {
                errorcode = (*ospvMsgInfo)->ErrorCode;
            }
        }
    }
    if (signature != OSPC_OSNULL) {
        OSPM_FREE(signature);
        signature = OSPC_OSNULL;
    }

    return errorcode;
}

/*
 * verifies signature and calls parser to retrieve data from returned message.
 *
 * Extract data and signature from MIME message, verify SMIME signature,
 * parse data out of message.
 *
 * returns OSPC_ERR_NO_ERROR if successful, otherwise error code.
 */
int OSPPTransactionProcessReturn(
    OSPTTRANS *ospvTrans,       /* In - Pointer to transaction */
    OSPT_MSG_INFO *ospvMsgInfo) /* In - Pointer to pointer to msginfo structure */
{
    int errcode = OSPC_ERR_NO_ERROR;
    unsigned char *incomingmsg = OSPC_OSNULL;
    unsigned char *incomingsignature = OSPC_OSNULL;
    unsigned sizeofmsg = 0;
    unsigned sizeofsig = 0;
    void *resultrsp = OSPC_OSNULL;
    OSPE_MESSAGE msgtype = OSPC_MSG_UNKNOWN;
    OSPT_AUDIT *audit = OSPC_OSNULL;
    OSPT_USAGE_CNF *usagecnf = OSPC_OSNULL;

#ifdef ENABLESMIME
    OSPTPROVIDER *provider = OSPC_OSNULL;
    OSPTSEC *security = OSPC_OSNULL;
#endif

    if ((ospvTrans == OSPC_OSNULL) || (ospvMsgInfo == OSPC_OSNULL)) {
        errcode = OSPC_ERR_TRAN_INVALID_ENTRY;
        OSPM_DBGERRORLOG(errcode, "invalid args");
    }

    if (errcode == OSPC_ERR_NO_ERROR) {
        audit = ospvTrans->Provider->Audit;
        /* Parse the incoming message into its MIME components, XML doc and Signature */
        errcode = OSPPMimeMessageParse(ospvMsgInfo->ResponseMsg,
            ospvMsgInfo->ResponseSz, ospvMsgInfo->ContentType, ospvMsgInfo->ContentSz,
            &incomingmsg, &sizeofmsg, &incomingsignature, &sizeofsig);
    }
#ifdef ENABLESMIME
    /* Validate the S/MIME signature */
    if (errcode == OSPC_ERR_NO_ERROR) {
        if (incomingsignature != OSPC_OSNULL) {
            errcode = OSPPTransactionGetProvider(ospvTrans, &provider);
            if (errcode == OSPC_ERR_NO_ERROR) {
                errcode = OSPPProviderGetSecurity(provider, &security);
            }

            errcode = OSPPSecSignatureVerify(security, &incomingmsg, &sizeofmsg, incomingsignature, sizeofsig, OSPC_SEC_SIGNATURE_ONLY);
        } else {
            errcode = OSPC_ERR_TRAN_VALUE_NOT_FOUND;
        }
    }
#endif

    if (errcode == OSPC_ERR_NO_ERROR) {
        /* Send the XML message doc to the XML parser */
        errcode = OSPPXMLMessageParse(incomingmsg, sizeofmsg, &resultrsp, &msgtype);
        if (errcode == OSPC_ERR_NO_ERROR) {
            OSPPAuditCheck(audit, resultrsp, msgtype);
            switch (msgtype) {
            case OSPC_MSG_ARESP:
                /* Authorization Response received */
                ospvTrans->AuthRsp = (OSPT_AUTH_RSP *)resultrsp;
                ospvTrans->TransactionID = ospvTrans->AuthRsp->TrxId;
                ospvTrans->HasTransactionID = OSPC_TRUE;
                break;
            case OSPC_MSG_UCNF:
                /* Usage Confirmation received */
                for ((usagecnf = (OSPT_USAGE_CNF *)OSPPListFirst((OSPTLIST *)&(resultrsp)));
                     (usagecnf != OSPC_OSNULL); (usagecnf = (OSPT_USAGE_CNF *)OSPPListNext((OSPTLIST *)&(resultrsp), usagecnf)))
                {
                    errcode = OSPPTransactionVerifyUsageCnf(usagecnf);
                }
                break;
            case OSPC_MSG_ACNF:
                /* Authorization Confirmation received */
                errcode = OSPPTransactionVerifyAuthCnf((OSPT_AUTH_CNF *)resultrsp);
                if (resultrsp != OSPC_OSNULL) {
                    OSPPAuthCnfDelete((OSPT_AUTH_CNF **)& resultrsp);
                }
                break;
            case OSPC_MSG_REARESP:
                /* Reauthorization Response received */
                ospvTrans->ReauthRsp = (OSPT_REAUTH_RSP *)resultrsp;
                ospvTrans->TransactionID = ospvTrans->ReauthRsp->TrxId;
                ospvTrans->HasTransactionID = OSPC_TRUE;
                break;
            case OSPC_MSG_CAPCNF:
                ospvTrans->CapCnf = (OSPT_CAP_CNF *)resultrsp;
                break;
            default:
                /* The Unknown received */
                errcode = OSPC_ERR_DATA_INVALID_TYPE;
                break;
            }
        }
    }

    /* Delete the usage confirmations */
    if (msgtype == OSPC_MSG_UCNF) {
        if ((OSPTLIST *)&(resultrsp) != OSPC_OSNULL) {
            while (!OSPPListEmpty((OSPTLIST *)&(resultrsp))) {
                usagecnf = (OSPT_USAGE_CNF *)OSPPListRemove((OSPTLIST *)&(resultrsp));
                if (usagecnf != OSPC_OSNULL) {
                    OSPPUsageCnfDelete(&(usagecnf));
                }
            }
            OSPPListDelete((OSPTLIST *)&(resultrsp));
        }
    }

    if (usagecnf != OSPC_OSNULL) {
        OSPPUsageCnfDelete(&usagecnf);
    }

    if (incomingmsg != OSPC_OSNULL) {
        OSPM_FREE(incomingmsg);
        incomingmsg = OSPC_OSNULL;
    }

    if (incomingsignature != OSPC_OSNULL) {
        OSPM_FREE(incomingsignature);
        incomingsignature = OSPC_OSNULL;
    }

    return errcode;
}

/*
 * create space and load request information.
 *
 * Check and store incoming data
 *
 * returns OSPC_ERR_NO_ERROR if successful, otherwise error code.
 */
int OSPPTransactionRequestNew(
    OSPTTRANS *ospvTrans,                       /* In - Transaction Pointer */
    const char *ospvSource,                     /* In - Source of call      */
    const char *ospvSourceDevice,               /* In - SourceDevice of call */
    const char *ospvCallingNumber,              /* In - Calling number      */
    const char *ospvCalledNumber,               /* In - Called number       */
    const char *ospvUser,                       /* In - End user (optional) */
    unsigned ospvNumberOfCallIds,               /* In - Number of call identifiers */
    OSPT_CALL_ID *ospvCallIds[],                /* In - List of call identifiers */
    const char *ospvPreferredDestinations[],    /* In - List of preferred destinations for call */
    unsigned *ospvNumberOfDestinations,         /* In\Out - Max number of destinations Actual number of dests authorised */
    unsigned *ospvSizeOfDetailLog,              /* In\Out - Max size of detail log Actual size of detail log */
    void *ospvDetailLog)                        /* In\Out - Location of detail log storage */
{
    int errorcode = OSPC_ERR_NO_ERROR, numbytesrandom = 0, numbytescounter = 0;
    unsigned i = 0;
    OSPTTIME timestamp = 0;
    OSPT_ALTINFO *altinfo = OSPC_OSNULL;
    OSPT_CALL_ID *callid = OSPC_OSNULL;
    char random[OSPC_MAX_RANDOM];
    char counter[OSPC_MAX_RANDOM];

    OSPM_MEMSET(random, 0, OSPC_MAX_RANDOM);
    OSPM_MEMSET(counter, 0, OSPC_MAX_RANDOM);
    if (ospvSizeOfDetailLog != OSPC_OSNULL) {
        ospvTrans->SizeOfDetailLog = *ospvSizeOfDetailLog;
    }
    ospvTrans->DetailLog = ospvDetailLog;

    /* so far no error */
    errorcode = OSPC_ERR_NO_ERROR;

    /*
     * create the authorization request object
     */
    ospvTrans->AuthReq = OSPPAuthReqNew();

    if (ospvTrans->AuthReq == OSPC_OSNULL) {
        errorcode = OSPC_ERR_DATA_NO_AUTHREQ;
        OSPM_DBGERRORLOG(errorcode, "AuthReq struct not created.");

    } else {
        if (errorcode == OSPC_ERR_NO_ERROR) {
            /*
             * Fill in the AuthReq structure
             */

            /* ----------------------------------
             * Timestamp
             * ----------------------------------
             */
            timestamp = time(NULL);
            OSPPAuthReqSetTimestamp(ospvTrans->AuthReq, timestamp);

            /* ----------------------------------
             * CallId
             * ----------------------------------
             */

            /* call ids - create a linked list */
            OSPPListNew((OSPTLIST *)&(ospvTrans->AuthReq->CallId));

            /* now append each requested call id to the list */
            for (i = 0; i < ospvNumberOfCallIds; i++) {
                callid = OSPPCallIdNew(ospvCallIds[i]->Length, ospvCallIds[i]->Value);

                if (callid != OSPC_OSNULL) {
                    OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->CallId), (void *)callid);
                    callid = OSPC_OSNULL;
                }
            }

            /* --------------------------------------
             * SourceInfo
             * --------------------------------------
             */
            OSPPAuthReqSetSourceNumber(ospvTrans->AuthReq, ospvCallingNumber);

            if (ospvSourceDevice != OSPC_OSNULL && OSPM_STRLEN(ospvSourceDevice) > 0) {
                OSPPListNew((OSPTLIST *)&(ospvTrans->AuthReq->DeviceInfo));
                altinfo = OSPPAltInfoNew(OSPM_STRLEN(ospvSourceDevice), ospvSourceDevice, OSPC_ALTINFO_TRANSPORT);
                if (altinfo != OSPC_OSNULL) {
                    OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->DeviceInfo), altinfo);
                    altinfo = OSPC_OSNULL;
                }
            }

            /* --------------------------------------
             * SourceAlternate
             * --------------------------------------
             */
            if ((ospvSource != OSPC_OSNULL) || (ospvTrans->SrcNetworkId != OSPC_OSNULL) || (ospvTrans->SrcSwitchId[0] != '\0') || (ospvUser != OSPC_OSNULL)) {
                /* source alternates - create a linked list */
                OSPPListNew((OSPTLIST *)&(ospvTrans->AuthReq->SourceAlternate));

                if (ospvTrans->SrcNetworkId != OSPC_OSNULL) {
                    altinfo = OSPPAltInfoNew(OSPM_STRLEN(ospvTrans->SrcNetworkId), ospvTrans->SrcNetworkId, OSPC_ALTINFO_NETWORK);
                    if (altinfo != OSPC_OSNULL) {
                        OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->SourceAlternate), (void *)altinfo);
                        altinfo = OSPC_OSNULL;
                    }
                }

                if (ospvTrans->SrcSwitchId[0] != '\0') {
                    altinfo = OSPPAltInfoNew(OSPM_STRLEN(ospvTrans->SrcSwitchId), ospvTrans->SrcSwitchId, OSPC_ALTINFO_SWITCHID);
                    if (altinfo != OSPC_OSNULL) {
                        OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->SourceAlternate), (void *)altinfo);
                        altinfo = OSPC_OSNULL;
                    }
                }

                if (ospvSource != OSPC_OSNULL) {
                    altinfo = OSPPAltInfoNew(OSPM_STRLEN(ospvSource), ospvSource, OSPC_ALTINFO_TRANSPORT);
                    if (altinfo != OSPC_OSNULL) {
                        OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->SourceAlternate), (void *)altinfo);
                        altinfo = OSPC_OSNULL;
                    }
                }

                if (ospvUser != OSPC_OSNULL) {
                    altinfo = OSPPAltInfoNew(OSPM_STRLEN(ospvUser), ospvUser, OSPC_ALTINFO_SUBSCRIBER);
                    if (altinfo != OSPC_OSNULL) {
                        OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->SourceAlternate), (void *)altinfo);
                        altinfo = OSPC_OSNULL;
                    }
                }
            } else {
                errorcode = OSPC_ERR_TRAN_SOURCE_INVALID;
            }

            /* ----------------------------------------
             * DestinationInfo
             * ----------------------------------------
             */
            OSPPAuthReqSetDestNumber(ospvTrans->AuthReq, ospvCalledNumber);

            /* -------------------------------------------
             * DestinationAlternative
             * --------------------------------------------
             * Preferred destination list.
             */
            altinfo = OSPC_OSNULL;

            if (ospvPreferredDestinations != OSPC_OSNULL) {
                /* destination alternates - create a linked list */
                OSPPListNew((OSPTLIST *)&(ospvTrans->AuthReq->DestinationAlternate));

                i = 0;

                while (ospvPreferredDestinations[i] != OSPC_OSNULL) {
                    if (*(ospvPreferredDestinations[i]) != '\0') {
                        altinfo = OSPPAltInfoNew(OSPM_STRLEN(ospvPreferredDestinations[i]), ospvPreferredDestinations[i], OSPC_ALTINFO_TRANSPORT);
                        if (altinfo != OSPC_OSNULL) {
                            OSPPListAppend((OSPTLIST *)&(ospvTrans->AuthReq->DestinationAlternate), (void *)altinfo);
                            altinfo = OSPC_OSNULL;
                        }
                    } else {
                        /* we're done */
                        break;
                    }

                    i++;
                }
            }

            /* -------------------------------------------
             * Service
             * --------------------------------------------
             * Default (Basic Internet telephony service)
             */

            /* -----------------------------------------
             * MaximumDestinations
             * -----------------------------------------
             */
            OSPPAuthReqSetMaxDest(ospvTrans->AuthReq, *ospvNumberOfDestinations);

            /* !!!TK added following lines */
            /* -----------------------------------------
             * Customer Id
             * -----------------------------------------
             */
            OSPPAuthReqSetCustId(ospvTrans->AuthReq, OSPPProviderGetCustId(ospvTrans->Provider));

            /* -----------------------------------------
             * Device Id
             * -----------------------------------------
             */
            OSPPAuthReqSetDeviceId(ospvTrans->AuthReq, OSPPProviderGetDeviceId(ospvTrans->Provider));

            /* Set ComponentID. We have to use the random generator
               because there is no transaction id yet.
             */

            numbytesrandom = OSPPUtilGetRandom(random, 0);
            numbytescounter = OSPM_SPRINTF(counter, "%d", OSPPTransactionGetCounter(ospvTrans));

            OSPM_MALLOC(ospvTrans->AuthReq->ComponentId, char, numbytesrandom + numbytescounter + 1);
            OSPM_MEMSET(ospvTrans->AuthReq->ComponentId, 0, numbytesrandom + numbytescounter + 1);
            OSPM_MEMCPY(ospvTrans->AuthReq->ComponentId, random, numbytesrandom);
            OSPM_MEMCPY((ospvTrans->AuthReq->ComponentId + numbytesrandom), counter, numbytescounter);

            /* Update the componentId Unique counter */
            OSPPTransactionUpdateCounter(ospvTrans);

            /* Set MessageId. The reasons are the same as for componentId */
            numbytesrandom = OSPPUtilGetRandom(random, 0);
            numbytescounter = OSPM_SPRINTF(counter, "%d", OSPPTransactionGetCounter(ospvTrans));

            OSPM_MALLOC(ospvTrans->AuthReq->MessageId, char, numbytesrandom + numbytescounter + 1);
            OSPM_MEMSET(ospvTrans->AuthReq->MessageId, 0, numbytesrandom + numbytescounter + 1);
            OSPM_MEMCPY(ospvTrans->AuthReq->MessageId, random, numbytesrandom);
            OSPM_MEMCPY((ospvTrans->AuthReq->MessageId + numbytesrandom), counter, numbytescounter);

            /* Update the ComponentId Unique counter again to
             * keep the MessageId and ComponentId values unique.
             */
            OSPPTransactionUpdateCounter(ospvTrans);
        } else {
            errorcode = OSPC_ERR_TRAN_TXID_NOT_FOUND;
            OSPM_DBGERRORLOG(errorcode, "Transaction id not found");
        }
    }

    if (errorcode != OSPC_ERR_NO_ERROR) {

        OSPPAuthReqDelete(&(ospvTrans->AuthReq));
        if (callid != OSPC_OSNULL) {
            OSPPCallIdDelete(&callid);
        }

        if (altinfo != OSPC_OSNULL) {
            OSPPAltInfoDelete(&altinfo);
        }
    }

    return errorcode;
}

/*
 * OSPPTransactionResponseBuild
 * If authrsp is not here create a new one
 * including destination
 * else just add destination
 * Set CurrentDest to point to the newly added destination
 */
int
OSPPTransactionResponseBuild(
    OSPTTRANS *ospvTrans,
    const char *ospvDestination,
    const char *ospvCallingNumber,
    unsigned ospvSizeOfCallId,
    const void *ospvCallId,
    unsigned ospvSizeOfToken,
    const void *ospvToken)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    OSPTTIME t = time(0);
    OSPT_DEST *dest = OSPC_OSNULL;
    OSPT_TOKEN *token = OSPC_OSNULL;

    /* check for new one */
    if (ospvTrans->AuthRsp == OSPC_OSNULL) {

        /* create the authorization response object */
        ospvTrans->AuthRsp = OSPPAuthRspNew();

        if (ospvTrans->AuthRsp == OSPC_OSNULL) {
            errorcode = OSPC_ERR_DATA_NO_AUTHRSP;
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            OSPPAuthRspSetTimestamp(ospvTrans->AuthRsp, t);
        }
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        /* create the destination object */
        dest = OSPPDestNew();
        /* dest = OSPPAuthRspAddDest(ospvTrans->AuthRsp,OSPC_OSNULL); */

        if (dest == OSPC_OSNULL) {
            errorcode = OSPC_ERR_DATA_NO_DEST;
        }
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {

        token = OSPPTokenNew(ospvSizeOfToken, (const unsigned char *)ospvToken);

        if (token != OSPC_OSNULL) {
            OSPPDestAddToken(dest, token);
            token = OSPC_OSNULL;
        } else {
            errorcode = OSPC_ERR_DATA_NO_TOKEN;
        }
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        OSPPDestSetCallId(dest, (const unsigned char *)ospvCallId, ospvSizeOfCallId);

        OSPPDestSetAddr(dest, ospvDestination);
        OSPPDestSetSrcNumber(dest, ospvCallingNumber);

        OSPPAuthRspAddDest(ospvTrans->AuthRsp, dest);

        ospvTrans->CurrentDest = dest;
        dest = OSPC_OSNULL;

    } else {
        OSPPAuthRspDelete(&(ospvTrans->AuthRsp));
        if (dest != OSPC_OSNULL) {
            OSPPDestDelete(&dest);
        }

        if (token != OSPC_OSNULL) {
            OSPPTokenDelete(&token);
        }
    }

    return errorcode;
}

/*
 * set transaction state.
 *
 * returns void.
 */
void OSPPTransactionSetState(
    OSPTTRANS *ospvTrans,       /* In - Transaction pointer */
    OSPE_TRANS_STATE ospvState) /* In - Transaction state */
{
    if (ospvTrans != OSPC_OSNULL) {
        /* Once there is a successful usage report, do not change the state */
        if (ospvTrans->State != OSPC_REPORT_USAGE_SUCCESS) {
            ospvTrans->State = ospvState;
        }
    }
}

/*
 * Update the counter in the transaction structure. Add one unless it is
 * time to roll over.
 */
void OSPPTransactionUpdateCounter(
    OSPTTRANS *ospvTrans)   /* In - Transaction pointer */
{
    if (ospvTrans != OSPC_OSNULL) {
        if (ospvTrans->Counter < INT_MAX)
            ospvTrans->Counter++;
        else
            ospvTrans->Counter = 0;
    }
}

int OSPPTransactionVerifyAuthCnf(
    OSPT_AUTH_CNF *ospvAuthCnf)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    OSPM_ARGUSED(ospvAuthCnf);
    return errorcode;
}

/* Note: this function needs to be expanded to return some specific
 * errorcode for each bad status code.
 */
int OSPPTransactionVerifyUsageCnf(
    OSPT_USAGE_CNF *ospvUsageCnf)
{
    OSPT_STATUS *status = OSPC_OSNULL;
    int errorcode = OSPC_ERR_TRAN_STATUS_INVALID;
    unsigned code = 0;

    if (OSPPUsageCnfHasStatus(ospvUsageCnf)) {
        status = OSPPUsageCnfGetStatus(ospvUsageCnf);
        if (OSPPStatusHasCode(status)) {
            code = OSPPStatusGetCode(status);
            if (OSPM_STATUSCODE_SUCCESSFUL(code))
                errorcode = OSPC_ERR_NO_ERROR;
        }
    }

    return errorcode;
}

int OSPPTransactionGetProvider(
    OSPTTRANS *ospvTransaction,
    OSPTPROVIDER **ospvProvider)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    *ospvProvider = ospvTransaction->Provider;

    return errorcode;
}

int OSPPTransactionValidateTokenCert(
    OSPTTRANS *ospvTrans,
    unsigned char *ospvToken,
    unsigned ospvTokenLen)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    OSPTSVCPT *svcpt = OSPC_OSNULL;
    OSPTSVCPT *svcptlist = OSPC_OSNULL;
    OSPTPROVIDER *provider = OSPC_OSNULL;
    unsigned char *commonname = OSPC_OSNULL;
    unsigned cnlen = 0;
    int found = OSPC_FALSE;

    errorcode = OSPPTransactionGetProvider(ospvTrans, &provider);

    if (errorcode == OSPC_ERR_NO_ERROR) {
        OSPPCommGetServicePointList(provider->Comm, &svcptlist);
        if (svcptlist == OSPC_OSNULL) {
            errorcode = OSPC_ERR_COMM_NO_SVC_PTS;
        }
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPSecGetSignerCertSubjectName(provider->Security, ospvToken, ospvTokenLen, &commonname, &cnlen);
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        for (svcpt = (OSPTSVCPT *)OSPPListFirst((OSPTLIST *)& svcptlist);
             svcpt != OSPC_OSNULL; svcpt = (OSPTSVCPT *)OSPPListNext((OSPTLIST *)& svcptlist, svcpt)) {
            fprintf(stderr, "CN:%s\nHN:%s\n", (char *)commonname, (char *)svcpt->HostName);
            if ((OSPM_STRSTR((const char *)commonname, (const char *)svcpt->HostName)) != OSPC_OSNULL) {
                found = OSPC_TRUE;
                break;
            }
        }
    }

    if (!found) {
        errorcode = OSPC_ERR_TRAN_TOKEN_INVALID;
    }

    if (commonname != OSPC_OSNULL) {
        OSPM_FREE(commonname);
    }

    return errorcode;
}
