/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 ******************************************************************************/
//  File:     EPTF_SIP_TestSteps.ttcn
//  Rev:      <RnXnn>
//  Prodnr:   CNL 113 522
//  Updated:  2012-11-28
//  Contact:  http://ttcn.ericsson.se
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////
//  Module: EPTF_SIP_TestSteps
// 
//  Purpose:
//    Contains the test steps.
// 
//  Module depends on:
//    <EPTF_CLL_Common_Definitions>
//
//    <EPTF_CLL_Common_IndexArrayFunctions>
//
//    <EPTF_CLL_LGenBase_ConfigFunctions>
//
//    <EPTF_CLL_LGenBase_Definitions>
//
//    <EPTF_CLL_LGenBase_EventHandlingFunctions>
//
//    <EPTF_CLL_LGenBase_TemplateDefinitions>
//
//    <EPTF_CLL_LGenBase_TemplateFunctions>
//
//    <EPTF_CLL_HashMapStr2Int_Functions>
//
//    <EPTF_CLL_Base_Functions>
//
//    <EPTF_SIP_Common_Definitions>
//
//    <EPTF_SIP_Common_Functions>
//
//    <EPTF_SIP_CreateRemove_Functions>
//
//    <EPTF_SIP_Dialog_Definitions>
//
//    <EPTF_SIP_Dialog_Functions>
//
//    <EPTF_SIP_EventNotification_Definitions>
//
//    <EPTF_SIP_EventNotification_Functions>
//
//    <EPTF_SIP_LGen_Definitions>
//
//    <EPTF_SIP_MessageCreator_Functions>
//
//    <EPTF_SIP_MessageHandler_Functions>
//
//    <EPTF_SIP_Publish_Functions>
//
//    <EPTF_SIP_StateHandler_Functions>
//
//    <EPTF_SIP_Templates>
//
//    <EPTF_SIP_Transaction_Definitions>
//
//    <EPTF_SIP_Transaction_Functions>
//
//    <EPTF_SIP_Transport_Functions>
//
//    <EPTF_SIP_UserDatabase_Definitions>
//
//    <EPTF_SIP_UserDatabase_Functions>
//
//    <SIPmsg_Types>
//
//    <TCCSecurity_Functions>
//
//  Last review date:
//    2012-11-20
///////////////////////////////////////////////////////////
module EPTF_SIP_TestSteps
{
import from EPTF_CLL_Logging_Functions all;

import from EPTF_CLL_Common_Definitions all;
import from EPTF_CLL_Common_IndexArrayFunctions all;
import from EPTF_CLL_LGenBase_ConfigFunctions all;
import from EPTF_CLL_LGenBase_Definitions all;
import from EPTF_CLL_LGenBase_EventHandlingFunctions all;
import from EPTF_CLL_LGenBase_TemplateDefinitions all;
import from EPTF_CLL_LGenBase_TemplateFunctions all;
import from EPTF_CLL_HashMapStr2Int_Functions all;
import from EPTF_CLL_Base_Functions all;

import from EPTF_SIP_Common_Definitions all;
import from EPTF_SIP_Common_Functions all;
import from EPTF_SIP_CreateRemove_Functions all;
import from EPTF_SIP_Dialog_Definitions all;
import from EPTF_SIP_Dialog_Functions all;
import from EPTF_SIP_EventNotification_Definitions all;
import from EPTF_SIP_EventNotification_Functions all;
import from EPTF_SIP_LGen_Definitions all;
import from EPTF_SIP_MessageCreator_Functions all;
import from EPTF_SIP_MessageHandler_Functions all;
import from EPTF_SIP_Publish_Functions all;
import from EPTF_SIP_StateHandler_Functions all;
import from EPTF_SIP_Templates all;
import from EPTF_SIP_Transaction_Definitions all;
import from EPTF_SIP_Transaction_Functions all;
import from EPTF_SIP_Transport_Functions all;
import from EPTF_SIP_UserDatabase_Definitions all;
import from EPTF_SIP_UserDatabase_Functions all;

import from SIPmsg_Types all;

import from TCCSecurity_Functions all;

const integer c_SIP_doRefresh := 0;
const integer c_SIP_doModify := 1;
const integer c_SIP_doRemove := 2;
const integer c_SIP_doInit := 3;
const charstring c_SIP_CRLF := int2char(13)&int2char(10);

///////////////////////////////////////////////////////////
//WARNING: AppLib databases should not be accessed directly!!!
//
//Automatic dialog and transaction handling.
//
//WARNING: The database state and the data in the outgoing message
//SHOULD BE consistent. The data in bold MUST NOT be changed at all.
//
//Call-back function signatures:
//  type function fcb_EPTF_SIP_setRequest(
//                  inout PDU_SIP_Request pl_request,
//                  in EPTF_LGenBase_TestStepArgs pl_ptr,
//                  in EPTF_IntegerList pl_params := {})
//  runs on self;
//
//  type function fcb_EPTF_SIP_setResponse(
//                  inout PDU_SIP_Response pl_response,
//                  in EPTF_LGenBase_TestStepArgs pl_ptr,
//                  in EPTF_IntegerList pl_params := {})
//  runs on self;
//
//The third parameter is optional and it is defined for each test step. In the
// call-back function 
//this parameter MUST BE accessed with indices given at the test step
// definition.
//
//The requests are handled only if the corresponding message handler is invoked.
// However,
//the message handler MUST BE called in the event listener (or in the FSM cell)
// of the event.
//The responses are handled by the AppLib before dispatch.
//
//v_msgToProcess: contains the incoming SIP message.
///////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_sendSTUN
//
//  Purpose:
//    Sends a SIP STUN
//
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    -
//
//  Detailed Comments:
//    -
//
///////////////////////////////////////////////////////////
public function f_SIP_step_sendSTUN(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_sessionIdx := v_db_users.data[v_currentUser].currentSession;

  if (vf_EPTF_SIP_LGen_msgSender != null)
  {
    var EPTF_SIP_Message_OUT  vl_SIP_message := c_SIP_MessageOUT_init;

    vl_SIP_message.userId := v_currentUser;

    vl_SIP_message.transportParams.proto := v_db_users.data[v_currentUser].preferredTransport;

    vl_SIP_message.transportParams.port_uc := v_db_users.data[v_currentUser].sessions[vl_sessionIdx].port_uc;
    vl_SIP_message.transportParams.port_us := v_db_users.data[v_currentUser].sessions[vl_sessionIdx].port_us;
    vl_SIP_message.transportParams.port_ps := v_db_users.data[v_currentUser].sessions[vl_sessionIdx].port_ps;

    var integer vl_proto := 0;
    if (vl_SIP_message.transportParams.proto == TCP) { vl_proto := 1 }

    if (vcb_EPTF_SIP_getSTUNPayload != null)
    {
      vcb_EPTF_SIP_getSTUNPayload.apply(vl_SIP_message.sipMessage.request, pl_ptr, {vl_proto, v_db_users.data[v_currentUser].sessions[vl_sessionIdx].port_uc});
    }

    if (vcb_EPTF_SIP_getSTUNHostName != null)
    {
      vcb_EPTF_SIP_getSTUNHostName.apply(vl_SIP_message.transportParams.toAddr, pl_ptr, {});
    }

    if (vl_SIP_message.sipMessage.request != ''O)
    {
      vf_EPTF_SIP_LGen_msgSender.apply(vl_SIP_message);  //send message to Transport
    }
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_sendRequest
// 
//  Purpose:
//    Sends a SIP Request message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *invalid dialog index in FSM context data...* - in case of sending ACK in dialog
//    *Message has not been generated...*
//    *could not get external template content...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    This test step should be used for sending out generated requests.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_step_sendRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;
  var integer vl_contentLenght := 0;
  var charstring vl_body := "";
  var charstring vl_requestRaw := "";

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0); 

  if(c_SIP_RequestType_ACKinDialog == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
    var integer vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;
    if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].ACKData.ACKReady)
    {
      f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,"), or ACK is not ready"));
      f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
      return;
    }

    var SipUrl vl_routingURI;
    f_SIP_selectRoutingURI(v_db_dialog.data[vl_dialog].ACKData.ACK, vl_routingURI);
    f_EPTF_SIP_SipUrl2FlatSipUrl(vl_routingURI, v_db_dialog.data[vl_dialog].ACKData.toAddr);

    //body creation
    if (-1 != v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateBodyIdx)
    {
      //get body from external template
      if (not f_EPTF_LGenBase_getTemplateContent(
                v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateBodyIdx,
                v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateParams,
                vl_body))
      {
        f_SIP_Logging_WARNING(
          %definitionId & ": could not get external template content.");
        return;
      }

      if("" != vl_body)
      {
        v_db_dialog.data[vl_dialog].ACKData.ACK.messageBody := vl_body;
        f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_dialog.data[vl_dialog].ACKData.ACK);
        vl_contentLenght := lengthof(vl_body);
      }
    }
    else{
      if(omit != v_db_dialog.data[vl_dialog].ACKData.ACK.messageBody)
      {
        f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_dialog.data[vl_dialog].ACKData.ACK);
        vl_contentLenght := lengthof(v_db_dialog.data[vl_dialog].ACKData.ACK.messageBody);
      }
    }

    //header creation
    if (-1 != v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateHeaderIdx)
    {
      v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateParams[
        sizeof(v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateParams)] := 
        {"contentLength", int2str(vl_contentLenght)};

      //get header from external template
      if (not f_EPTF_LGenBase_getTemplateContent(
                v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateHeaderIdx,
                v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateParams,
                vl_requestRaw))
      {
        f_SIP_Logging_WARNING(
          %definitionId & ": could not get external template content.");
        return;
      }
      //add header delimiter
      vl_requestRaw := vl_requestRaw & c_SIP_CRLF;

      if (omit != v_db_dialog.data[vl_dialog].ACKData.ACK.messageBody)
      {
       vl_requestRaw := vl_requestRaw & v_db_dialog.data[vl_dialog].ACKData.ACK.messageBody;
      }

      //create the encoded request
      v_db_dialog.data[vl_dialog].ACKData.ACKRaw := char2oct(vl_requestRaw); //FIXME maybe not char2oct is needed

    }else{
      if (omit != v_db_dialog.data[vl_dialog].ACKData.ACK.messageBody)
      {
        f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_dialog.data[vl_dialog].ACKData.ACK);
      }

      //create the encoded request
      v_db_dialog.data[vl_dialog].ACKData.ACKRaw := f_EPTF_SIP_sipEncodeRequest(v_db_dialog.data[vl_dialog].ACKData.ACK); // HN75193
    }

    //send to lower layer
    f_EPTF_SIP_Message_SendRequest(
        v_currentUser,
        v_db_users.data[v_currentUser].currentSession,
        v_db_users.data[v_currentUser].preferredTransport, 
        v_db_dialog.data[vl_dialog].ACKData.ACKRaw,
        v_db_dialog.data[vl_dialog].ACKData.toAddr,
        v_db_dialog.data[vl_dialog].ACKData.ACK);

    v_db_dialog.data[vl_dialog].ACKData.ACKSent := true;
  } else if(c_SIP_RequestType_ForwardedACK == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType or
      c_SIP_RequestType_RequestStateless == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
    var SipUrl vl_routingURI;
    var SIP_FlatSipUrl vl_toAddr := cg_FlatSipUrl_base;
    f_SIP_selectRoutingURI(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request, vl_routingURI);
    f_EPTF_SIP_SipUrl2FlatSipUrl(vl_routingURI, vl_toAddr);

    f_EPTF_SIP_Message_SendRequest(
      v_currentUser,
      v_db_users.data[v_currentUser].currentSession,
      v_db_users.data[v_currentUser].preferredTransport,
      f_EPTF_SIP_sipEncodeRequest(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request),
      vl_toAddr,
      v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request);

    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request := omit;
  } else {
    var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
    if(vl_UAC == -1)
    {
      f_SIP_Logging_WARNING(
        %definitionId & 
        ": Message has not been generated. Use appropriate test step to generate message first.");
      return;
    }

    //body creation
    if (-1 != v_db_UAC.data[vl_UAC].templateBodyIdx)
    {
      //get body from external template
      if (not f_EPTF_LGenBase_getTemplateContent(
                v_db_UAC.data[vl_UAC].templateBodyIdx,
                v_db_UAC.data[vl_UAC].templateParams,
                vl_body))
      {
        f_SIP_Logging_WARNING(
          %definitionId & ": could not get external template content.");
        return;
      }

      if("" != vl_body)
      {
        v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
        vl_contentLenght := lengthof(vl_body);
      }
    }else{
      if(omit != v_db_UAC.data[vl_UAC].request.messageBody)
      {
        vl_contentLenght := lengthof(v_db_UAC.data[vl_UAC].request.messageBody);
      }
    }

    //header creation
    if (-1 != v_db_UAC.data[vl_UAC].templateHeaderIdx)
    {
      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {"contentLength", int2str(vl_contentLenght)};
      vl_requestRaw := "";

      if (not f_EPTF_LGenBase_getTemplateContent(
                v_db_UAC.data[vl_UAC].templateHeaderIdx,
                v_db_UAC.data[vl_UAC].templateParams,
                vl_requestRaw))
      {
        f_SIP_Logging_WARNING(
          %definitionId & ": could not get external template content.");
        return;
      }
      //add header delimiter
      vl_requestRaw := vl_requestRaw & c_SIP_CRLF;

      if (omit != v_db_UAC.data[vl_UAC].request.messageBody)
      {
        vl_requestRaw := vl_requestRaw & v_db_UAC.data[vl_UAC].request.messageBody;
      }

      //create the encoded request
      v_db_UAC.data[vl_UAC].requestRaw := char2oct(vl_requestRaw); //FIXME maybe not char2oct is needed

    }else{
      if (omit != v_db_UAC.data[vl_UAC].request.messageBody)
      {
        f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
      }

      //create the encoded request
      v_db_UAC.data[vl_UAC].requestRaw := f_EPTF_SIP_sipEncodeRequest(v_db_UAC.data[vl_UAC].request);
    }

    if(c_SIP_RequestType_ACKnotInDialog == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
      f_EPTF_SIP_TrasactionState_ACKTo3xxto6xx(vl_UAC);
    }

    f_SIP_sendRequestRaw(v_currentUser, vl_UAC, v_db_UAC.data[vl_UAC].sessionIdx);

    if(c_SIP_RequestType_ACKinDialog == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType and
      c_SIP_TrState_Terminated == v_db_UAC.data[vl_UAC].state)
    {
      f_EPTF_SIP_removeUAC(vl_UAC);
    } else if(c_SIP_RequestType_DEREGISTER == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
      v_db_users.data[v_currentUser].regData.state := c_SIP_Reg_State_deregistering;
    } else if(c_SIP_RequestType_REGISTER == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
      if (c_SIP_Reg_State_unregistered == v_db_users.data[v_currentUser].regData.state)
      {
        v_db_users.data[v_currentUser].regData.state := c_SIP_Reg_State_registering;
      }else if (c_SIP_Reg_State_registered == v_db_users.data[v_currentUser].regData.state)
      {
        v_db_users.data[v_currentUser].regData.state := c_SIP_Reg_State_reregistering;
      }
    }

    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx := -1;

    /*
    // NEW
    var charstring vl_headerBody := "", vl_transportBody := "";
    if (f_EPTF_SIP_Message_GetHeaderInMessage(v_db_UAC.data[vl_UAC].requestRaw, "Contact", vl_headerBody)) {
      action("Header body: ", vl_headerBody);
      if (f_EPTF_SIP_Message_GetParamValueInHeaderBody(vl_headerBody, "transport", vl_transportBody)) {
      }
    } else {
      f_SIP_Logging_DEBUG(%definitionId & "Header body NOT found!");
    }
    
    if (ispresent(v_db_UAC.data[vl_UAC].request.msgHeader.contact)) 
    {
      var SipUrl vl_remoteTarget;    
      var charstring vl_transport;

      f_EPTF_SIP_GetUri(v_db_UAC.data[vl_UAC].request.msgHeader.contact.contactBody.contactAddresses[0].addressField,
        vl_remoteTarget);

      if (f_EPTF_SIP_Transport_getTransportFromAddress(vl_remoteTarget, vl_transport)) 
      {
        v_db_users.data[v_currentUser].preferredTransport := 
              f_EPTF_SIP_MessageConvertToTransport(vl_transport);
      }
      else {
        if (v_db_UAC.data[vl_UAC].request.requestLine.method == INVITE_E or
        v_db_UAC.data[vl_UAC].request.requestLine.method == UPDATE_E) { 
          v_db_users.data[v_currentUser].preferredTransport := TCP; 
          }
      } 
    }
    // NEW
    */
    v_db_UAC.data[vl_UAC].request.messageBody := omit;
    // HQ50093 - incorrect content length fix:
    v_db_UAS.data[vl_UAC].request.msgHeader.contentLength := omit;
    v_db_UAS.data[vl_UAC].request.msgHeader.contentType := omit;
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := -1;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_sendResponse
// 
//  Purpose:
//    Sends a SIP Response message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *invalid dialog index in FSM context data...*
//    *Message has not been generated...*
//    *could not start retransmission for user...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    This test step should be used for sending out generated responses.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_step_sendResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;
  var charstring vl_responseRaw := "";

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  if(c_SIP_ResponseCode_ForwardedResponseStateless == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode) {
    f_EPTF_SIP_Message_SendResponse(
      v_currentUser,
      0,
      f_EPTF_SIP_getTransport(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response.msgHeader.via.viaBody[0].sentProtocol.transport),
      f_EPTF_SIP_sipEncodeResponse(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response),
      v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response.msgHeader.via.viaBody[0],
      "",
      v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response);

      v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response := omit;
  } else if(c_SIP_ResponseCode_ForwardedResponse == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode or
      c_SIP_ResponseCode_RejectRequest == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode) {
    var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
    if(vl_UAS == -1)
    {
      f_SIP_Logging_WARNING(
        %definitionId & 
        ": Message has not been generated. Use appropriate test step to generate message first.");
      return;
    }

    if(c_SIP_ResponseCode_ForwardedResponse == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode) {
      v_db_UAS.data[vl_UAS].via := v_db_UAS.data[vl_UAS].response.msgHeader.via.viaBody[0];
    }

    f_SIP_sendResponse(v_currentUser, vl_UAS);

    f_EPTF_SIP_TransactionState_ResponseUAS(v_db_UAS.data[vl_UAS].response, vl_UAS);

    if(c_SIP_ResponseCode_ForwardedResponse == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode) {
      if (c_SIP_TrState_Keepalive == v_db_UAS.data[vl_UAS].state or
            c_SIP_TrState_Terminated == v_db_UAS.data[vl_UAS].state)
      {
        f_EPTF_SIP_removeUAS(vl_UAS);
      }
    } else if(c_SIP_ResponseCode_RejectRequest == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode) {
      if (c_SIP_TrState_Terminated == v_db_UAS.data[vl_UAS].state)
      {
        f_EPTF_SIP_removeUAS(vl_UAS);
      }
      v_lastRequestRejected := true;
    }

    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx := -1;
  } else {
    var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
    if(vl_UAS == -1)
    {
      f_SIP_Logging_WARNING(
        %definitionId & 
        ": Message has not been generated. Use appropriate test step to generate message first.");
      return;
    }

    var integer vl_dialog := v_db_UAS.data[vl_UAS].dialogIdx;
    var integer vl_subscription := v_db_UAS.data[vl_UAS].subscriptionIdx;
    if (OUTOF_DIALOG != v_db_UAS.data[vl_UAS].trInDialog and 
          not f_EPTF_SIP_checkDialog(vl_dialog))
    {
      f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
      return;
    }

    var charstring vl_body;
    var integer vl_contentLenght := 0;
    //body creation
    if (-1 != v_db_UAS.data[vl_UAS].templateBodyIdx)
    {
      if (not f_EPTF_LGenBase_getTemplateContent(
                v_db_UAS.data[vl_UAS].templateBodyIdx,
                v_db_UAS.data[vl_UAS].templateParams,
                vl_body))
      {
        f_SIP_Logging_WARNING(
          %definitionId & ": could not get external template content.");
        return;
      }

      if("" != vl_body)
      {
        v_db_UAS.data[vl_UAS].response.messageBody := vl_body;
        vl_contentLenght := lengthof(vl_body); 
        //f_EPTF_SIP_Message_CalcContentLengthResponse(v_db_UAS.data[vl_UAS].response);
        //vl_contentLenght := v_db_UAS.data[vl_UAS].response.msgHeader.contentLength.len;
      }
    }else{
      if(omit != v_db_UAS.data[vl_UAS].response.messageBody)
      {
        vl_contentLenght := lengthof(v_db_UAS.data[vl_UAS].response.messageBody);
        //f_EPTF_SIP_Message_CalcContentLengthResponse(v_db_UAS.data[vl_UAS].response);
        //vl_contentLenght := v_db_UAS.data[vl_UAS].response.msgHeader.contentLength.len;
      }
    }

    //header creation
    if (-1 != v_db_UAS.data[vl_UAS].templateHeaderIdx)
    {
      v_db_UAS.data[vl_UAS].templateParams[sizeof(v_db_UAS.data[vl_UAS].templateParams)] := {"contentLength", int2str(vl_contentLenght)};

      if (not f_EPTF_LGenBase_getTemplateContent(
                v_db_UAS.data[vl_UAS].templateHeaderIdx,
                v_db_UAS.data[vl_UAS].templateParams,
                vl_responseRaw))
      {
        f_SIP_Logging_WARNING(
          %definitionId & ": could not get external template content.");
        return;
      }
      //add header delimiter
      vl_responseRaw := vl_responseRaw & c_SIP_CRLF;

      if (omit != v_db_UAS.data[vl_UAS].response.messageBody)
      {
        vl_responseRaw := vl_responseRaw & v_db_UAS.data[vl_UAS].response.messageBody;
      }

      //create the encoded response
      v_db_UAS.data[vl_UAS].responseRaw := char2oct(vl_responseRaw); //FIXME maybe not char2oct is needed

    }else{
      if (omit != v_db_UAS.data[vl_UAS].response.messageBody)
      {
        f_EPTF_SIP_Message_CalcContentLengthResponse(v_db_UAS.data[vl_UAS].response); 
        vl_contentLenght := v_db_UAS.data[vl_UAS].response.msgHeader.contentLength.len;
      }
      else
      {
        v_db_UAS.data[vl_UAS].response.msgHeader.contentLength :=
        {
          fieldName := CONTENT_LENGTH_E,
          len := 0
        }
      }

      //create the encoded response
      v_db_UAS.data[vl_UAS].responseRaw := f_EPTF_SIP_sipEncodeResponse(v_db_UAS.data[vl_UAS].response);
    }

    f_SIP_sendResponseRaw(v_currentUser, vl_UAS, v_db_UAS.data[vl_UAS].sessionIdx);
    //f_SIP_sendResponse(v_currentUser, vl_UAS);

    var float vl_retransmissionTime := 0.0;
    var float vl_maxRetransTime := 0.0;
    var float vl_retransTimeout := 0.0;
    if (v_db_UAS.data[vl_UAS].prack and
        101 <= v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode and 
        199 >= v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode)
    {
      vl_retransmissionTime := tsp_SIP_TUTimerValues[c_SIP_TimerTUProvisional_Retransmission];
      vl_maxRetransTime := tsp_SIP_TUTimerValues[c_SIP_TimerTUProvisional_MaxRetransmission];
      vl_retransTimeout := tsp_SIP_TUTimerValues[c_SIP_TimerTUProvisional_RetransTimeout];
    }

    if (0.0 < vl_retransmissionTime)
    {
      v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retransCache := c_SIP_RetransCache_init;
      f_EPTF_SIP_setRetransCache(
        v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retransCache,
        {
          sipMessageRaw := v_db_UAS.data[vl_UAS].responseRaw, 
          sipMessage := { response := v_db_UAS.data[vl_UAS].response},
          transactionId := v_db_UAS.data[vl_UAS].transactionId,
          trIdx := vl_UAS
        },
        vl_retransmissionTime,
        vl_maxRetransTime,
        vl_retransTimeout);

      var float vl_timer := 0.0;
      f_EPTF_SIP_startRetransmission(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retransCache, vl_timer);
      if (not f_EPTF_SIP_StartT_FSMRetransmit(v_currentUser, v_db_UAS.data[vl_UAS].sessionIdx, vl_FSMIdx, vl_timer, v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retransCache.timerIdx))
      {
        f_SIP_Logging_WARNING(log2str(
          %definitionId,": could not start retransmission for user: ",v_currentUser," FSM: ", vl_FSMIdx));
      }
    }

    if(0 <= vl_dialog and
        (INSIDE_DIALOG == v_db_UAS.data[vl_UAS].trInDialog and
        (481 == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode or 408 == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode)) or
        /*REFRESH_DIALOG == v_db_UAS.data[vl_UAS].trInDialog or */CREATE_DIALOG == v_db_UAS.data[vl_UAS].trInDialog or
        REMOVE_DIALOG == v_db_UAS.data[vl_UAS].trInDialog)
    {
      f_EPTF_SIP_DialogState_ResponseUAS(v_db_UAS.data[vl_UAS].response, vl_dialog, vl_subscription, v_db_UAS.data[vl_UAS].trInDialog);
    }

    f_EPTF_SIP_TransactionState_ResponseUAS(v_db_UAS.data[vl_UAS].response, vl_UAS);
    if (c_SIP_TrState_Terminated == v_db_UAS.data[vl_UAS].state)
    {
      f_EPTF_SIP_removeUAS(vl_UAS);
    }

    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx := -1;

    v_db_UAS.data[vl_UAS].response.messageBody := omit;
    // HQ50093 - incorrect content length fix:
    v_db_UAS.data[vl_UAS].response.msgHeader.contentLength := omit;
    v_db_UAS.data[vl_UAS].response.msgHeader.contentType := omit;
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode := -1;
}

///////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////
//  Function: f_SIP_generateExtTemplateBodyOfClient
// 
//  Purpose:
//    Generates the body of a SIP message with external templates
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//    *could not get external template content...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_generateExtTemplateBodyOfClient(in integer pl_eIdx, in integer pl_fIdx)
runs on EPTF_SIP_LGen_CT return charstring
{
  var integer vl_FSMIdx := -1;
  var charstring vl_body := "";

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return "";
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
  if(vl_UAC == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return "";
  }

  if (-1 != v_db_UAC.data[vl_UAC].templateBodyIdx) {
    if (not f_EPTF_LGenBase_getTemplateContent(
              v_db_UAC.data[vl_UAC].templateBodyIdx,
              v_db_UAC.data[vl_UAC].templateParams,
              vl_body))
    {
      f_SIP_Logging_WARNING(%definitionId & ": could not get external template content.");
      return "";
    }

    v_db_UAC.data[vl_UAC].templateBodyIdx := -1; // disable template body
    return vl_body;
  }
  else {
    if(omit != v_db_UAC.data[vl_UAC].request.messageBody) {
      return vl_body;
    }
  }

  //v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := -1;

  v_db_UAC.data[vl_UAC].templateBodyIdx := -1; // disable template body
  return "";
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_generateExtTemplateBodyOfServer
// 
//  Purpose:
//    Generates the body of a SIP message with external templates
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//    *could not get external template content...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_generateExtTemplateBodyOfServer(in integer pl_eIdx, in integer pl_fIdx)
runs on EPTF_SIP_LGen_CT return charstring
{
  var integer vl_FSMIdx := -1;
  var charstring vl_body := "";

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return "";
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
  if(vl_UAS == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return "";
  }

  if (-1 != v_db_UAS.data[vl_UAS].templateBodyIdx) {
    if (not f_EPTF_LGenBase_getTemplateContent(
              v_db_UAS.data[vl_UAS].templateBodyIdx,
              v_db_UAS.data[vl_UAS].templateParams,
              vl_body))
    {
      f_SIP_Logging_WARNING(%definitionId & ": could not get external template content.");
      return "";
    }

    v_db_UAS.data[vl_UAS].templateBodyIdx := -1; // disable template body
    return vl_body;
  }
  else {
    if (not isbound(v_db_UAS.data[vl_UAS].request.messageBody)) {
      return "";
    }
    if(omit != v_db_UAS.data[vl_UAS].request.messageBody) {
      return vl_body;
    }
  }

  //v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := -1;

  v_db_UAS.data[vl_UAS].templateBodyIdx := -1; // disable template body
  return "";
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_setMessageBodyOfRequest
// 
//  Purpose:
//    Generates the body of a SIP message with external templates
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_setMessageBodyOfRequest(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_body)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
  if(vl_UAC == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAC.data[vl_UAC].request.messageBody := pl_body;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_setMessageBodyOfResponse
// 
//  Purpose:
//    Generates the body of a SIP message with external templates
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_setMessageBodyOfResponse(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_body)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
  if(vl_UAS == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAS.data[vl_UAS].response.messageBody := pl_body;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_registerContentTypeExtTemplateForRequest
// 
//  Purpose:
//    Generates the Content-Type of a SIP message with external templates
//    for request messages
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_contentType - *in* *charstrnig* - content type
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_registerContentTypeExtTemplateForRequest(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_contentType)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
  if(vl_UAC == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := { "cType", pl_contentType };
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_registerContentTypeExtTemplateForResponse
// 
//  Purpose:
//    Generates the Content-Type of a SIP message with external templates
//    for response messages
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_contentType - *in* *charstrnig* - content type
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_registerContentTypeExtTemplateForResponse(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_contentType)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
  if(vl_UAS == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAS.data[vl_UAS].templateParams[sizeof(v_db_UAS.data[vl_UAS].templateParams)] := { "cType", pl_contentType };
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_registerRSeqExtTemplateForRequest
// 
//  Purpose:
//    Generates the RSeq of a SIP message with external templates
//    for request messages
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_rseq - *in* *charstrnig* - response number
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_registerRSeqExtTemplateForRequest(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_rseq)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
  if(vl_UAC == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := { "rSeq", pl_rseq };
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_registerRSeqExtTemplateForResponse
// 
//  Purpose:
//    Generates the RSeq of a SIP message with external templates
//    for response messages
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_rseq - *in* *charstrnig* - response number
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
public function f_SIP_registerRSeqExtTemplateForResponse(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_rseq)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
  if(vl_UAS == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAS.data[vl_UAS].templateParams[sizeof(v_db_UAS.data[vl_UAS].templateParams)] := { "rSeq", pl_rseq };
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_registerRSeqNumExtTemplateForRequest
// 
//  Purpose:
//    Generates the RSeqNum of a SIP message with external templates
//    for request messages
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_rseqnum - *in* *charstrnig* - response sequence number
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
private function f_SIP_registerRSeqNumExtTemplateForRequest(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_rseqnum)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
  if(vl_UAC == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := { "rSeqNum", pl_rseqnum };
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_registerRSeqNumExtTemplateForResponse
// 
//  Purpose:
//    Generates the RSeqNum of a SIP message with external templates
//    for response messages
// 
//  Parameters:
//    pl_eIdx - *in* *integer* - entity index
//    pl_fIdx - *in* *integer* - FSM index
//    pl_rseqnum - *in* *charstrnig* - response sequence number
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    -
//
//  Errors:
//    *FSM has not been initialized...*
//    *Message has not been generated...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM.
//    Before calling this test step message MUST be generated
//     with the appropriate "f_SIP_step_generateXXXXX" step.
//
///////////////////////////////////////////////////////////
private function f_SIP_registerRSeqNumExtTemplateForResponse(in integer pl_eIdx, in integer pl_fIdx, in charstring pl_rseqnum)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_eIdx, pl_fIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
  if(vl_UAS == -1)
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": Message has not been generated. Use appropriate test step to generate message first.");
    return;
  }

  v_db_UAS.data[vl_UAS].templateParams[sizeof(v_db_UAS.data[vl_UAS].templateParams)] := { "rSeqNum", pl_rseqnum };
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_modifyRequestCallBack
// 
//  Purpose:
//    Calls the registered call-back functions stored in the "v_db_modifyMsgCallBack" database.
//     to modify Request message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - the indexes of the call-back functions to be called
//
//  Errors:
//    -
//
//  Detailed Comments:
//    -
//
///////////////////////////////////////////////////////////
public function f_SIP_step_modifyRequestCallBack(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var EPTF_IntegerList vl_params := {};
  f_SIP_modifyRequestCallBack(pl_ptr, vl_params);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_modifyRequestCallBack
// 
//  Purpose:
//    Calls the registered call-back functions stored in the "v_db_modifyMsgCallBack" database
//     to modify Request message content or template parameters.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//    pl_params - *in* <EPTF_IntegerList> - the parameters which are passed in the arguments of the call-back function
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - the indexes of the call-back functions to be called
//
//  Errors:
//    *FSM has not been initialized...*
//    *No call-back function index in test step args...*
//    *invalid dialog index in FSM context...* - in case of ACK in dialog
//    *Message has not been generated...*
//    *No call-back function was registered with index...*
//
//  Detailed Comments:
//    The function MUST BE called from an initialized FSM.
//
///////////////////////////////////////////////////////////
public function f_SIP_modifyRequestCallBack(
  in EPTF_LGenBase_TestStepArgs pl_ptr,
  in EPTF_IntegerList pl_params)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;
  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_argIdx := 0;
  var integer vl_argCount := sizeof(pl_ptr.refContext.fRefArgs);
  if(vl_argCount == 0)
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": No call-back function index in test step args");
    return;
  }

  if(c_SIP_RequestType_ACKinDialog == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType)
  {
    var integer vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;

    if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].ACKData.ACKReady)
    {
      f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,"), or ACK is not ready"));
      f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
      return;
    }

    for(vl_argIdx := 0; vl_argIdx < vl_argCount; vl_argIdx := vl_argIdx + 1)
    {
      var integer vl_callBackIdx := -1;
      f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, vl_argIdx, vl_callBackIdx);

      if(not isvalue(v_db_modifyMsgCallBack.data[vl_callBackIdx]))
      {
        f_SIP_Logging_WARNING(
          %definitionId & 
          ": No call-back function was registered with index: " & int2str(vl_callBackIdx));
        return;
      }

      v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyRequestHeaderAndBody.apply(
        v_db_dialog.data[vl_dialog].ACKData.ACK,
        pl_params, pl_ptr);
    }
  } else if(c_SIP_RequestType_ForwardedACK == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType or
      c_SIP_RequestType_RequestStateless == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
    for(vl_argIdx := 0; vl_argIdx < vl_argCount; vl_argIdx := vl_argIdx + 1)
    {
      var integer vl_callBackIdx := -1;
      f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, vl_argIdx, vl_callBackIdx);

      if(not isvalue(v_db_modifyMsgCallBack.data[vl_callBackIdx]))
      {
        f_SIP_Logging_WARNING(
          %definitionId & 
          ": No call-back function was registered with index: " & int2str(vl_callBackIdx));
        return;
      }

      v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyRequestHeaderAndBody.apply(
        v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request,
        pl_params, pl_ptr);
    }
  } else {
    var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
    if(vl_UAC == -1)
    {
      f_SIP_Logging_WARNING(
        %definitionId & 
        ": Message has not been generated. Use appropriate test step to generate message first.");
      return;
    }

    for(vl_argIdx := 0; vl_argIdx < vl_argCount; vl_argIdx := vl_argIdx + 1)
    {
      var integer vl_callBackIdx := -1;
      f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, vl_argIdx, vl_callBackIdx);

      if(not isvalue(v_db_modifyMsgCallBack.data[vl_callBackIdx]))
      {
        f_SIP_Logging_WARNING(
          %definitionId & 
          ": No call-back function was registered with index: " & int2str(vl_callBackIdx));
        return;
      }

      if (0 > v_db_UAC.data[vl_UAC].templateBodyIdx and 0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
      {
        v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyRequestHeaderAndBody.apply(
          v_db_UAC.data[vl_UAC].request,
          pl_params, pl_ptr);
      } else if(0 <= v_db_UAC.data[vl_UAC].templateBodyIdx and 0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
      {
        v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyRequestHeaderAndTemplateBody.apply(
          v_db_UAC.data[vl_UAC].request.msgHeader,
          v_db_UAC.data[vl_UAC].templateParams,
          pl_params, pl_ptr);
      } else if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx and 0 <= v_db_UAC.data[vl_UAC].templateHeaderIdx)
      {
        var charstring vl_body := "";
        v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyRequestTemplateHeaderAndBody.apply(
          v_db_UAC.data[vl_UAC].templateParams, vl_body, pl_params, pl_ptr);
        if("" != vl_body)
        {
          v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
          f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
        }
      } else if(0 <= v_db_UAC.data[vl_UAC].templateBodyIdx and 0 <= v_db_UAC.data[vl_UAC].templateHeaderIdx)
      {
        v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyRequestTemplateParams.apply(
          v_db_UAC.data[vl_UAC].templateParams,
          pl_params, pl_ptr);
      }
    }
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_modifyResponseCallBack
// 
//  Purpose:
//    Calls the registered call-back functions stored in the "v_db_modifyMsgCallBack" database
//     to modify Response message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - the indexes of the call-back functions to be called
//
//  Errors:
//    -
//
//  Detailed Comments:
//    -
//
///////////////////////////////////////////////////////////
public function f_SIP_step_modifyResponseCallBack(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var EPTF_IntegerList vl_params := {};
  f_SIP_modifyResponseCallBack(pl_ptr, vl_params);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_modifyResponseCallBack
// 
//  Purpose:
//    Calls the registered call-back functions stored in the "v_db_modifyMsgCallBack" database
//     to modify Response message content.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//    pl_params - *in* <EPTF_IntegerList> - the parameters which are passed in the arguments of the call-back function
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - the indexes of the call-back functions to be called
//
//  Errors:
//    *FSM has not been initialized...*
//    *No call-back function index in test step args...*
//    *Message has not been generated...*
//    *No call-back function was registered with index...*
//
//  Detailed Comments:
//    The function MUST BE called from an initialized FSM.
//
///////////////////////////////////////////////////////////
public function f_SIP_modifyResponseCallBack(
  in EPTF_LGenBase_TestStepArgs pl_ptr,
  in EPTF_IntegerList pl_params)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;
  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_argIdx := 0;
  var integer vl_argCount := sizeof(pl_ptr.refContext.fRefArgs);

  if(vl_argCount == 0)
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": No call-back function index in test step args");
    return;
  }

  if(c_SIP_ResponseCode_ForwardedResponseStateless == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode) {
    for(vl_argIdx := 0; vl_argIdx < vl_argCount; vl_argIdx := vl_argIdx + 1)
    {
      var integer vl_callBackIdx := -1;
      f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, vl_argIdx, vl_callBackIdx);

      if(not isvalue(v_db_modifyMsgCallBack.data[vl_callBackIdx]))
      {
        f_SIP_Logging_WARNING(
          %definitionId & 
          ": No call-back function was registered with index: " & int2str(vl_callBackIdx));
        return;
      }

      v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyResponseHeaderAndBody.apply(
        v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response,
        pl_params, pl_ptr);
    }
  } else {
    var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
    if(vl_UAS == -1)
    {
      f_SIP_Logging_WARNING(
        %definitionId & 
        ": Message has not been generated. Use appropriate test step to generate message first.");
      return;
    }

    for(vl_argIdx := 0; vl_argIdx < vl_argCount; vl_argIdx := vl_argIdx + 1)
    {
      var integer vl_callBackIdx := -1;
      f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, vl_argIdx, vl_callBackIdx);

      if(not isvalue(v_db_modifyMsgCallBack.data[vl_callBackIdx]))
      {
        f_SIP_Logging_WARNING(
          %definitionId & 
          ": No call-back function was registered with index: " & int2str(vl_callBackIdx));
        return;
      }

      v_db_modifyMsgCallBack.data[vl_callBackIdx].modifyResponseHeaderAndBody.apply(
        v_db_UAS.data[vl_UAS].response,
        pl_params, pl_ptr);
    }
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateREGISTER
// 
//  Purpose:
//    Generates a SIP REGISTER message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (default: calledUser := -1)
//    - 2nd(optional): if 1, creates initial REGISTER (new Call-Id and Cseq) (default: registrar: -1)
//    - 3rd(optional): if -1, external templates will be disabled in the request (default: disableExtTemplates := 0)
//
//  Errors:
//    *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM. The response to this
//    request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC.
//    Stores the UAC index in the FSM context data.
//    
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateREGISTER - step index
//    c_SIP_stepFunction_generateREGISTER - "SIPAppLib: StepFunction_generateREGISTER"
//
//  SIP message passed to call-back:
//  (start example)
//
//    if (ispresent(SIP_User.regData.registrar))
//      Request-URI = SIP_User.regData.registrar
//    elseif (calledUser>=0)
//      Request-URI = SIP_User.calledUsers[calledUser].addr.addrSpecUnion
//    else
//      Request-URI = SIP_User.iD[SIP_User.regData.currentID].addr.addrSpecUnion
//
//    if (calledUser>=0)
//      ToField = SIP_User.calledUsers[calledUser].addr
//    else
//      ToField = SIP_User.iD[SIP_User.regData.currentID].addr
//
//    REGISTER Request-URI SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx REGISTER
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:_ToField_
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
//
///////////////////////////////////////////////////////////
public function f_SIP_step_generateREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateREGISTER(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;
  var integer vl_sessionIdx := v_db_users.data[v_currentUser].currentSession;

  if(ispresent(v_db_users.data[v_currentUser].imsAKAData))
  {  
    if (v_db_users.data[v_currentUser].regData.authRequired)
    {
      f_EPTF_SIP_imsAKA_authRequired(v_currentUser, vl_sessionIdx);
    }
  }

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC, 
    REGISTER_E, 
    vl_sessionIdx,
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport,
    "");

  // default: called user index is -1
  var integer vl_calledUser := -1;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_calledUser);
  // default: initial register not created
  var integer vl_initialReg := -1;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_initialReg);
  // default: external Templates enabled
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 2, vl_disableExtTemplates);


  var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;

  if (1 == vl_initialReg)
  {
    f_SIP_initRegister(v_currentUser, vl_idIdx, vl_calledUser);
  }else{
    var CallidString vl_callId;
    var integer vl_cSeq;

    if (v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest.method == REGISTER_E)
    {
      v_db_users.data[v_currentUser].regData.callId := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest.callId
      v_db_users.data[v_currentUser].regData.cSeq :=
        f_EPTF_SIP_increaseCSeq(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest.cSeq);

    }else if (c_SIP_Reg_State_unregistered == v_db_users.data[v_currentUser].regData.state)
    {
      f_SIP_initRegister(v_currentUser, vl_idIdx, vl_calledUser);
    }else{
      v_db_users.data[v_currentUser].regData.cSeq := f_EPTF_SIP_increaseCSeq(v_db_users.data[v_currentUser].regData.cSeq);
    }
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest := cg_SIP_RetryRequest;

  var charstring vl_localTag;
  f_EPTF_SIP_genLocalTag(v_currentUser, vl_localTag);

  var SipUrl vl_requestUri := v_db_users.data[v_currentUser].regData.registrar;

  var Addr_Union vl_to, vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.currentID, vl_from);

  if (ischosen(v_db_users.data[v_currentUser].regData.toIdx.calledUser))
  {
    f_EPTF_SIP_getCalledUser_addr(v_currentUser, v_db_users.data[v_currentUser].regData.toIdx.calledUser, vl_to);
  }else{
    f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.toIdx.userId, vl_to);
  }

  var RouteBody_List vl_routeBody := {};
  f_EPTF_SIP_SIPRouteBodyList2Route(v_db_users.data[v_currentUser].route, vl_routeBody);

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    vl_requestUri, // Request-URI
    v_db_users.data[v_currentUser].regData.callId, //Call-ID
    v_db_users.data[v_currentUser].regData.cSeq, //CSeq
    vl_to,//To
    vl_from, // From
    vl_localTag,
    vl_routeBody); //local tag

  f_SIP_generateREGISTER(v_currentUser, vl_UAC, vl_sessionIdx);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_extTemplateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTemplateSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_REGISTER, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_REGISTER_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_SIP_createREGISTERTemplate(v_currentUser, vl_UAC, v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createREGISTER
// 
//  Purpose:
//    Generates and sends a SIP REGISTER message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (default: calledUser := -1)
//    - 2nd(optional): if 1, creates initial REGISTER (new Call-Id and Cseq) (default: registrar: -1)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an initialized FSM. The response to this
//    request will be reported to the FSM.
//    
//  Call-back function reference:
//    v_setMsgREGISTER
//
//  Call-back function parameters:
//    - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createREGISTER - step index
//    c_SIP_stepFunction_createREGISTER - "SIPAppLib: StepFunction_createREGISTER"
//
//  SIP message passed to call-back:
//  (start example)
//
//    if (ispresent(SIP_User.regData.registrar))
//      Request-URI = SIP_User.regData.registrar
//    elseif (calledUser>=0)
//      Request-URI = SIP_User.calledUsers[calledUser].addr.addrSpecUnion
//    else
//      Request-URI = SIP_User.iD[SIP_User.regData.currentID].addr.addrSpecUnion
//
//    if (calledUser>=0)
//      ToField = SIP_User.calledUsers[calledUser].addr
//    else 
//      ToField = SIP_User.iD[SIP_User.regData.currentID].addr
//
//    REGISTER Request-URI SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx REGISTER
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:_ToField_
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateREGISTER(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgREGISTER)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgREGISTER.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

private function f_SIP_generateREGISTER(in integer pl_userIdx, in integer pl_UAC, in integer pl_sessionIdx )
runs on EPTF_SIP_LGen_CT
{
  if (ispresent(v_db_users.data[pl_userIdx].imsAKAData))
  {
    if (v_db_users.data[pl_userIdx].regData.authRequired)
    {
      f_EPTF_SIP_imsAKA_setIPSec(pl_userIdx, pl_sessionIdx);
      f_EPTF_SIP_imsAKA_addHeaders(pl_userIdx, v_db_UAC.data[pl_UAC].request.msgHeader);

      f_EPTF_SIP_generateUEParams(pl_userIdx, v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams)

      v_db_users.data[pl_userIdx].imsAKAData.securityClientData:={
        {
          mechanism_name := c_IMSAKA_mechanismName,
          mechanism_params := {}
        }  
      }

      f_SIP_addUserParams2MechList(v_db_users.data[pl_userIdx].imsAKAData.securityClientData[0].mechanism_params, pl_userIdx);

      f_SIP_addSessionParams2MechList(
        v_db_users.data[pl_userIdx].imsAKAData.securityClientData[0].mechanism_params,
        v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.spi_c,
        v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.spi_s,
        v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.port_c,
        v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.port_s);
    }else
    {
      if (c_SIP_Reg_State_unregistered == v_db_users.data[pl_userIdx].regData.state)
      {
        f_EPTF_SIP_generateUEParams(pl_userIdx, v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams)

        v_db_users.data[pl_userIdx].imsAKAData.securityClientData:={
          {
            mechanism_name := c_IMSAKA_mechanismName,
            mechanism_params := {}
          }  
        }

        f_SIP_addUserParams2MechList(v_db_users.data[pl_userIdx].imsAKAData.securityClientData[0].mechanism_params, pl_userIdx);

        f_SIP_addSessionParams2MechList(
          v_db_users.data[pl_userIdx].imsAKAData.securityClientData[0].mechanism_params,
          v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.spi_c,
          v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.spi_s,
          v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.port_c,
          v_db_users.data[pl_userIdx].imsAKAData.negotiatedSessionParams.port_s);

      }

      f_EPTF_SIP_imsAKA_addHeaders(pl_userIdx, v_db_UAC.data[pl_UAC].request.msgHeader);
    }
  }

  v_db_users.data[pl_userIdx].regData.authRequired := false;
}

private function f_SIP_createREGISTERTemplate(
  in integer pl_userIdx, 
  in integer pl_UAC, 
  inout EPTF_LGenBase_TemplParamSubstList pl_templateParams)
runs on EPTF_SIP_LGen_CT
{
  f_EPTF_SIP_CreateNewRequestDictionary(
    pl_UAC,
    pl_templateParams
  );

  var charstring vl_reqHost := "";
  var integer vl_reqPort := 0;

  vl_reqHost := v_db_UAC.data[pl_UAC].request.requestLine.requestUri.hostPort.host;
  if (ispresent(v_db_UAC.data[pl_UAC].request.requestLine.requestUri.hostPort.portField))
  {
    vl_reqPort := v_db_UAC.data[pl_UAC].request.requestLine.requestUri.hostPort.portField;
  }

  pl_templateParams[sizeof(pl_templateParams)] := {"reqHost", vl_reqHost};
  pl_templateParams[sizeof(pl_templateParams)] := {"reqPort", int2str(vl_reqPort)};
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateDEREGISTER
// 
//  Purpose:
//    Generates a SIP de-REGISTER message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): if -1, external templates will be disabled in the request (default: disableExtTemplates := 0)
//
//  Errors:
//    *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC.
//    Stores the UAC index in the FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//  
//  Constants:
//    c_SIP_stepIdx_generateDEREGISTER - test step index
//    c_SIP_stepFunction_generateDEREGISTER - "SIPAppLib: StepFunction_generateDEREGISTER"
//
//  SIP message passed to call-back:
//  (start example)
//
//    if (ispresent(SIP_User.regData.registrar))
//      Request-URI = SIP_User.regData.registrar
//    elseif (calledUser>=0)
//      Request-URI = SIP_User.calledUsers[calledUser].addr.addrSpecUnion
//    else
//      Request-URI = SIP_User.iD[SIP_User.regData.currentID].addr.addrSpecUnion
//
//    if (calledUser>=0)
//      ToField = SIP_User.calledUsers[calledUser].addr
//    else
//      ToField = SIP_User.iD[SIP_User.regData.currentID].addr
//
//    REGISTER Request-URI SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:*
//    Content-Length:0
//    CSeq:xxxxxxxxxx REGISTER
//    Expires:0
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:_ToField_
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
//
///////////////////////////////////////////////////////////
public function f_SIP_step_generateDEREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateDEREGISTER(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateDEREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);


  if (v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest.method == REGISTER_E)
  {
    v_db_users.data[v_currentUser].regData.callId := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest.callId
    v_db_users.data[v_currentUser].regData.cSeq :=
      f_EPTF_SIP_increaseCSeq(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest.cSeq);
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].retryRequest := cg_SIP_RetryRequest;

  var integer vl_UAC := -1;
  var integer vl_sessionIdx := v_db_users.data[v_currentUser].currentSession;

  if(ispresent(v_db_users.data[v_currentUser].imsAKAData))
  {  
    if (v_db_users.data[v_currentUser].regData.authRequired)
    {
      f_EPTF_SIP_imsAKA_authRequired(v_currentUser, vl_sessionIdx);
    }
  }

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC, 
    REGISTER_E, 
    vl_sessionIdx,
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport, 
    "");

  v_db_users.data[v_currentUser].regData.cSeq := f_EPTF_SIP_increaseCSeq(v_db_users.data[v_currentUser].regData.cSeq);

  var charstring vl_localTag;
  f_EPTF_SIP_genLocalTag(v_currentUser, vl_localTag);

  var SipUrl vl_requestUri := v_db_users.data[v_currentUser].regData.registrar;

  var Addr_Union vl_to, vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.currentID, vl_from);

  if (ischosen(v_db_users.data[v_currentUser].regData.toIdx.calledUser))
  {
    f_EPTF_SIP_getCalledUser_addr(v_currentUser, v_db_users.data[v_currentUser].regData.toIdx.calledUser, vl_to);
  }else{
    f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.toIdx.userId, vl_to);
  }

  var RouteBody_List vl_routeBody := {};
  f_EPTF_SIP_SIPRouteBodyList2Route(v_db_users.data[v_currentUser].route, vl_routeBody);

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    vl_requestUri, // Request-URI
    v_db_users.data[v_currentUser].regData.callId, //Call-ID
    v_db_users.data[v_currentUser].regData.cSeq, //CSeq
    vl_to,//To
    vl_from, // From
    vl_localTag,
    vl_routeBody); //local tag

  f_SIP_generateREGISTER(v_currentUser, vl_UAC, vl_sessionIdx);

  v_db_UAC.data[vl_UAC].request.msgHeader.expires :=
  {
    fieldName := EXPIRES_E,
    deltaSec := "0"
  }

  v_db_UAC.data[vl_UAC].request.msgHeader.contact :=
  {
    fieldName := CONTACT_E,
    contactBody :=
    {
      wildcard := "*"
    }
  }

  // default: external Templates enabled
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_extTemplateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTemplateSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_DEREGISTER, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_DEREGISTER_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_SIP_createREGISTERTemplate(v_currentUser, vl_UAC, v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := c_SIP_RequestType_DEREGISTER;

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createDEREGISTER
// 
//  Purpose:
//    Generates and sends a SIP de-REGISTER message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgDEREGISTER
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//  
//  Constants:
//    c_SIP_stepIdx_createDEREGISTER - test step index
//    c_SIP_stepFunction_createDEREGISTER - "SIPAppLib: StepFunction_createDEREGISTER"
//
//  SIP message passed to call-back:
//(start example)
//    if (ispresent(SIP_User.regData.registrar))
//      Request-URI = SIP_User.regData.registrar
//    elseif (calledUser>=0)
//      Request-URI = SIP_User.calledUsers[calledUser].addr.addrSpecUnion
//    else
//      Request-URI = SIP_User.iD[SIP_User.regData.currentID].addr.addrSpecUnion
//
//    if (calledUser>=0)
//      ToField = SIP_User.calledUsers[calledUser].addr
//    else
//      ToField = SIP_User.iD[SIP_User.regData.currentID].addr
//
//    REGISTER Request-URI SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:*
//    Content-Length:0
//    CSeq:xxxxxxxxxx REGISTER
//    Expires:0
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:_ToField_
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//(end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createDEREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateDEREGISTER(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgDEREGISTER)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgDEREGISTER.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleREGISTER
// 
//  Purpose:
//    Handles an incoming REGISTER request. SHOULD BE called to handle the c_SIP_eventIdx_REGISTER
//    event. The step does not create any kind of database entries. The <f_EPTF_SIP_storeRegistration>
//    function can be used for this purpose.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleREGISTER - test step index
//    c_SIP_stepFunction_handleREGISTER - "SIPAppLib: StepFunction_handleREGISTER"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleREGISTER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx:=pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  f_EPTF_SIP_createNewUAS(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession,
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateINVITE
// 
//  Purpose:
//    Generates a SIP INVITE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//    - 2nd(optional): contact identifier (contactID := 0)
//    - 3rd(optional): if 1, the Require:100rel header will be added to the request (add100rel := 0)
//    - 4th(optional): if 1, early dialogs will not be created (createEarlyDialog := 0)
//    - 5th(optional): if 1, the Require:precondition header will be added to the request (precondition := 0)
//    - 6th(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC.
//    Stores the UAC index in the FSM context data.
//    Creates a dialog. The dialog index is stored in the FSM context data. *WARNING*: only one dialog index can be stored in the
//      FSM context data
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//    
//  Constants:
//    c_SIP_stepIdx_generateINVITE - test step index
//    c_SIP_stepFunction_generateINVITE - "SIPAppLib: StepFunction_generateINVITE"
//
//  SIP message passed to call-back:
//  (start example)
//
//    INVITE SIP_User.calledUsers[calledUser].addr.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:xxxxxxxxxx INVITE
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    [Require:100rel]
//    To:SIP_User.calledUsers[calledUser]
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateINVITE(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;
  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(
      %definitionId & 
      ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;
  var integer vl_dialog := -1;

  //default values
  var integer vl_calledUser := 0;
  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  var integer vl_add100rel := 0;
  var integer vl_addPrecond := 0;
  var integer vl_createEarlyDialog := 0;
  var integer vl_disableExtTemplates := 0;

  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_calledUser);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_contactID);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 2, vl_add100rel);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 3, vl_createEarlyDialog);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 4, vl_addPrecond);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 5, vl_disableExtTemplates);

  var boolean vl_create := true;
  if (1 == vl_createEarlyDialog)
  {
    vl_create := false;
  }

  var Addr_Union vl_to, vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.currentID, vl_from);
  f_EPTF_SIP_getCalledUser_addr(v_currentUser, vl_calledUser, vl_to);

  f_EPTF_SIP_CreateOutgoingDialog(
    vl_dialog,
    v_currentUser,
    vl_FSMIdx,
    vl_from,
    vl_to,
    INVITE_E,
    vl_create
    );

  f_EPTF_SIP_check4xxRetryInDialog(INVITE_E, v_currentUser, vl_dialog, vl_FSMIdx);

  v_db_dialog.data[vl_dialog].userSessionAssociated := true;

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    INVITE_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    pl_ptr.refContext.fCtxIdx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    CREATE_DIALOG);

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  var charstring vl_extraHeaders := "";
  var OptionTag_List vl_optionsTags := {};
  f_EPTF_SIP_prepareOptionsTag(vl_add100rel, vl_addPrecond, vl_disableExtTemplates,
    vl_optionsTags ,vl_extraHeaders);

  if (sizeof(vl_optionsTags) > 0)
  {
    v_db_UAC.data[vl_UAC].request.msgHeader.require := {
      fieldName := REQUIRE_E,
      optionsTags := vl_optionsTags
    }

    if (vl_disableExtTemplates > -1) {
      vl_extraHeaders := "Require: " & vl_extraHeaders & "\r\n";
    }
  }

  if (omit != v_db_UAC.data[vl_UAC].request.msgHeader.authorization)
  {
    v_db_dialog.data[vl_dialog].ACKData.authInfo :={
      fieldName := AUTHORIZATION_E,
      credentials := v_db_UAC.data[vl_UAC].request.msgHeader.authorization.body
    }
  }else if(omit != v_db_UAC.data[vl_UAC].request.msgHeader.proxyAuthorization)
  {
    v_db_dialog.data[vl_dialog].ACKData.authInfo :={
      fieldName := PROXY_AUTHORIZATION_E,
      credentials := v_db_UAC.data[vl_UAC].request.msgHeader.proxyAuthorization.credentials
    }
  }
  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID); 

  if (vl_disableExtTemplates > -1)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_INVITE, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_INVITE_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );
      /*
      if (v_db_UAC.data[vl_UAC].templateParams[6].paramValue[0] == "+") 
      {
        v_db_UAC.data[vl_UAC].templateParams[6].paramValue := //"600" &
          substr(v_db_UAC.data[vl_UAC].templateParams[6].paramValue, 1, 
          lengthof(v_db_UAC.data[vl_UAC].templateParams[6].paramValue)-1);
      }
      else 
      {
        v_db_UAC.data[vl_UAC].templateParams[6].paramValue := //"600" &
          v_db_UAC.data[vl_UAC].templateParams[6].paramValue;
      }      
      */

      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {
        "extraHeaders", vl_extraHeaders
      }

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createINVITE
// 
//  Purpose:
//    Generates and sends a SIP INVITE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LG!=enBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//    - 2nd(optional): contact identifier (contactID := 0)
//    - 3rd(optional): if 1, the Require:100rel header will be added the the request (add100rel := 0)
//    - 4th(optional): if 1, early dialogs will not be created (createEarlyDialog := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgINVITE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//    
//  Constants:
//    c_SIP_stepIdx_createINVITE - test step index
//    c_SIP_stepFunction_createINVITE - "SIPAppLib: StepFunction_createINVITE"
//
//  SIP message passed to call-back:
//(start example)
//
//    INVITE SIP_User.calledUsers[calledUser].addr.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:xxxxxxxxxx INVITE
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    [Require:100rel]
//    To:SIP_User.calledUsers[calledUser]
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  if(not f_SIP_private_generateINVITE(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgINVITE)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgINVITE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleINVITE
// 
//  Purpose:
//    Handles an incoming INVITE request. SHOULD BE called to handle the c_SIP_eventIdx_INVITE 
//    event. *WARNING*: the test step cannot handle the c_SIP_eventIdx_reINVITE event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *could not start dialog watchdog timer*: each time a dialog is created a
//        watchdog timer is started, and the dialog is deleted on timeout. The error message means that the
//        timer could not be started
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS and a new dialog. The UAS and the dialog index is stored in the FSM context data.
//    
//
//  Constants:
//    c_SIP_stepIdx_handleINVITE - test step index
//    c_SIP_stepFunction_handleINVITE - "SIPAppLib: StepFunction_handleINVITE"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;
  var integer vl_dialog := -1;

  if(not ischosen(v_msgToProcess.request)){
    f_EPTF_Logging_error(true, %definitionId&
      ": The message is not a request: "&log2str(v_msgToProcess.request)&
      "\nEvent to be processed: "&log2str(pl_ptr.reportedEvent)&
      "\nFSM table: "&f_EPTF_LGenBase_getFsmNameByCtxIdx(vl_eCtx, vl_fsmCtx));

  }
  f_EPTF_SIP_CreateIncomingDialog(v_msgToProcess.request, vl_dialog, v_currentUser, vl_FSMIdx);

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession, 
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    vl_dialog, 
    CREATE_DIALOG);

  v_db_dialog.data[vl_dialog].UASIdx := vl_UAS; //hack, SIP sucks
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateReINVITE
// 
//  Purpose:
//    Generates a SIP re-INVITE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1nd(optional): contact identifier (contactID := 0)
//    - 2nd(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//    - *invalid dialog index in FSM context data*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC.
//    Stores the UAC index in the FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//    
//  Constants:
//    c_SIP_stepIdx_generateReINVITE - test step index
//    c_SIP_stepFunction_generateReINVITE - "SIPAppLib: StepFunction_generateReINVITE"
//
//  SIP message passed to call-back:
//(start example)
//
//    INVITE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum INVITE
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateReINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateReINVITE(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateReINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_dialog := -1;
  var integer vl_UAC := -1;

  vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;
  if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].userSessionAssociated)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }

  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;

  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_contactID);

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    INVITE_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    REFRESH_DIALOG);

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  if (omit != v_db_UAC.data[vl_UAC].request.msgHeader.authorization)
  {
    v_db_dialog.data[vl_dialog].ACKData.authInfo :={
      fieldName := AUTHORIZATION_E,
      credentials := v_db_UAC.data[vl_UAC].request.msgHeader.authorization.body
    }
  }else if(omit != v_db_UAC.data[vl_UAC].request.msgHeader.proxyAuthorization)
  {
    v_db_dialog.data[vl_dialog].ACKData.authInfo :={
      fieldName := PROXY_AUTHORIZATION_E,
      credentials := v_db_UAC.data[vl_UAC].request.msgHeader.proxyAuthorization.credentials
    }
  }

  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID); 

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_reINVITE, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_reINVITE_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  //v_db_UAC.data[vl_UAC].templateBodyIdx := -1;
  //v_db_UAC.data[vl_UAC].templateHeaderIdx := -1;

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createReINVITE
// 
//  Purpose:
//    Generates and sends a SIP re-INVITE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1nd(optional): contact identifier (contactID := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//    - *invalid dialog index in FSM context data*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgReINVITE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//    
//  Constants:
//    c_SIP_stepIdx_createReINVITE - test step index
//    c_SIP_stepFunction_createReINVITE - "SIPAppLib: StepFunction_createReINVITE"
//
//  SIP message passed to call-back:
//(start example)
//
//    INVITE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum INVITE
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createReINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateReINVITE(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgINVITE)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgINVITE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleReINVITE
// 
//  Purpose:
//    Handles an incoming re-INVITE request. SHOULD BE called to handle the c_SIP_eventIdx_reINVITE 
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//    
//
//  Constants:
//    c_SIP_stepIdx_handleReINVITE - test step index
//    c_SIP_stepFunction_handleReINVITE - "SIPAppLib: StepFunction_handleReINVITE"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleReINVITE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  if (0 <= v_db_dialog.data[v_currentDialog].UASIdx)//hack, SIP sucks
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": received new INVITE, but ACK has not arrived to the previous one."));
    f_EPTF_SIP_handleACK(v_currentDialog, f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0), vl_FSMIdx);
  }

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession, 
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx,
    v_currentDialog,
    REFRESH_DIALOG);

  f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);

  v_db_dialog.data[v_currentDialog].UASIdx := vl_UAS; //hack, SIP sucks

  if (ispresent(v_msgToProcess.request.msgHeader.contact) and
          ischosen(v_msgToProcess.request.msgHeader.contact.contactBody.contactAddresses))
  {
    var SipUrl vl_remoteTarget;
    var charstring vl_transport;

    f_EPTF_SIP_GetUri(v_msgToProcess.request.msgHeader.contact.contactBody.contactAddresses[0].addressField,
      vl_remoteTarget);

    if (f_EPTF_SIP_Transport_getTransportFromAddress(vl_remoteTarget, vl_transport)) 
    {
      v_db_users.data[v_currentUser].preferredTransport := 
        f_EPTF_SIP_MessageConvertToTransport(vl_transport);
    }

    f_EPTF_SIP_refreshTarget(v_currentDialog, vl_remoteTarget);
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateUPDATE
// 
//  Purpose:
//    Generates a SIP UPDATE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1nd(optional): contact identifier (contactID := 0)
//    - 2nd(optional): if 1, the Require:precondition header will be added to the request (precondition := 0)
//    - 3rd(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//    - *invalid dialog index in FSM context data*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC. Stores the UAC index in the
//    FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//    
//  Constants:
//    c_SIP_stepIdx_generateUPDATE - test step index
//    c_SIP_stepFunction_generateUPDATE - "SIPAppLib: StepFunction_generateUPDATE"
//
//  SIP message passed to call-back:
//(start example)
//
//    UPDATE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum UPDATE
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateUPDATE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateUPDATE(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateUPDATE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_dialog := -1;
  var integer vl_UAC := -1;

  vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;

  if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].userSessionAssociated)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }

  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_contactID);

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    UPDATE_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    REFRESH_DIALOG);

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID); 

  var integer vl_addPrecond := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_addPrecond);  
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 2, vl_disableExtTemplates);

  var charstring vl_extraHeaders := "";
  var OptionTag_List vl_optionsTags := {};
  f_EPTF_SIP_prepareOptionsTag(0, vl_addPrecond, vl_disableExtTemplates,
    vl_optionsTags ,vl_extraHeaders);

  if (sizeof(vl_optionsTags) > 0)
  {
    v_db_UAC.data[vl_UAC].request.msgHeader.require := {
      fieldName := REQUIRE_E,
      optionsTags := vl_optionsTags
    }

    if (vl_disableExtTemplates != -1) {
      vl_extraHeaders := "Require: " & vl_extraHeaders & "\r\n";
    }
  }

  if (vl_disableExtTemplates != -1)
  {  
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;   

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_UPDATE, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_UPDATE_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {
        "extraHeaders", vl_extraHeaders
      }

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createUPDATE
// 
//  Purpose:
//    Generates and sends a SIP UPDATE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1nd(optional): contact identifier (contactID := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgUPDATE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//    
//  Constants:
//    c_SIP_stepIdx_createUPDATE - test step index
//    c_SIP_stepFunction_createUPDATE - "SIPAppLib: StepFunction_createUPDATE"
//
//  SIP message passed to call-back:
//(start example)
//
//    UPDATE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum UPDATE
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createUPDATE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateUPDATE(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgUPDATE)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgUPDATE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }
  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleUPDATE
// 
//  Purpose:
//    Handles an incoming re-INVITE request. SHOULD BE called to handle the c_SIP_eventIdx_UPDATE 
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//    
//
//  Constants:
//    c_SIP_stepIdx_handleUPDATE - test step index
//    c_SIP_stepFunction_handleUPDATE - "SIPAppLib: StepFunction_handleUPDATE"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleUPDATE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession, 
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    v_currentDialog, 
    REFRESH_DIALOG);

  f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);

  if (ispresent(v_msgToProcess.request.msgHeader.contact) and
          ischosen(v_msgToProcess.request.msgHeader.contact.contactBody.contactAddresses))
  {
    var SipUrl vl_remoteTarget;
    var charstring vl_transport;

    f_EPTF_SIP_GetUri(v_msgToProcess.request.msgHeader.contact.contactBody.contactAddresses[0].addressField,
      vl_remoteTarget);

    if (f_EPTF_SIP_Transport_getTransportFromAddress(vl_remoteTarget, vl_transport)) 
    {
      v_db_users.data[v_currentUser].preferredTransport := 
        f_EPTF_SIP_MessageConvertToTransport(vl_transport);
    }

    f_EPTF_SIP_refreshTarget(v_currentDialog, vl_remoteTarget);
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateMESSAGE
// 
//  Purpose:
//    Creates and sends a SIP MESSAGE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//    - 2nd(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores in the UAC.
//    Stores the UAC index in the FSM context data.
//    The request is sent outside of dialog.
//    
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateMESSAGE - test step index
//    c_SIP_stepFunction_generateMESSAGE - "SIPAppLib: StepFunction_generateMESSAGE"
//
//  SIP message passed to call-back:
//(start example)
//
//    MESSAGE _SIP_User.calledUsers[calledUser].addr.addrSpecUnion_ SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx MESSAGE
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:SIP_User.calledUsers[calledUser]
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateMESSAGE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateMESSAGE(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateMESSAGE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;
  var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC,
    MESSAGE_E,
    v_db_users.data[v_currentUser].currentSession, 
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport,
    "");

  var CallidString vl_callId;

  f_EPTF_SIP_check4xxRetry(
    MESSAGE_E,
    v_currentUser,
    vl_FSMIdx,
    vl_callId,
    v_db_users.data[v_currentUser].cSeq
  );

  var integer  vl_calledUser:= 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_calledUser);

  var Addr_Union vl_to;
  f_EPTF_SIP_getCalledUser_addr(v_currentUser, vl_calledUser, vl_to);

  var SipUrl vl_requestUri;
  f_EPTF_SIP_GetUri(vl_to, vl_requestUri);

  var charstring vl_localTag;
  f_EPTF_SIP_genLocalTag(v_currentUser, vl_localTag);

  var Addr_Union vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, vl_idIdx, vl_from);

  var RouteBody_List vl_routeBody := {};
  f_EPTF_SIP_SIPRouteBodyList2Route(v_db_users.data[v_currentUser].route, vl_routeBody);

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    vl_requestUri, // Request-URI
    vl_callId, //Call-ID
    v_db_users.data[v_currentUser].cSeq, //CSeq
    vl_to, // To
    vl_from, // From
    vl_localTag,
    vl_routeBody); //local tag

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_templateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_templateSetIdx)
    {
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_MESSAGE, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_MESSAGE_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createMESSAGE
// 
//  Purpose:
//    Generates and sends a SIP MESSAGE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    The request is sent outside of dialog.
//    
//  Call-back function reference:
//    v_setMsgMESSAGE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createMESSAGE - test step index
//    c_SIP_stepFunction_createMESSAGE - "SIPAppLib: StepFunction_createMESSAGE"
//
//  SIP message passed to call-back:
//(start example)
//
//    MESSAGE _SIP_User.calledUsers[calledUser].addr.addrSpecUnion_ SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx MESSAGE
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:SIP_User.calledUsers[calledUser]
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createMESSAGE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateMESSAGE(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgMESSAGE)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgMESSAGE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}
///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleMESSAGE
// 
//  Purpose:
//    Handles an incoming MESSAGE request. SHOULD BE called to handle the c_SIP_eventIdx_MESSAGE
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleMESSAGE - test step index
//    c_SIP_stepFunction_handleMESSAGE - "SIPAppLib: StepFunction_handleMESSAGE"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleMESSAGE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  if (0 <= v_currentDialog)
  {
    f_EPTF_SIP_createNewUASinDialog(
      v_msgToProcess, 
      vl_UAS, 
      v_currentSession, 
      v_currentUser,
      vl_fsmCtx, 
      vl_FSMIdx, 
      v_currentDialog, 
      INSIDE_DIALOG);

    f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);
  }else{
    f_EPTF_SIP_createNewUAS(v_msgToProcess, vl_UAS, v_currentSession, v_currentUser, vl_fsmCtx, vl_FSMIdx);
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateCANCEL
// 
//  Purpose:
//    Creates and sends a SIP CANCEL message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid dialog index in FSM context data...*: the dialog stored in the FSM context data where this step
//        is invoked contains an invalid dialog index (not created, already destroyed, ...). The message 
//        will not be sent out.
//    - *invalid transaction or no INVITE transaction in FSM context dataa*: no transaction was found to cancel.
//        The message will not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC. Stores the UAC index in the
//    FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateCANCEL - test step index
//    c_SIP_stepFunction_generateCANCEL - "SIPAppLib: StepFunction_generateCANCEL"
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (i.e. for example by invoking the f_SIP_step_createINVITE test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    The message is created according to the rules and procedures defined in RFC3261 Section 9:
//
//    CANCEL from INVITE SIP/2.0
//    Call-ID: from INVITE
//    Content-Length:0
//    CSeq: from INVITE CANCEL
//    From: from INVITE
//    Max-Forwards:70
//    Route: from INVITE
//    To:from INVITE
//    Via:top Via value from INVITE
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateCANCEL(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateCANCEL(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateCANCEL(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;
  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_disableExtTemplates);  

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;
  var integer vl_UACtoCANCEL := -1;
  for (var integer i := 0; i < sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data); i := i + 1)
  {
    if (INVITE_E == v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].method and
          (v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].state == c_SIP_TrState_Calling or
            v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].state == c_SIP_TrState_Proceeding))
    {
      vl_UACtoCANCEL := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i];
      break;
    }
  }

  if (not f_EPTF_SIP_checkTransaction(v_db_UAC, vl_UACtoCANCEL))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid transaction or no INVITE transaction in FSM context data."));
    return false;
  }

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC,
    CANCEL_E,
    v_db_users.data[v_currentUser].currentSession, 
    v_currentUser, 
    vl_fsmCtx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport, 
    v_db_UAC.data[vl_UACtoCANCEL].transactionId);

  var RouteBody_List vl_routeBody := {};

  if (omit != v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.route)
  {
    vl_routeBody := v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.route.routeBody
  }

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    v_db_UAC.data[vl_UACtoCANCEL].request.requestLine.requestUri, // Request-URI
    v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.callId.callid, //Call-ID
    v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.cSeq.seqNumber, //CSeq
    v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.toField.addressField,//To
    v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.fromField.addressField, //From
    "",
    vl_routeBody); //local tag

  v_db_UAC.data[vl_UAC].request.msgHeader.toField.toParams := v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.toField.toParams;
  v_db_UAC.data[vl_UAC].request.msgHeader.fromField.fromParams := v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.fromField.fromParams;

  v_db_UAC.data[vl_UAC].request.msgHeader.via := {
    fieldName := VIA_E,
    viaBody := {v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.via.viaBody[0]}
  }

  v_db_UAC.data[vl_UAC].request.msgHeader.route := v_db_UAC.data[vl_UACtoCANCEL].request.msgHeader.route;

  if (vl_disableExtTemplates > -1)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_CANCEL, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_CANCEL_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createCANCEL
// 
//  Purpose:
//    Generates and sends a SIP CANCEL message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgCANCEL
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createCANCEL - test step index
//    c_SIP_stepFunction_createCANCEL - "SIPAppLib: StepFunction_createCANCEL"
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (i.e. for example by invoking the f_SIP_step_createINVITE test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    The message is created according to the rules and procedures defined in RFC3261 Section 9:
//
//    CANCEL from INVITE SIP/2.0
//    Call-ID: from INVITE
//    Content-Length:0
//    CSeq: from INVITE CANCEL
//    From: from INVITE
//    Max-Forwards:70
//    Route: from INVITE
//    To:from INVITE
//    Via:top Via value from INVITE
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createCANCEL(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateCANCEL(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  if (null != v_setMsgCANCEL)
  {
    var EPTF_IntegerList vl_params := {};
    f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
    v_setMsgCANCEL.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
  }

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleCANCEL
// 
//  Purpose:
//    Handles an incoming CANCEL request. SHOULD BE called to handle the c_SIP_eventIdx_CANCEL
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleCANCEL - test step index
//    c_SIP_stepFunction_handleCANCEL - "SIPAppLib: StepFunction_handleCANCEL"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleCANCEL(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }
  var integer vl_UAS := -1;

  f_EPTF_SIP_createNewUAS(v_msgToProcess, vl_UAS, v_currentSession,  v_currentUser, vl_fsmCtx, vl_FSMIdx);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateSUBSCRIBE
// 
//  Purpose:
//    Generates and sends a SIP SUBSCRIBE message outside of a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): contact identifier (contactID := 0)
//    - 2nd(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *invalid event type index in FSM context data*: invalid event type index in the FSM context data. The message
//        will not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC. Stores the UAC index in the
//    FSM context data.
//    Creates a dialog. The dialog index is stored in the FSM context data. *WARNING*: only one dialog index can be stored in the
//      FSM context data.
//    Creates a subscription. The subscription index is stored in the FSM context data. *WARNING*: only one subscription index
//      can be stored in the FSM context data.
//    Before invoking, the event type must be registered with the <f_EPTF_SIP_Subscription_AddSupportedEventType> function. The
//      regsitered events can be refered through indices returned by this function (event type index), and the event will be 
//      placed in the Event SIP header field.
//    
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateSUBSCRIBE - test step index
//    c_SIP_stepFunction_generateSUBSCRIBE - "SIPAppLib: StepFunction_generateSUBSCRIBE"
//
//  FSM context data:
//    An event type index must be added to the FSM context data by means of the <f_EPTF_SIP_setFSMData_subEventIdx> function.
//      The event type index is an index returned by <f_EPTF_SIP_Subscription_AddSupportedEventType> function.
//    The notifier URI data must be set by means of the <f_EPTF_SIP_setFSMData_notifierURI> 
//      function before invokation.
//    Optionally an event ID can be added to the FSM context data by means of the <f_EPTF_SIP_setFSMData_subEventId> function.
//      This event ID will be added to the SIP Event header and can be used to identify the
//      subscription in the dialog(see RFC3265 Section 7.2.1).
//
//  SIP message passed to call-back:
//(start example)
//
//    SUBSCRIBE SIP_FSMData.notifierURI.addr.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:xxxxxxxxxx SUBSCRIBE
//    Event:Event_type[;id=ID]
//    Expires:SIP_FSMData.subscriptionExpireTime
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:SIP_FSMData.notifierURI.addr
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
// note: used for create SUBSCRIBE
public function f_SIP_step_generateSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateSUBSCRIBE(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_eventTypeIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionEventIdx
  if (sizeof(v_db_subscription.supportedEventTypes) <= vl_eventTypeIdx or
        0 > vl_eventTypeIdx)
  {
    f_SIP_Logging_WARNING(%definitionId&": invalid event type index in FSM context data: " & int2str(vl_eventTypeIdx));
    return false;
  }

  var integer vl_UAC := -1;
  var integer vl_dialog := -1;
  var integer vl_subscription := -1;

  var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;
  var charstring vl_id := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].eventId;

  var Addr_Union addr;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, vl_idIdx, addr);

  var Addr_Union notifierURI;
  if(ispresent(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].notifierURI)) {
    f_EPTF_SIP_FlatSipUrl2AddrUnion(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].notifierURI, notifierURI);
  } else {
    notifierURI := {addrSpecUnion := cg_SipUrl_base};
  }

  f_EPTF_SIP_CreateOutgoingDialog(
    vl_dialog,
    v_currentUser,
    vl_FSMIdx,
    addr,
    notifierURI,
    SUBSCRIBE_E
    );

  f_EPTF_SIP_check4xxRetryInDialog(SUBSCRIBE_E, v_currentUser, vl_dialog, vl_FSMIdx);

  f_EPTF_SIP_CreateSubscription(
    vl_subscription,
    vl_dialog,
    vl_FSMIdx,
    vl_eventTypeIdx,
    vl_id,
    v_db_dialog.data[vl_dialog].callId,
    v_db_dialog.data[vl_dialog].localTag,
    v_db_dialog.data[vl_dialog].remoteTag
    );

  v_db_subscription.data[vl_subscription].expireInterval := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionExpireTime;

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    SUBSCRIBE_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    pl_ptr.refContext.fCtxIdx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    CREATE_DIALOG);

  v_db_UAC.data[vl_UAC].subscriptionIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionIdx;

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  f_EPTF_SIP_addSUBSCRIBEHeaders(
    vl_subscription, 
    v_db_UAC.data[vl_UAC].request.msgHeader);

  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_contactID);

  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID);
  //hack, store contact ID for bacward compatibility
  if (0 != vl_contactID)
  {
    v_db_users.data[v_currentUser].regData.contactId := vl_contactID;
  }

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_extTemplateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTemplateSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_initSUBSCRIBE, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_initSUBSCRIBE_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {"expires", int2str(v_db_subscription.data[vl_subscription].expireInterval)};

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createSUBSCRIBE
// 
//  Purpose:
//    Creates and sends a SIP SUBSCRIBE message outside of a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): contact identifier (contactID := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Before invoking, the event type must be registered with the <f_EPTF_SIP_Subscription_AddSupportedEventType> function. The
//      regsitered events can be refered through indices returned by this function (event type index), and the event will be 
//      placed in the Event SIP header field.
//    
//  Call-back function reference:
//    v_setMsgSUBSCRIBE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createSUBSCRIBE - test step index
//    c_SIP_stepFunction_createSUBSCRIBE - "SIPAppLib: StepFunction_createSUBSCRIBE"
//
//
//  FSM context data:
//    An event type index must be added to the FSM context data by means of the <f_EPTF_SIP_setFSMData_subEventIdx> function.
//      The event type index is an index returned by <f_EPTF_SIP_Subscription_AddSupportedEventType> function.
//    The notifier URI data must be set by means of the <f_EPTF_SIP_setFSMData_notifierURI> 
//      function before invokation.
//    Optionally an event ID can be added to the FSM context data by means of the <f_EPTF_SIP_setFSMData_subEventId> function.
//      This event ID will be added to the SIP Event header and can be used to identify the
//      subscription in the dialog(see RFC3265 Section 7.2.1).
//
//  SIP message passed to call-back:
//(start example)
//
//    SUBSCRIBE SIP_FSMData.notifierURI.addr.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:xxxxxxxxxx SUBSCRIBE
//    Event:Event_type[;id=ID]
//    Expires:SIP_FSMData.subscriptionExpireTime
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:SIP_FSMData.notifierURI.addr
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateSUBSCRIBE(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgSUBSCRIBE)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgSUBSCRIBE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleSUBSCRIBE
// 
//  Purpose:
//    Handles an incoming SUBSCRIBE request inside or outside of a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *could not start dialog watchdog timer*: each time a dialog is created a
//        watchdog timer is started, and the dialog is deleted on timeout. The error message means that the
//        timer could not be started
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS and a new dialog if necessary. The UAS and the index of the new dialog is stored in the FSM context data.
//    Creates a new subscription if needed. The index of the subscription is stored in the FSM context data.
//    
//
//  Constants:
//    c_SIP_stepIdx_handleSUBSCRIBE - test step index
//    c_SIP_stepFunction_handleSUBSCRIBE- "SIPAppLib: StepFunction_handleSUBSCRIBE"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;
  var integer vl_dialog := v_currentDialog;
  var integer vl_subscription := -1;
  var SIP_TransactionInDialog vl_trInDialog := INSIDE_DIALOG;

  var integer vl_eventTypeIdx := -1;
  if(not ispresent(v_msgToProcess.request.msgHeader.event)) {
    f_SIP_Logging_WARNING(%definitionId & ": Event header is missing in incoming SUBSCRIBE message.");
    return;
  }
  for(var integer i:=0; i<sizeof(v_db_subscription.supportedEventTypes); i:=i+1) {
    if(v_db_subscription.supportedEventTypes[i].event_package ==
      v_msgToProcess.request.msgHeader.event.event_type.event_package) {
      vl_eventTypeIdx := i;
      break;
    }
  }
  if(vl_eventTypeIdx < 0) {
    f_SIP_Logging_WARNING(%definitionId&": event type " &
      v_msgToProcess.request.msgHeader.event.event_type.event_package &
      " in incoming SUBSCRIBE is added automatically to supported event types.");
    vl_eventTypeIdx := f_EPTF_SIP_Subscription_AddSupportedEventType(v_msgToProcess.request.msgHeader.event.event_type);
  }
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionEventIdx := vl_eventTypeIdx;

  var charstring vl_id := "";
  if (ispresent(v_msgToProcess.request.msgHeader.event.event_params))
  {
    f_EPTF_SIP_GetParameter(v_msgToProcess.request.msgHeader.event.event_params, c_SIP_ID_ID, vl_id);
  }
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].eventId := vl_id;

  if (0 > vl_dialog)
  {  
    f_EPTF_SIP_CreateIncomingDialog(v_msgToProcess.request, vl_dialog, v_currentUser, vl_FSMIdx);
    vl_trInDialog := CREATE_DIALOG;

    f_EPTF_SIP_CreateSubscription(
      vl_subscription,
      vl_dialog,
      vl_FSMIdx,
      vl_eventTypeIdx,
      vl_id,
      v_db_dialog.data[vl_dialog].callId,
      v_db_dialog.data[vl_dialog].localTag,
      v_db_dialog.data[vl_dialog].remoteTag
      );
  } else {
    vl_subscription := v_db_dialog.data[vl_dialog].subscriptionIdx;

    // set this here in order the re-SUBSCRIBE to work the same as on initial SUBSCRIBE
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx := vl_dialog;

    f_EPTF_SIP_handleRequestInDialog(vl_dialog, v_msgToProcess.request);
  }

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession, 
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    vl_dialog, 
    vl_trInDialog);

  v_db_UAS.data[vl_UAS].subscriptionIdx := vl_subscription;
}

// note: used for refresh/remove SUBSCRIBE
private function f_SIP_generateSUBSCRIBE(
  in EPTF_LGenBase_TestStepArgs pl_ptr,
  in integer pl_type)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_subscription := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionIdx;

  if (not f_EPTF_SIP_checkSubscription(vl_subscription))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid subscription index in FSM context data."));
    return false;
  }

  var integer vl_UAC := -1;
  var integer vl_dialog := v_db_subscription.data[vl_subscription].dialogIdx;

  if (not f_EPTF_SIP_checkDialogInSubscription(vl_dialog, vl_subscription))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in subscription data."));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user(",v_currentUser,")"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current subscription(",vl_subscription,")"));
    return false;
  }


  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    SUBSCRIBE_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    pl_ptr.refContext.fCtxIdx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    INSIDE_DIALOG);

  v_db_UAC.data[vl_UAC].subscriptionIdx := vl_subscription;

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  if (c_SIP_doRemove == pl_type)
  {
    v_db_subscription.data[vl_subscription].expireInterval := 0;
  }

  f_EPTF_SIP_addSUBSCRIBEHeaders(
    vl_subscription, 
    v_db_UAC.data[vl_UAC].request.msgHeader );
  
  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_contactID); 
   
  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID);
  
  //hack, store contact ID for bacward compatibility
  if (0 != vl_contactID)
  {
    v_db_users.data[v_currentUser].regData.contactId := vl_contactID;
  }

  var integer vl_extTemplateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
  var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

  if (0 <= vl_extTemplateSetIdx)
  {
    f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_refreshSUBSCRIBE, vl_templateHeaderIdx);
    f_SIP_useExtTemplate(vl_extTemplateSetIdx, v_templateTypeIdx_refreshSUBSCRIBE_BODY, vl_templateBodyIdx);
  }

  if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
  {
    f_EPTF_SIP_CreateNewRequestDictionary(
      vl_UAC,
      v_db_UAC.data[vl_UAC].templateParams);

    v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {"expires", int2str(v_db_subscription.data[vl_subscription].expireInterval)};
    v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
    v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
  }

  return true;
}


// note: used for refresh/remove SUBSCRIBE
private function f_SIP_SUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr, in integer pl_type)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_generateSUBSCRIBE(pl_ptr, pl_type)) { return; } // HN78478

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    var fcb_EPTF_SIP_setRequest vl_fn := null;

    if (c_SIP_doRefresh == pl_type)
    {
      vl_fn := v_setMsgRefreshSUBSCRIBE;
    }else if (c_SIP_doRemove == pl_type)
    {
      vl_fn := v_setMsgRemoveSUBSCRIBE;
    }

    if (null != vl_fn)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      vl_fn.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_refreshSUBSCRIBE, f_SIP_step_removeSUBSCRIBE
// 
//  Purpose:
//    Generates and sends a SIP SUBSCRIBE refresh/remove message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid subscription index in FSM context data*: invalid subscription index in the FSM context data. The message will
//        not be sent out.
//    - *invalid dialog index in subscription data*: invalid dialog index in the subscription context data. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC, then sends the message. Stores the UAC index in the
//    FSM context data.
//
//  Call-back function reference:
//    v_setMsgRefreshSUBSCRIBE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_refreshSUBSCRIBE - test step index
//    c_SIP_stepFunction_refreshSUBSCRIBE - "SIPAppLib: StepFunction_refreshSUBSCRIBE"
//
//    c_SIP_stepIdx_removeSUBSCRIBE - test step index
//    c_SIP_stepFunction_removeSUBSCRIBE - "SIPAppLib: StepFunction_removeSUBSCRIBE"
//
//  FSM context data:
//    A subscription must be created and the index must be stored in the FSM context data.
//      (for example by invoking the f_SIP_step_createSUBSCRIBE test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    SUBSCRIBE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum SUBSCRIBE
//    Event:SIP_SubscriptionData.eventType.event_type[;id=SIP_SubscriptionData.eventType.id]
//    Expires:SIP_SubscriptionData.expireInterval | Expires:0
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_refreshSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_SUBSCRIBE(pl_ptr, c_SIP_doRefresh);
}

public function f_SIP_step_removeSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_SUBSCRIBE(pl_ptr, c_SIP_doRemove);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateRefreshSUBSCRIBE, f_SIP_step_generateRemoveSUBSCRIBE
// 
//  Purpose:
//    Generates a SIP SUBSCRIBE refresh/remove message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid subscription index in FSM context data*: invalid subscription index in the FSM context data. The message will
//        not be sent out.
//    - *invalid dialog index in subscription data*: invalid dialog index in the subscription context data. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC.
//    Stores the UAC index in the FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateRefreshSUBSCRIBE - test step index
//    c_SIP_stepFunction_generateRefreshSUBSCRIBE - "SIPAppLib: StepFunction_generateRefreshSUBSCRIBE"
//
//    c_SIP_stepIdx_generateRemoveSUBSCRIBE - test step index
//    c_SIP_stepFunction_generateRemoveSUBSCRIBE - "SIPAppLib: StepFunction_generateRemoveSUBSCRIBE"
//
//  FSM context data:
//    A subscription must be created and the index must be stored in the FSM context data.
//      (for example by invoking the f_SIP_step_createSUBSCRIBE test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    SUBSCRIBE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum SUBSCRIBE
//    Event:SIP_SubscriptionData.eventType.event_type[;id=SIP_SubscriptionData.eventType.id]
//    Expires:SIP_SubscriptionData.expireInterval | Expires:0
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateRefreshSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_generateSUBSCRIBE(pl_ptr, c_SIP_doRefresh)) { /*remove warning about unused return value*/ }
}

public function f_SIP_step_generateRemoveSUBSCRIBE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_generateSUBSCRIBE(pl_ptr, c_SIP_doRemove)) { /*remove warning about unused return value*/ }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateREFER
// 
//  Purpose:
//    Generates a SIP REFER message outside of a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): contact identifier (contactID := 0)
//
//  Errors:
//    - *could not start dialog watchdog timer*: each time a dialog is created a
//        watchdog timer is started, and the dialog is deleted on timeout. The error message means that the
//        timer could not be started
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC. Stores the UAC index in the
//    FSM context data.
//    Creates a dialog. The dialog index is stored in the FSM context data. *WARNING*: only one dialog index can be stored in the
//      FSM context data.
//    Creates a subscription. The subscription index is stored in the FSM context data. *WARNING*: only one subscription index
//      can be stored in the FSM context data.
//
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateREFER - test step index
//    c_SIP_stepFunction_generateREFER - "SIPAppLib: StepFunction_generateREFER"
//
//  FSM context data:
//    The notifier URI and the refer-to URI data must be set by means of the 
//    <f_EPTF_SIP_setFSMData_notifierURI> and <f_EPTF_SIP_setFSMData_referToURI> functions before invokation.
//
//  SIP message passed to call-back:
//(start example)
//
//    REFER SIP_FSMData.notifierURI.addr.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:xxxxxxxxxx REFER
//    Expires:SIP_SubscriptionData.expireInterval
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    Refer-to:SIP_FSMData.referToURI.addr
//    To:SIP_FSMData.notifierURI.addr
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateREFER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateREFER(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateREFER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;
  var integer vl_dialog := -1;

  var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;

  var integer vl_subscription := -1;

  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_contactID);

  var Addr_Union addr;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, vl_idIdx, addr);

  var Addr_Union notifierURI;
  if(ispresent(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].notifierURI)) {
    f_EPTF_SIP_FlatSipUrl2AddrUnion(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].notifierURI, notifierURI);
  } else {
    notifierURI := {addrSpecUnion := cg_SipUrl_base};
  }

  f_EPTF_SIP_CreateOutgoingDialog(
    vl_dialog,
    v_currentUser,
    vl_FSMIdx,
    addr,
    notifierURI,
    REFER_E
    );

  f_EPTF_SIP_check4xxRetryInDialog(REFER_E, v_currentUser, vl_dialog, vl_FSMIdx);

  f_EPTF_SIP_CreateSubscription(
    vl_subscription,
    vl_dialog,
    vl_FSMIdx,
    v_eventType_refer,
    "",
    v_db_dialog.data[vl_dialog].callId,
    v_db_dialog.data[vl_dialog].localTag,
    v_db_dialog.data[vl_dialog].remoteTag
    );

   v_db_subscription.data[vl_subscription].expireInterval := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionExpireTime;

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    REFER_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    CREATE_DIALOG);

  v_db_UAC.data[vl_UAC].subscriptionIdx := vl_subscription;

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  f_EPTF_SIP_addREFERHeaders(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request.msgHeader);

  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID);

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates > -1)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_REFER, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_REFER_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createREFER
// 
//  Purpose:
//    Generates and sends a SIP REFER message outside of a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): contact identifier (contactID := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgREFER
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createREFER - test step index
//    c_SIP_stepFunction_createREFER - "SIPAppLib: StepFunction_createREFER"
//
//  FSM context data:
//    The notifier URI and the refer-to URI data must be set by means of the 
//    <f_EPTF_SIP_setFSMData_notifierURI> and <f_EPTF_SIP_setFSMData_referToURI> functions before invokation.
//
//  SIP message passed to call-back:
//(start example)
//
//    REFER SIP_FSMData.notifierURI.addr.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Contact:SIP_User.iD[contactID].addr
//    Content-Length:0
//    CSeq:xxxxxxxxxx REFER
//    Expires:SIP_SubscriptionData.expireInterval
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    Refer-to:SIP_FSMData.referToURI.addr
//    To:SIP_FSMData.notifierURI.addr
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createREFER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateREFER(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  if (null != v_setMsgREFER)
  {
    var EPTF_IntegerList vl_params := {};
    f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
    v_setMsgREFER.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
  }

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateREFERinDialog
// 
//  Purpose:
//    Generates a SIP REFER message inside a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//    - *invalid dialog index in FSM context data...*: the dialog stored in the FSM context data where this step
//        is invoked contains an invalid dialog index (not created, already destroyed, ...). The message 
//        will not be sent out.
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC. Stores the UAC index in the
//    FSM context data.
//    Creates a subscription. The subscription index is stored in the FSM context data. *WARNING*: only one subscription index
//      can be stored in the FSM context data.
//
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateREFERinDialog - test step index
//    c_SIP_stepFunction_generateREFERinDialog - "SIPAppLib: StepFunction_generateREFERinDialog"
//
//  FSM context data:
//    The refer-to URI data must be set by means of the 
//    <f_EPTF_SIP_setFSMData_referToURI> function before invokation.
//
//  SIP message passed to call-back:
//(start example)
//
//    REFER SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum REFER
//    Expires:SIP_SubscriptionData.expireInterval
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    Refer-to:SIP_FSMData.referToURI.addr
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateREFERinDialog(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateREFERinDialog(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateREFERinDialog(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;

  var integer vl_subscription := -1;

  var integer vl_dialog := -1;
  vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;

  if (not f_EPTF_SIP_checkDialog(vl_dialog))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }

  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_contactID);

  f_EPTF_SIP_CreateSubscription(
    vl_subscription,
    vl_dialog,
    vl_FSMIdx,
    v_eventType_refer,
    "",
    v_db_dialog.data[vl_dialog].callId,
    v_db_dialog.data[vl_dialog].localTag,
    v_db_dialog.data[vl_dialog].remoteTag
    );

  v_db_subscription.data[vl_subscription].expireInterval := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionExpireTime;

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    REFER_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    INSIDE_DIALOG);

  v_db_UAC.data[vl_UAC].subscriptionIdx := vl_subscription;

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  f_EPTF_SIP_addREFERHeaders(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request.msgHeader);

  f_EPTF_SIP_addContact(v_currentUser, v_db_UAC.data[vl_UAC].request.msgHeader, vl_contactID);

  v_db_UAC.data[vl_UAC].templateBodyIdx := -1;
  v_db_UAC.data[vl_UAC].templateHeaderIdx := -1;

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createREFERinDialog
// 
//  Purpose:
//    Creates and sends a SIP REFER message inside a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//    - *invalid dialog index in FSM context data...*: the dialog stored in the FSM context data where this step
//        is invoked contains an invalid dialog index (not created, already destroyed, ...). The message 
//        will not be sent out.
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC, then sends the message. Stores the UAC index in the
//    FSM context data.
//    Creates a subscription. The subscription index is stored in the FSM context data. *WARNING*: only one subscription index
//      can be stored in the FSM context data.
//
//  Call-back function reference:
//    v_setMsgREFERinDialog
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createREFERinDialog - test step index
//    c_SIP_stepFunction_createREFERinDialog - "SIPAppLib: StepFunction_createREFERinDialog"
//
//  FSM context data:
//    The refer-to URI data must be set by means of the 
//    <f_EPTF_SIP_setFSMData_referToURI> function before invokation.
//
//  SIP message passed to call-back:
//(start example)
//
//    REFER SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum REFER
//    Expires:SIP_SubscriptionData.expireInterval
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    Refer-to:SIP_FSMData.referToURI.addr
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createREFERinDialog(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateREFERinDialog(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  if (null != v_setMsgREFERinDialog)
  {
    var EPTF_IntegerList vl_params := {};
    f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
    v_setMsgREFERinDialog.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
  }

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleREFER
// 
//  Purpose:
//    Handles an incoming REFER request inside or outside of a dialog.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *could not start dialog watchdog timer*: each time a dialog is created a
//        watchdog timer is started, and the dialog is deleted on timeout. The error message means that the
//        timer could not be started
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS and a new dialog if necessary. The UAS and the index of the new dialog is stored in the FSM context data.
//    Creates a new subscription. The index of the subscription is stored in the FSM context data.
//    
//
//  Constants:
//    c_SIP_stepIdx_handleREFER - test step index
//    c_SIP_stepFunction_handleREFER- "SIPAppLib: StepFunction_handleREFER"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleREFER(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;
  var integer vl_dialog := v_currentDialog;
  var integer vl_subscription := -1;
  var SIP_TransactionInDialog vl_trInDialog := INSIDE_DIALOG;

  if (0 > vl_dialog)
  {  
    f_EPTF_SIP_CreateIncomingDialog(v_msgToProcess.request, vl_dialog, v_currentUser, vl_FSMIdx);
    vl_trInDialog := CREATE_DIALOG;
  }

  if (CREATE_DIALOG == vl_trInDialog)
  {
    f_EPTF_SIP_CreateSubscription(
      vl_subscription,
      vl_dialog,
      vl_FSMIdx,
      v_eventType_refer,
      int2str(v_msgToProcess.request.msgHeader.cSeq.seqNumber),//ID
      v_db_dialog.data[vl_dialog].callId,
      v_db_dialog.data[vl_dialog].localTag,
      v_db_dialog.data[vl_dialog].remoteTag
      );
  }else{
    vl_subscription := v_db_dialog.data[vl_dialog].subscriptionIdx;

    f_EPTF_SIP_handleRequestInDialog(vl_dialog, v_msgToProcess.request);
  }


  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession, 
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    vl_dialog, 
    vl_trInDialog);

  v_db_UAS.data[vl_UAS].subscriptionIdx := vl_subscription;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generatePUBLISH
// 
//  Purpose:
//    Generates a SIP PUBLISH message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//    - 2nd(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC. Stores the UAC index in the
//    FSM context data.
//    Creates a publication. The publication index is stored in the FSM context data. *WARNING*: only one publish index
//      can be stored in the FSM context data.
//    The entity tag sent back by the EPA is stored by the SIP AppLib.
//    Sets SIP_PublishData.escURI.
//    Before invoking, the event type must be registered with the <f_EPTF_SIP_Publish_AddSupportedEventType> function. The
//      regsitered events can be refered through indices returned by this function (event type index), and the event will be 
//      placed in the Event SIP header field.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generatePUBLISH - test step index
//    c_SIP_stepFunction_generatePUBLISH - "SIPAppLib: StepFunction_generatePUBLISH"
//
//  FSM context data:
//    Before invoking the test step an event type index must be added to the FSM context data by means of the
//      <f_EPTF_SIP_setFSMData_publishEventIdx>. The event type index is an index returned by
//      <f_EPTF_SIP_Publish_AddSupportedEventType>.
//
//  SIP message passed to call-back:
//(start example)
//    if (calledUser>=0)
//      Request-URI = SIP_User.calledUsers[calledUser].addr.addrSpecUnion
//      ToField = SIP_User.calledUsers[calledUser].addr
//    else
//      Request-URI = SIP_User.iD[SIP_User.regData.currentID].addr.addrSpecUnion
//      ToField = SIP_User.iD[SIP_User.regData.currentID].addr
//
//
//    PUBLISH Request-URI SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx PUBLISH
//    Event:SIP_PublishData.eventType
//    Expires:SIP_PublishData.expireInterval
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:ToField
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generatePUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generatePUBLISH(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generatePUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_eventTypeIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].publishEventIdx;
  if (sizeof(v_db_publish.supportedEventTypes) <= vl_eventTypeIdx or
    0 > vl_eventTypeIdx)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid event type index in FSM context data."));
    return false;
  }

  var integer vl_UAC := -1;
  var integer vl_publish := -1;
  var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;

  var integer  vl_calledUser:= -1;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_calledUser);

  var AddrIndex vl_toIdx;
  var Addr_Union vl_to, vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, vl_idIdx, vl_from);

  if (0 <= vl_calledUser)
  {
    vl_toIdx := {calledUser := vl_calledUser};
    f_EPTF_SIP_getCalledUser_addr(v_currentUser, vl_calledUser, vl_to);
  }else{
    vl_toIdx := {userId := vl_idIdx};
    vl_to := vl_from;
  }

  f_EPTF_SIP_CreatePublish(
    vl_publish, 
    vl_eventTypeIdx, 
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    vl_toIdx);

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC,
    PUBLISH_E, 
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport, 
    "");

  var charstring vl_callId;

  f_EPTF_SIP_check4xxRetry(
    PUBLISH_E,
    v_currentUser,
    vl_FSMIdx,
    vl_callId,
    v_db_users.data[v_currentUser].cSeq
  );

  v_db_UAC.data[vl_UAC].publishIdx := vl_publish;

  v_db_publish.data[vl_publish].expireInterval := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].publishExpireTime;

  var SipUrl vl_requestURI;
  f_EPTF_SIP_GetUri(vl_to, vl_requestURI);

  var charstring vl_localTag;
  f_EPTF_SIP_genLocalTag(v_currentUser, vl_localTag);

  var RouteBody_List vl_routeBody := {};
  f_EPTF_SIP_SIPRouteBodyList2Route(v_db_users.data[v_currentUser].route, vl_routeBody);

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    vl_requestURI, // Request-URI
    vl_callId, //Call-ID
    v_db_users.data[v_currentUser].cSeq, //CSeq
    vl_to,//To
    vl_from, // From
    vl_localTag,
    vl_routeBody); //local tag

  f_EPTF_SIP_addPUBLISHHeadersINIT(
    vl_publish, 
    v_db_UAC.data[vl_UAC].request.msgHeader);

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_templateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_templateSetIdx)
    {
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_initPUBLISH, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_initPUBLISH_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {"expires", int2str(v_db_publish.data[vl_publish].expireInterval)};

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createPUBLISH
// 
//  Purpose:
//    Generates and sends a SIP PUBLISH message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    The entity tag sent back by the EPA is stored by the SIP AppLib.
//    Sets SIP_PublishData.escURI.
//    Before invoking, the event type must be registered with the <f_EPTF_SIP_Publish_AddSupportedEventType> function. The
//      regsitered events can be refered through indices returned by this function (event type index), and the event will be 
//      placed in the Event SIP header field.
//
//  Call-back function reference:
//    v_setMsgPUBLISH
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createPUBLISH - test step index
//    c_SIP_stepFunction_createPUBLISH - "SIPAppLib: StepFunction_createPUBLISH"
//
//  FSM context data:
//    Before invoking the test step an event type index must be added to the FSM context data by means of the
//      <f_EPTF_SIP_setFSMData_publishEventIdx>. The event type index is an index returned by
//      <f_EPTF_SIP_Publish_AddSupportedEventType>.
//
//  SIP message passed to call-back:
//(start example)
//    if (calledUser>=0)
//      Request-URI = SIP_User.calledUsers[calledUser].addr.addrSpecUnion
//      ToField = SIP_User.calledUsers[calledUser].addr
//    else
//      Request-URI = SIP_User.iD[SIP_User.regData.currentID].addr.addrSpecUnion
//      ToField = SIP_User.iD[SIP_User.regData.currentID].addr
//
//
//    PUBLISH Request-URI SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx PUBLISH
//    Event:SIP_PublishData.eventType
//    Expires:SIP_PublishData.expireInterval
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:ToField
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createPUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generatePUBLISH(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgPUBLISH)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgPUBLISH.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handlePUBLISH
// 
//  Purpose:
//    Handles an incoming PUBLISH request. SHOULD BE called to handle the c_SIP_eventIdx_PUBLISH
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//    - *Event header is missing...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the FSM context data.
//    Creates a publication. The publication index is stored in the FSM context data.
//      *WARNING*: only one publish index can be stored in the FSM context data.
//    If entity tag is received within the PUBLISH message it is stored by the SIP AppLib. SIP_PublishData.eTag
//    Sets SIP_PublishData.escURI.
//
//  Constants:
//    c_SIP_stepIdx_handlePUBLISH - test step index
//    c_SIP_stepFunction_handlePUBLISH- "SIPAppLib: StepFunction_handlePUBLISH"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handlePUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  var integer vl_eventTypeIdx := -1;
  if(not ispresent(v_msgToProcess.request.msgHeader.event)) {
    f_SIP_Logging_WARNING(%definitionId & ": Event header is missing in incoming PUBLISH message.");
    return;
  }
  for(var integer i:=0; i<sizeof(v_db_publish.supportedEventTypes); i:=i+1) {
    if(v_db_publish.supportedEventTypes[i].event_package ==
      v_msgToProcess.request.msgHeader.event.event_type.event_package) {
      vl_eventTypeIdx := i;
      break;
    }
  }
  if(vl_eventTypeIdx < 0) {
    f_SIP_Logging_WARNING(%definitionId&": event type " &
      v_msgToProcess.request.msgHeader.event.event_type.event_package &
      " in incoming PUBLISH is added automatically to supported event types.");
    vl_eventTypeIdx := f_EPTF_SIP_Publish_AddSupportedEventType(v_msgToProcess.request.msgHeader.event.event_type);
  }
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].publishEventIdx := vl_eventTypeIdx;

  var SipUrl vl_requestUri := v_msgToProcess.request.requestLine.requestUri;
  var charstring vl_requestUri_str := "";
  vl_requestUri.urlParameters := omit;
  vl_requestUri.headers := omit;
  f_EPTF_SIP_SIPUrl2str(vl_requestUri, vl_requestUri_str);
  var integer vl_published_idx := -1;
  f_EPTF_SIP_Findstr2int(
    v_db_published.hashRef,
    vl_requestUri_str,
    vl_published_idx);
  var integer vl_publish_idx := -1;
  var charstring vl_eTag := f_EPTF_SIP_Publish_generateETag();
  if(ispresent(v_msgToProcess.request.msgHeader.sip_If_Match))
  {
    if(-1 == vl_published_idx)
    {
      f_SIP_Logging_WARNING(%definitionId & ": test step was called with unknown Request-URI value.");
      return;
    }
    f_EPTF_SIP_Publish_getPublishIdxByIfMatch(
      vl_published_idx,
      v_msgToProcess.request.msgHeader.sip_If_Match.entity_tag,
      vl_publish_idx);

    if(-1 != vl_publish_idx)
    {
      if(ispresent(v_msgToProcess.request.msgHeader.expires) and
          0 == str2int(v_msgToProcess.request.msgHeader.expires.deltaSec))
      {
        f_EPTF_SIP_Publish_Remove(vl_publish_idx);
        f_EPTF_SIP_Publish_removePublishIdx(v_db_published.data[vl_published_idx].publishIdxList, vl_publish_idx);
        if(0 == sizeof(v_db_published.data[vl_published_idx].publishIdxList))
        {
          f_EPTF_str2int_HashMap_Erase(v_db_published.hashRef, vl_requestUri_str);
        }
      } else {
        if(ispresent(v_msgToProcess.request.msgHeader.expires))
        {
          v_db_publish.data[vl_publish_idx].expireInterval := str2int(v_msgToProcess.request.msgHeader.expires.deltaSec);
        }
        v_db_publish.data[vl_publish_idx].creationtime := f_EPTF_Base_getRelTimeInSecs();
        v_db_publish.data[vl_publish_idx].eTag := vl_eTag;
      }
    } else {
      f_SIP_Logging_WARNING(%definitionId & ": test step was called with unknown SIP-If-Match value.");
      return;
    }
  } else {
    var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;
    var AddrIndex vl_toIdx := {userId := vl_idIdx};
    f_EPTF_SIP_Publish_Create(
      vl_publish_idx,
      vl_eventTypeIdx, 
      v_currentUser, 
      pl_ptr.refContext.fCtxIdx, 
      vl_FSMIdx, 
      vl_toIdx);
    v_db_publish.data[vl_publish_idx].eTag := vl_eTag;
    if(ispresent(v_msgToProcess.request.msgHeader.expires))
    {
      v_db_publish.data[vl_publish_idx].expireInterval := str2int(v_msgToProcess.request.msgHeader.expires.deltaSec);
    }

    if(-1 == vl_published_idx)
    {
      f_EPTF_SIP_Publish_getNewIdx4Published(vl_published_idx);
      f_EPTF_str2int_HashMap_Insert(v_db_published.hashRef, vl_requestUri_str, vl_published_idx);
    }

    f_EPTF_SIP_Publish_addPublishIdx(v_db_published.data[vl_published_idx].publishIdxList, vl_publish_idx);
  }

  f_EPTF_SIP_createNewUAS(
    v_msgToProcess,
    vl_UAS,
    0,
    v_currentUser,
    pl_ptr.refContext.fCtxIdx,
    vl_FSMIdx);

  v_db_UAS.data[vl_UAS].response.msgHeader.sip_ETag := {
    fieldName := SIP_ETAG_E,
    entity_tag := vl_eTag
  }

  v_db_UAS.data[vl_UAS].publishIdx := vl_publish_idx;
}

private function f_SIP_generatePUBLISH(
  in EPTF_LGenBase_TestStepArgs pl_ptr,
  in integer pl_type)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_publish := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].publishIdx;

  if (not f_EPTF_SIP_checkPublish(vl_publish))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid publish index in FSM context data."));
    return;
  }

  var integer vl_UAC := -1;

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC, 
    PUBLISH_E, 
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport, 
    "");

  v_db_UAC.data[vl_UAC].publishIdx := vl_publish;

  var Addr_Union vl_to, vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.currentID, vl_from);

  if (ischosen(v_db_publish.data[vl_publish].escURI.calledUser))
  {
    f_EPTF_SIP_getCalledUser_addr(v_currentUser, v_db_publish.data[vl_publish].escURI.calledUser, vl_to);
  }else{
    f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_publish.data[vl_publish].escURI.userId, vl_to);
  }

  var SipUrl vl_requestURI;
  f_EPTF_SIP_GetUri(vl_to, vl_requestURI);

  var charstring vl_callId;
  f_EPTF_SIP_genCallId(v_currentUser,
    v_db_users.data[v_currentUser].localHost,
    vl_callId);

  var charstring vl_localTag;
  f_EPTF_SIP_genLocalTag(v_currentUser, vl_localTag);

  var RouteBody_List vl_routeBody := {};
  f_EPTF_SIP_SIPRouteBodyList2Route(v_db_users.data[v_currentUser].route, vl_routeBody);

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    vl_requestURI, // Request-URI
    vl_callId, //Call-ID
    f_EPTF_SIP_genCSeq(), //CSeq
    vl_to,//To
    vl_from, //From
    vl_localTag,
    vl_routeBody); //local tag

  if (c_SIP_doRemove == pl_type)
  {
    v_db_publish.data[vl_publish].expireInterval := 0;
  }

  f_EPTF_SIP_addPUBLISHHeadersSUB(
    vl_publish,
    v_db_UAC.data[vl_UAC].request.msgHeader);

  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_templateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_templateSetIdx)
    {
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_modifyPUBLISH, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_modifyPUBLISH_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {"eTag", v_db_publish.data[vl_publish].eTag};
      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {"expires", int2str(v_db_publish.data[vl_publish].expireInterval)};

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }
}

private function f_SIP_PUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr, in integer pl_type)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_generatePUBLISH(pl_ptr, pl_type);

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;

  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    var fcb_EPTF_SIP_setRequest vl_fn := null;

    if (c_SIP_doRefresh == pl_type)
    {
      vl_fn := v_setMsgRefreshPUBLISH;
    }else if (c_SIP_doModify == pl_type)
    {
      vl_fn := v_setMsgModifyPUBLISH;
    }else if (c_SIP_doRemove == pl_type)
    {
      vl_fn := v_setMsgRemovePUBLISH;
    }

    if (null != vl_fn)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      vl_fn.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_refreshPUBLISH, f_SIP_step_modifyPUBLISH, f_SIP_step_removePUBLISH
// 
//  Purpose:
//    Generates and sends a SIP refresh/modify/remove PUBLISH message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid publish index in FSM context data*: invalid publish index in the FSM context data.  The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgRefreshPUBLISH, v_setMsgModifyPUBLISH
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_refreshPUBLISH - test step index
//    c_SIP_stepFunction_refreshPUBLISH - "SIPAppLib: StepFunction_refreshPUBLISH"
//
//    c_SIP_stepIdx_modifyPUBLISH - test step index
//    c_SIP_stepFunction_modifyPUBLISH - "SIPAppLib: StepFunction_modifyPUBLISH"
//
//    c_SIP_stepIdx_removePUBLISH - test step index
//    c_SIP_stepFunction_removePUBLISH - "SIPAppLib: StepFunction_removePUBLISH"
//
//  FSM context data:
//    A publish index must be stored in the FSM context data before calling this test step
//      (for example by invoking the f_SIP_step_createPUBLISH test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    PUBLISH SIP_PublishData.escURI.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx PUBLISH
//    Expires:SIP_PublishData.expireInterval | Expires:0
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    SIP-If_Match:SIP_PublishData.eTag
//    To:SIP_PublishData.escURI
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_refreshPUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_PUBLISH(pl_ptr, c_SIP_doRefresh);
}

public function f_SIP_step_modifyPUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_PUBLISH(pl_ptr, c_SIP_doModify);
}

public function f_SIP_step_removePUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_PUBLISH(pl_ptr, c_SIP_doRemove);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateRefreshPUBLISH, f_SIP_step_generateModifyPUBLISH, f_SIP_step_generateRemovePUBLISH
// 
//  Purpose:
//    Generates a SIP refresh/modify/remove PUBLISH message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid publish index in FSM context data*: invalid publish index in the FSM context data.  The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateRefreshPUBLISH - test step index
//    c_SIP_stepFunction_generateRefreshPUBLISH - "SIPAppLib: StepFunction_generateRefreshPUBLISH"
//
//    c_SIP_stepIdx_generateModifyPUBLISH - test step index
//    c_SIP_stepFunction_generateModifyPUBLISH - "SIPAppLib: StepFunction_generateModifyPUBLISH"
//
//    c_SIP_stepIdx_generateRemovePUBLISH - test step index
//    c_SIP_stepFunction_generateRemovePUBLISH - "SIPAppLib: StepFunction_generateRemovePUBLISH"
//
//  FSM context data:
//    A publish index must be stored in the FSM context data before calling this test step
//      (for example by invoking the f_SIP_step_createPUBLISH test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    PUBLISH SIP_PublishData.escURI.addrSpecUnion SIP/2.0
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx PUBLISH
//    Expires:SIP_PublishData.expireInterval | Expires:0
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    SIP-If_Match:SIP_PublishData.eTag
//    To:SIP_PublishData.escURI
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateRefreshPUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_generatePUBLISH(pl_ptr, c_SIP_doRefresh);
}

public function f_SIP_step_generateModifyPUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_generatePUBLISH(pl_ptr, c_SIP_doModify);
}

public function f_SIP_step_generateRemovePUBLISH(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_generatePUBLISH(pl_ptr, c_SIP_doRemove);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateResponse
// 
//  Purpose:
//    Generates a response message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): status code (statusCode := 200)
//    - 2nd(optional): method (method := the method of the first UAS find in the FSM context data)
//    - 3rd(optional): contact identifier (contactId := 0)
//    - 4th(optional): if 1, the Require:100rel header and the RSeq: (seqNum) will be added to the response
//    - 5th(optional): if -1, external templates will be disabled in the request, otherwise the external template
//                     assigned to the provided index will be used to generate the response
//    - 6th(optional): if 1, the Require:precondition header will be added to the response (precondition := 0)
//
//  Errors:
//    - *no matching UAS in FSM context data*: no transaction was found in the FSM context data. The message will
//      not be sent out.
//    - *invalid dialog index in FSM context data*: invalid dialog index in the FSM context data. The message will
//        not be sent out.
//    - *could not start dialog timer for 2xx retransmission. 2xx will not be retransmitted*: in case of
//        sending a 2xx response to an INVITE request, timers for retransmitting the response is started.
//        The error message means that the timer could not be started, i.e. the 2xx response will not be
//        retransmitted.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates and sends a response to an UAS. The UAS is retrieved from the FSM context data. If the FSM
//    context contains more than one UAS, the UAS will be selected using the method test step parameter.
//    If more than one UAS with the same method is stored in the FSM context data, the first will be used.
//    A request handler test step MUST BE invoked before invoking this step.
//    
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyResponseCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateResponse - test step index
//    c_SIP_stepFunction_generateResponse - "SIPAppLib: StepFunction_generateResponse";
//
//  SIP message passed to call-back:
//
//    The message is created accroding to the rules and procedures defined the RFC containing
//    the request (general procedures: RFC3261 Section 8.2.6). For further details see
//    <f_EPTF_SIP_Message_CreateResponseFromUAS>
//
///////////////////////////////////////////////////////////
public function f_SIP_step_generateResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  // HN64135 - moved to a separate function with return value indicating fail/success
  // to be able to also use in createResponse without errors
  if(f_SIP_private_generateResponse(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_subscription := -1;
  var integer vl_dialog := -1;

  var integer vl_statusCodeIdx := c_status_200OK_idx;
  var integer vl_methodIdx := -1;
  var integer vl_contactID := v_db_users.data[v_currentUser].regData.contactId;
  var integer vl_forcePrack := 0;
  var integer vl_templateSelectorIdx := 0;
  var integer vl_addPrecond := 0;

  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_statusCodeIdx);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_methodIdx);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 2, vl_contactID);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 3, vl_forcePrack);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 4, vl_templateSelectorIdx);
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 5, vl_addPrecond);

  var Method vl_method := ACK_E;
  if (-1 < vl_methodIdx)
  {
    f_EPTF_SIP_IntToMethod(vl_methodIdx, vl_method)
  }

  var integer vl_statusCode := c_EPTF_SIP_StatusLines[vl_statusCodeIdx].statusCode;

  v_currentUAS := -1;
  if (ACK_E == vl_method)
  {
    for (var integer i := 0; i < sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data); i := i + 1)
    {
      if (c_SIP_TrState_Proceeding == v_db_UAS.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i]].state or
            c_SIP_TrState_Trying == v_db_UAS.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i]].state)
      {
        v_currentUAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i];
        break;
      }
    }
  }else{
    for (var integer i := 0; i < sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data); i := i + 1)
    {
      if (vl_method == v_db_UAS.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i]].method and 
            (c_SIP_TrState_Proceeding == v_db_UAS.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i]].state or
              c_SIP_TrState_Trying == v_db_UAS.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i]].state))
      {
        v_currentUAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i];
        break;
      }
    }
  }

  if (not f_EPTF_SIP_checkTransaction(v_db_UAS, v_currentUAS))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": no matching UAS in FSM context data."));
    return false;
  }

  vl_dialog := v_db_UAS.data[v_currentUAS].dialogIdx;
  vl_subscription := v_db_UAS.data[v_currentUAS].subscriptionIdx;

  if (OUTOF_DIALOG != v_db_UAS.data[v_currentUAS].trInDialog and 
        not f_EPTF_SIP_checkDialog(vl_dialog))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
    return false;
  }

  f_EPTF_SIP_Message_CreateResponseFromUAS(v_currentUAS, c_EPTF_SIP_StatusLines[vl_statusCodeIdx], vl_contactID);

  var float vl_retransmissionTime := 0.0;
  var float vl_maxRetransTime := 0.0;
  var float vl_retransTimeout := 0.0;

  if (vl_forcePrack > 0) // add 100rel
  {
    v_db_UAS.data[v_currentUAS].prack := true;
  } else {
    if(v_db_UAS.data[v_currentUAS].prack == true) { // if prack flag already set somewhere
      if(c_EPTF_Common_debugSwitch and f_SIP_Logging_debugEnabled()) {
        f_SIP_Logging_DEBUG(%definitionId&": Handle prack requires '100rel added', adding it");
      }
      vl_forcePrack := 1;
    }
  }

  // handle 100rel and precond option tags
  var charstring vl_extraHeaders := "";
  var OptionTag_List vl_optionsTags := {};
  f_EPTF_SIP_prepareOptionsTag(vl_forcePrack, vl_addPrecond, vl_templateSelectorIdx, vl_optionsTags , vl_extraHeaders);

  if (1 == vl_addPrecond and vl_forcePrack <= 0) // add precond options tag if not added together with 100rel
  {
    if (101 <= vl_statusCode and 199 >= vl_statusCode)
    {
      v_db_UAS.data[v_currentUAS].response.msgHeader.require := {
        fieldName := REQUIRE_E,
        optionsTags := vl_optionsTags
      }
    }

    if (-1 != vl_templateSelectorIdx) {
      vl_extraHeaders := "Require: " & vl_extraHeaders & "\r\n";
    }
  }

  if (v_db_UAS.data[v_currentUAS].prack) // handle prack required (100rel added)
  {
    if (101 <= vl_statusCode and 199 >= vl_statusCode)
    {
      v_db_UAS.data[v_currentUAS].response.msgHeader.require := {
        fieldName := REQUIRE_E,
        optionsTags := vl_optionsTags
      }

      if (-1 == v_db_UAS.data[v_currentUAS].currentRSeq)
      {
        v_db_UAS.data[v_currentUAS].currentRSeq := f_EPTF_SIP_genCSeq();
        if (0 == v_db_UAS.data[v_currentUAS].currentRSeq)
        {
          v_db_UAS.data[v_currentUAS].currentRSeq := 1;
        }
      }else{
        v_db_UAS.data[v_currentUAS].currentRSeq := f_EPTF_SIP_increaseCSeq(v_db_UAS.data[v_currentUAS].currentRSeq);
      }


      if (-1 != vl_templateSelectorIdx) {
        vl_extraHeaders := "Require: " & vl_extraHeaders & "\r\nRSeq: " & int2str(v_db_UAS.data[v_currentUAS].currentRSeq) & "\r\n";
      }

      v_db_UAS.data[v_currentUAS].unackRespData.rSeq := v_db_UAS.data[v_currentUAS].currentRSeq;
      v_db_UAS.data[v_currentUAS].unackRespData.seqNumber := v_db_UAS.data[v_currentUAS].response.msgHeader.cSeq.seqNumber;

      v_db_UAS.data[v_currentUAS].response.msgHeader.rseq := {
        fieldName := RSEQ_E,
        response_num := v_db_UAS.data[v_currentUAS].currentRSeq
      }

      vl_retransmissionTime := tsp_SIP_TUTimerValues[c_SIP_TimerTUProvisional_Retransmission];
      vl_maxRetransTime := tsp_SIP_TUTimerValues[c_SIP_TimerTUProvisional_MaxRetransmission];
      vl_retransTimeout := tsp_SIP_TUTimerValues[c_SIP_TimerTUProvisional_RetransTimeout];
    }else if (200 <= c_EPTF_SIP_StatusLines[vl_statusCodeIdx].statusCode and 699 >= c_EPTF_SIP_StatusLines[vl_statusCodeIdx].statusCode)
    {
      v_db_UAS.data[v_currentUAS].response.msgHeader.require := omit;
      v_db_UAS.data[v_currentUAS].response.msgHeader.rseq := omit;

      f_ETPF_SIP_CancelRetransmit(v_currentUser, vl_FSMIdx);
    }
  }

  if (OPTIONS_E == v_db_UAS.data[v_currentUAS].method)
  {
    if (200 == vl_statusCode)
    {
      if (0 < sizeof(v_db_UAs.uaData.acceptList))
      {
        v_db_UAS.data[v_currentUAS].response.msgHeader.accept :=
        {
          fieldName := ACCEPT_E,
          acceptArgs := v_db_UAs.uaData.acceptList
        }
      }

      if (0 < sizeof(v_db_UAs.uaData.allowedMethods))
      {
        v_db_UAS.data[v_currentUAS].response.msgHeader.allow :=
        {
          fieldName := ALLOW_E,
          methods := v_db_UAs.uaData.allowedMethods
        }
      }

      if (0 < sizeof(v_db_UAs.uaData.acceptEncodingList))
      {
        v_db_UAS.data[v_currentUAS].response.msgHeader.acceptEncoding :=
        {
          fieldName := ACCEPT_ENCODING_E,
          contentCoding := v_db_UAs.uaData.acceptEncodingList
        }
      }

      if (0 < sizeof(v_db_UAs.uaData.acceptLanguageList))
      {
        v_db_UAS.data[v_currentUAS].response.msgHeader.acceptLanguage :=
        {
          fieldName := ACCEPT_LANGUAGE_E,
          languageBody := v_db_UAs.uaData.acceptLanguageList
        }
      }

      if (0 < sizeof(v_db_UAs.uaData.supportedList))
      {
        v_db_UAS.data[v_currentUAS].response.msgHeader.supported :=
        {
          fieldName := SUPPORTED_E,
          optionsTags := v_db_UAs.uaData.supportedList
        }
      }
    }
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx := v_currentUAS;
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode := vl_statusCode;

  // External template handling 
  if (vl_templateSelectorIdx >= 0)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      if (vl_templateSelectorIdx >= tsp_EPTF_SIP_maxResponseTemplates) {
        f_SIP_Logging_WARNING(%definitionId & ": Template selector index (" & int2str(vl_templateSelectorIdx) & 
          ") exceeds its limit [0 .." & int2str(tsp_EPTF_SIP_maxResponseTemplates-1) & 
          "]. The default template (0) will be used instead.");
        vl_templateSelectorIdx       := 0;
      }

      if (sizeof(v_templateTypeIdx_Responses[vl_statusCode]) > 0) {
        f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_Responses[vl_statusCode][vl_templateSelectorIdx], 
          vl_templateHeaderIdx);
      }
      if (sizeof(v_templateTypeIdx_Responses_BODY[vl_statusCode]) > 0) {
        f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_Responses_BODY[vl_statusCode][vl_templateSelectorIdx], 
          vl_templateBodyIdx);
      }       
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewResponseDictionary(
        v_currentUAS,
        v_db_UAS.data[v_currentUAS].templateParams
      );

      v_db_UAS.data[v_currentUAS].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAS.data[v_currentUAS].templateHeaderIdx := vl_templateHeaderIdx;

      v_db_UAS.data[v_currentUAS].templateParams[sizeof(v_db_UAS.data[v_currentUAS].templateParams)] := {
        "extraHeaders", vl_extraHeaders
      }
    }
    else {
      v_db_UAS.data[v_currentUAS].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAS.data[v_currentUAS].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createResponse
// 
//  Purpose:
//    Generates and sends a response message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): status code (statusCode := 200)
//    - 2nd(optional): method (method := the method of the first UAS find in the FSM context data)
//    - 3rd(optional): contact identifier (contactId := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates and sends a response to an UAS. The UAS is retrieved from the FSM context data. If the FSM
//    context contains more than one UAS, the UAS will be selected using the method test step parameter.
//    If more than one UAS with the same method is stored in the FSM context data, the first will be used.
//    A request handler test step MUST BE invoked before invoking this step.
//    
//  Call-back function reference:
//    v_setMsgResponse
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UASIdx]: the UAS database index
//
//  Constants:
//    c_SIP_stepIdx_createResponse - test step index
//    c_SIP_stepFunction_createResponse - "SIPAppLib: StepFunction_createResponse";
//
//  SIP message passed to call-back:
//
//    The message is created accroding to the rules and procedures defined the RFC containing
//    the request (general procedures: RFC3261 Section 8.2.6). For further details see
//    <f_EPTF_SIP_Message_CreateResponseFromUAS>
//
///////////////////////////////////////////////////////////
public function f_SIP_step_createResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  // HN64135 - if generateResponse fails, v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx
  // would be left unchanged (-1 or some old value) and then used to index into v_db_UAS.data causing error
  if(not f_SIP_private_generateResponse(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAS.data[vl_UAS].templateBodyIdx)
  {    
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAS.data[vl_UAS].response.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthResponse(v_db_UAS.data[vl_UAS].response);
    }
  }

  if(0 > v_db_UAS.data[vl_UAS].templateHeaderIdx)
  {
    if (null != v_setMsgResponse)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UASIdx, vl_UAS);
      v_setMsgResponse.apply(v_db_UAS.data[vl_UAS].response, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetResponse(v_currentUser, vl_FSMIdx, v_db_UAS.data[vl_UAS].response, pl_ptr);
  }

  f_SIP_step_sendResponse(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateACK
// 
//  Purpose:
//    Generates an ACK request to an INVITE.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Test step parameters 
//    - 1st(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
// 
//  Errors:
//    - *invalid dialog index in FSM context data or ACK is not ready*: invalid dialog index in the FSM context data,
//        or the ACK could not be constructed. The message will not be sent out.
//    - *no INVITE UAC in FSM context data*: no transaction was found in the FSM context data. This message can
//        can occur during the send of ACK to a 3xxto6xx response. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//
//  Call-back function references:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  FSM context data:
//    Either a valid dialog index (2xx ACK) or an INVITE UAC index (non-2xx ACK) must be stored in the FSM context data
//    before calling this test step.
//
//  Constants:
//    c_SIP_stepIdx_generateACK - test step index
//    c_SIP_stepFunction_generateACK - "SIPAppLib: StepFunction_generateACK"
//
//  SIP message passed to call-back:
//    The message is created accroding to the rules and procedures defined in RFC3261 Section 17.1.1.3.
//
///////////////////////////////////////////////////////////
public function f_SIP_step_generateACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateACK(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }
  
  //trying to find an INVITE UAC
  var integer vl_UAC := -1;
  for (var integer i := 0; i < sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data) and vl_UAC == -1; i := i + 1)
  {
    if (INVITE_E == v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].method and
          (c_SIP_TrState_Proceeding == v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].state or
            c_SIP_TrState_Calling == v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].state) and
          v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].sendNACK)
    {
      vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i];
    }
  }

  // template handling
  var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
  var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

  if (0 <= vl_extTempSetIdx)
  {
    var integer vl_templateSelectorIdx := 0;

    f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_templateSelectorIdx);

    if (vl_templateSelectorIdx >= tsp_EPTF_SIP_maxRequestTemplates) {
      f_SIP_Logging_WARNING(%definitionId & ": Template selector index (" & int2str(vl_templateSelectorIdx) & 
        ") exceeds its limit [0 .." & int2str(tsp_EPTF_SIP_maxRequestTemplates-1) & 
        "]. The default template (0) will be used instead.");
      vl_templateSelectorIdx       := 0;
    }

    f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_ACK[vl_templateSelectorIdx], vl_templateHeaderIdx);
    f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_ACK_BODY[vl_templateSelectorIdx], vl_templateBodyIdx);
  }

  if (f_EPTF_SIP_checkTransaction(v_db_UAC, vl_UAC))
  {
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx := vl_UAC;
    v_db_UAC.data[vl_UAC].templateBodyIdx   := -1;
    v_db_UAC.data[vl_UAC].templateHeaderIdx := -1;
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := c_SIP_RequestType_ACKnotInDialog;

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }
  else{ //sending an ACK in the dialog
    var integer vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx; 

    if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].ACKData.ACKReady)
    {
      f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,"), or ACK is not ready"));
      f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
      return false;
    }
    v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData := c_SIP_ACK_Template_DB_init;

    if(not ispresent(v_db_dialog.data[vl_dialog].ACKData.ACK)) {
      v_db_dialog.data[vl_dialog].ACKData.ACK := cg_PDU_SIP_Request_base;
    }

    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := c_SIP_RequestType_ACKinDialog;

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionaryForACKInDialogue(
        v_currentUser, vl_FSMIdx,
        v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateParams
      );

      v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateBodyIdx   := vl_templateBodyIdx;
      v_db_dialog.data[vl_dialog].ACKData.ACKTemplateData.templateHeaderIdx := vl_templateHeaderIdx;
    }   
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createACK
// 
//  Purpose:
//    Generates  and Sends an ACK request to an INVITE.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//
//  Call-back function references:
//    v_setMsgACKto2xx, v_setMsgACKto3xxTo6xx
//
//  Call-back function parameter (v_setMsgACKto3xxTo6xx):
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the dialog database index
//    
//  FSM context data:
//    Either a valid dialog index (2xx ACK) or an INVITE UAC index (non-2xx ACK) must be stored in the FSM context data
//    before calling this test step.
//
//  Constants:
//    c_SIP_stepIdx_createACK - test step index
//    c_SIP_stepFunction_createACK - "SIPAppLib: StepFunction_createACK"
//
//  SIP message passed to call-back:
//    The message is created accroding to the rules and procedures defined in RFC3261 Section 17.1.1.3.
//
///////////////////////////////////////////////////////////
public function f_SIP_step_createACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateACK(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  if(c_SIP_RequestType_ACKnotInDialog == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType) {
    var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

    if (null != v_setMsgACKto3xxTo6xx)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgACKto3xxTo6xx.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  } else if(c_SIP_RequestType_ACKinDialog == v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType)
  {
    var integer vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx; 

    if (null != v_setMsgACKto2xx)
    {
      v_setMsgACKto2xx.apply(v_db_dialog.data[vl_dialog].ACKData.ACK, pl_ptr);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_dialog.data[vl_dialog].ACKData.ACK, pl_ptr);
  } 

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateBYE
// 
//  Purpose:
//    Generates a SIP BYE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Test step parameters 
//    - 1st(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
// 
//  Errors:
//    - *invalid dialog index in FSM context data*: invalid dialog index in the FSM context data. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC.
//    Stores the UAC index in the FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateBYE - test step index
//    c_SIP_stepFunction_generateBYE - "SIPAppLib: StepFunction_generateBYE"
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    BYE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum BYE
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateBYE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateBYE(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateBYE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_dialog := -1;
  var integer vl_UAC := -1;

  vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;

  if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].userSessionAssociated)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    BYE_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    REMOVE_DIALOG);

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);


  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_templateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_templateSetIdx)
    {
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_BYE, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_BYE_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createBYE
// 
//  Purpose:
//    Generates and sends a SIP BYE message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgBYE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the dialog database index
//
//  Constants:
//    c_SIP_stepIdx_createBYE - test step index
//    c_SIP_stepFunction_createBYE - "SIPAppLib: StepFunction_createBYE"
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//
//  SIP message passed to call-back:
//(start example)
//
//    BYE SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum BYE
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createBYE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateBYE(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgBYE)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgBYE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleBYE
// 
//  Purpose:
//    Handles an incoming BYE request. SHOULD BE called to handle the c_SIP_eventIdx_BYE 
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleBYE - test step index
//    c_SIP_stepFunction_handleBYE - "SIPAppLib: StepFunction_handleBYE"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleBYE(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession, 
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx,
    v_currentDialog, 
    REMOVE_DIALOG);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateNOTIFY
// 
//  Purpose:
//    Generates a SIP NOTIFY message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters:
//    - 1st(optional): the state of the subscription to report. The state will be set
//      in the subscription database
//
//  Errors:
//    - *invalid dialog index in subscription*: the dialog belonging to the subscription in the FSM context data is
//        not valid
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC. Stores the UAC index in the
//    FSM context data.
//    
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  FSM context data:
//    A subscription must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createSUBSCRIBE test step)
//
//  Constants:
//    c_SIP_stepIdx_generateNOTIFY - test step index
//    c_SIP_stepFunction_generateNOTIFY - "SIPAppLib: StepFunction_generateNOTIFY"
//
//  SIP message passed to call-back:
//(start example)
//
//    NOTIFY SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum NOTIFY
//    Event:SIP_SubscriptionData.eventType.event_type[;id=SIP_SubscriptionData.eventType.id]
//    Expires:SIP_SubscriptionData.expireInterval
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    Subscription-State:SIP_SubscriptionData.state[;expires=SIP_SubscriptionData.expireInterval]
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateNOTIFY(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateNOTIFY(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateNOTIFY(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_subscription := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].subscriptionIdx;

  if (not f_EPTF_SIP_checkSubscription(vl_subscription))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid subscription index in FSM context data."));
    return false;
  }

  var integer vl_dialog := v_db_subscription.data[vl_subscription].dialogIdx;

  if (not f_EPTF_SIP_checkDialogInSubscription(vl_dialog, vl_subscription))
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in subscription data."));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }

  if (c_SIP_Subscribe_State_unknown == v_db_subscription.data[vl_subscription].state)
  {
    v_db_subscription.data[vl_subscription].remoteTag := v_db_dialog.data[vl_dialog].remoteTag;
    v_db_subscription.data[vl_subscription].state := c_SIP_Subscribe_State_created;
  }

  var integer vl_subscriptionState := -1;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_subscriptionState);

  if (-1 == vl_subscriptionState)
  {
    vl_subscriptionState := v_db_subscription.data[vl_subscription].state;
  }else{
    if (c_SIP_Subscribe_State_terminated == vl_subscriptionState)
    {
      v_db_subscription.data[vl_subscription].state := c_SIP_Subscribe_State_toBeterminated;
    }else{
      v_db_subscription.data[vl_subscription].state := vl_subscriptionState;
    }
  }

  var integer vl_UAC := -1;

  var SIP_TransactionInDialog vl_trInDialog := INSIDE_DIALOG;
  if (c_SIP_DlgState_Unknown == v_db_dialog.data[vl_dialog].state)
  {
    vl_trInDialog := CREATE_DIALOG;
  }

  if (c_SIP_Subscribe_State_toBeterminated == v_db_subscription.data[vl_subscription].state or
        c_SIP_Subscribe_State_terminated == v_db_subscription.data[vl_subscription].state)
  {
    vl_trInDialog := REMOVE_DIALOG;
  }

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    NOTIFY_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    pl_ptr.refContext.fCtxIdx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    vl_trInDialog);

  v_db_UAC.data[vl_UAC].subscriptionIdx := vl_subscription;

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  v_db_UAC.data[vl_UAC].request.msgHeader.event :={
    fieldName := EVENT_E,
    event_type := v_db_subscription.supportedEventTypes[v_db_subscription.data[vl_subscription].eventTypeIdx],
    event_params := omit
  }

  if ("" != v_db_subscription.data[vl_subscription].eventId)
  {
    v_db_UAC.data[vl_UAC].request.msgHeader.event.event_params := {{c_SIP_ID_ID, v_db_subscription.data[vl_subscription].eventId}};
  }
  var charstring vl_state := "";
  f_EPTF_SIP_stateInt2Str(vl_subscriptionState, vl_state);

  var SemicolonParam_List pl_params := {};
  if (v_db_subscription.data[vl_subscription].expireInterval > 0 and 
        (c_SIP_Subscribe_State_active == v_db_subscription.data[vl_subscription].state or
          c_SIP_Subscribe_State_pending == v_db_subscription.data[vl_subscription].state))
  {
    f_EPTF_SIP_SetParameter(pl_params, c_SIP_EXPIRES_ID, int2str(v_db_subscription.data[vl_subscription].expireInterval));
  }

  v_db_UAC.data[vl_UAC].request.msgHeader.subscription_state :={
    fieldName := SUBSCRIPTION_STATE_E,
    substate_value := vl_state,
    subexp_params := pl_params
  }
  
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates > -1)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_NOTIFY, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_NOTIFY_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createNOTIFY
// 
//  Purpose:
//    Generates and sends a SIP NOTIFY message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters:
//    - 1st(optional): the state of the subscription to report. The state will be set
//      in the subscription database
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    
//  Call-back function reference:
//    v_setMsgNOTIFY
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the dialog database index
//
//  FSM context data:
//    A subscription must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createSUBSCRIBE test step)
//
//  Constants:
//    c_SIP_stepIdx_createNOTIFY - test step index
//    c_SIP_stepFunction_createNOTIFY - "SIPAppLib: StepFunction_createNOTIFY"
//
//  SIP message passed to call-back:
//(start example)
//
//    NOTIFY SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum NOTIFY
//    Event:SIP_SubscriptionData.eventType.event_type[;id=SIP_SubscriptionData.eventType.id]
//    Expires:SIP_SubscriptionData.expireInterval
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    Subscription-State:SIP_SubscriptionData.state[;expires=SIP_SubscriptionData.expireInterval]
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createNOTIFY(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateNOTIFY(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  if (null != v_setMsgNOTIFY)
  {
    var EPTF_IntegerList vl_params := {};
    f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
    v_setMsgNOTIFY.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
  }

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);

  f_SIP_step_sendRequest(pl_ptr);
}
///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleNOTIFY
//
//  Purpose:
//    Handles an incoming NOTIFY request. SHOULD BE called to handle the c_SIP_eventIdx_CANCEL
//    event.
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Test step parameters:
//    - pl_ptr.stepArgs[0](optional): the state of the subscription to report. The
//      state will be set in the subscription database
//    - pl_ptr.refContext.fRefArgs[0](optional): if its value equals 1 then value
//      of expires tag of Subscription-State header will be discarded, and won't be
//      set in the subscription database
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS and sets the subscripton state and the expire interval of
//    the subscription. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleNOTIFY - test step index
//    c_SIP_stepFunction_handleNOTIFY - "SIPAppLib: StepFunction_handleNOTIFY"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleNOTIFY(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;
  var integer vl_discardExpires := -1;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_discardExpires);

  if (c_SIP_Subscribe_State_unknown == v_db_subscription.data[v_currentSubscription].state)
  {
    var charstring fromTag := "";
    f_EPTF_SIP_GetParameter(v_msgToProcess.request.msgHeader.fromField.fromParams,
      c_SIP_TAG_ID, fromTag);
    v_db_dialog.data[v_currentDialog].remoteTag := fromTag;
    v_db_subscription.data[v_currentSubscription].remoteTag := fromTag;

    f_EPTF_str2int_HashMap_Insert(v_db_dialog.hashRef,
      v_db_dialog.data[v_currentDialog].callId & v_db_dialog.data[v_currentDialog].localTag & v_db_dialog.data[v_currentDialog].remoteTag,
      v_currentDialog);

    v_db_subscription.data[v_currentSubscription].state := c_SIP_Subscribe_State_created;
  }

  var charstring vl_id := "";

  if (ispresent(v_msgToProcess.request.msgHeader.event.event_params))
  {
    f_EPTF_SIP_GetParameter(v_msgToProcess.request.msgHeader.event.event_params, c_SIP_ID_ID, vl_id);
  }

  if ("refer" == v_db_subscription.supportedEventTypes[v_db_subscription.data[v_currentSubscription].eventTypeIdx].event_package and
        "" != vl_id and "" == v_db_subscription.data[v_currentSubscription].eventId)
  {
    var charstring vl_str := "";
    f_EPTF_SIP_eventType2str(v_db_subscription.supportedEventTypes[v_db_subscription.data[v_currentSubscription].eventTypeIdx], vl_str);

    f_EPTF_str2int_HashMap_Erase(v_db_subscription.hashRef,
      v_db_subscription.data[v_currentSubscription].callId & v_db_subscription.data[v_currentSubscription].localTag & vl_str);

    v_db_subscription.data[v_currentSubscription].eventId := vl_id;

    f_EPTF_str2int_HashMap_Insert(v_db_subscription.hashRef,
      v_db_subscription.data[v_currentSubscription].callId & v_db_subscription.data[v_currentSubscription].localTag & vl_str & vl_id,
      v_currentSubscription);
  }

  if (ispresent(v_msgToProcess.request.msgHeader.subscription_state))
  {
    if (sizeof(pl_ptr.stepArgs) > 0)
    {
      v_db_subscription.data[v_currentSubscription].state := pl_ptr.stepArgs[0];
    }else{
      if ("terminated" == v_msgToProcess.request.msgHeader.subscription_state.substate_value)
      {
        v_db_subscription.data[v_currentSubscription].state := c_SIP_Subscribe_State_terminated;

      }else if ("pending" == v_msgToProcess.request.msgHeader.subscription_state.substate_value)
      {
        v_db_subscription.data[v_currentSubscription].state := c_SIP_Subscribe_State_pending;
      }else if ("active" == v_msgToProcess.request.msgHeader.subscription_state.substate_value)
      {
        v_db_subscription.data[v_currentSubscription].state := c_SIP_Subscribe_State_active;
      }
    }

    if (ispresent(v_msgToProcess.request.msgHeader.subscription_state.subexp_params))
    {
      var charstring vl_expires := "";

      f_EPTF_SIP_GetParameter(v_msgToProcess.request.msgHeader.subscription_state.subexp_params,
        c_SIP_EXPIRES_ID, vl_expires);

      if ("" != vl_expires and vl_discardExpires!=1)
      {
        v_db_subscription.data[v_currentSubscription].expireInterval := str2int(vl_expires);
      }
    }
  }

  var SIP_TransactionInDialog vl_trInDialog := INSIDE_DIALOG;
  if (c_SIP_DlgState_Unknown == v_db_dialog.data[v_currentDialog].state)
  {
    vl_trInDialog := CREATE_DIALOG;
  }

  if (c_SIP_Subscribe_State_terminated == v_db_subscription.data[v_currentSubscription].state)
  {
    vl_trInDialog := REMOVE_DIALOG;
  }

  if (vl_trInDialog != CREATE_DIALOG)
  {
    f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);
  }

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess, 
    vl_UAS, 
    v_currentSession,
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    v_currentDialog, 
    vl_trInDialog);

  v_db_UAS.data[vl_UAS].subscriptionIdx := v_currentSubscription;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generatePRACK
// 
//  Purpose:
//    Generates a SIP PRACK message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1rd(optional): if 1, the Require:100rel header will be added to the request (add100rel := 0)
//    - 2th(optional): if 1, the Require:precondition header will be added to the request (precondition := 0)
//    - 3th(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
// 
//  Errors:
//    - *invalid dialog index in FSM context data*: invalid dialog index in the FSM context data. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message in the UAC. Stores the UAC index in the
//    FSM context data.
//
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generatePRACK - test step index
//    c_SIP_stepFunction_generatePRACK - "SIPAppLib: StepFunction_generatePRACK"
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//    A reliably sent provisional response has been arrived to the FSM.
//
//  SIP message passed to call-back:
//(start example)
//
//    PRACK SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum PRACK
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    RAck: SIP_UnacknowledgedRespData.seqNumber SIP_UnacknowledgedRespData.rSeq SIP_UnacknowledgedRespData.method
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generatePRACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generatePRACK(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generatePRACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx:=pl_ptr.eIdx;

  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_dialog := -1;
  var integer vl_UAC := -1;
  var integer vl_UACforPRACK := -1;

  vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;

  if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].userSessionAssociated)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,")"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }
  
  
  for (var integer i := 0; i < sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data); i := i + 1)
  {
    if (v_db_UAC.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i]].prack)
    {
      vl_UACforPRACK := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACs.data[i];
      break;
    }
  }

  if (-1 == vl_UACforPRACK)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": no UAC found in FSM the send PRACK (",vl_dialog,")"));
    return false;
  }

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    PRACK_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    INSIDE_DIALOG);

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  var charstring vl_methodStr;
  f_EPTF_SIP_method2str(v_db_UAC.data[vl_UACforPRACK].method, vl_methodStr);

  var integer vl_add100rel := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_add100rel);   
  var integer vl_addPrecond := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_addPrecond);  
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 2, vl_disableExtTemplates);

  var charstring vl_extraHeaders := "";
  var OptionTag_List vl_optionsTags := {};
  f_EPTF_SIP_prepareOptionsTag(vl_add100rel, vl_addPrecond, vl_disableExtTemplates,
    vl_optionsTags ,vl_extraHeaders);

  if (sizeof(vl_optionsTags) > 0)
  {
    v_db_UAC.data[vl_UAC].request.msgHeader.require := {
      fieldName := REQUIRE_E,
      optionsTags := vl_optionsTags
    }

    if (vl_disableExtTemplates != -1) {
      vl_extraHeaders := "Require: " & vl_extraHeaders & "\r\n";
    }
  }
  
  v_db_UAC.data[vl_UAC].request.msgHeader.rack :=
  {
    fieldName := RACK_E,
    response_num := v_db_UAC.data[vl_UACforPRACK].unackRespData.rSeq,
    seqNumber := v_db_UAC.data[vl_UACforPRACK].unackRespData.seqNumber,
    method := vl_methodStr
  }

  if (vl_disableExtTemplates != -1)
  {  
    var integer vl_templateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_templateSetIdx)
    {
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_PRACK, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_PRACK_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateParams[sizeof(v_db_UAC.data[vl_UAC].templateParams)] := {
        "extraHeaders", vl_extraHeaders
      }

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;

      // register dynamic templates
      f_SIP_registerRSeqExtTemplateForRequest(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, 
        int2str(v_db_UAC.data[vl_UACforPRACK].unackRespData.rSeq));
      f_SIP_registerRSeqNumExtTemplateForRequest(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, 
        int2str(v_db_UAC.data[vl_UACforPRACK].unackRespData.seqNumber));
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createPRACK
// 
//  Purpose:
//    Generates and sends a SIP PRACK message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid dialog index in FSM context data*: invalid dialog index in the FSM context data. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//
//  Call-back function reference:
//    v_setMsgPRACK
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createPRACK - test step index
//    c_SIP_stepFunction_createPRACK - "SIPAppLib: StepFunction_createPRACK"
//
//  FSM context data:
//    A dialog must be created and the index must be stored in the FSM context data
//    before calling this test step.
//      (for example by invoking the f_SIP_step_createINVITE or f_SIP_step_handleINVITE test step)
//    A reliably sent provisional response has been arrived to the FSM.
//
//  SIP message passed to call-back:
//(start example)
//
//    PRACK SIP_DialogData.requestUri SIP/2.0
//    Call-ID:SIP_DialogData.callId
//    Content-Length:0
//    CSeq:SIP_DialogData.localSeqNum PRACK
//    From:SIP_DialogData.localUri;tag=SIP_DialogData.localTag
//    Max-Forwards:70
//    RAck: SIP_UnacknowledgedRespData.seqNumber SIP_UnacknowledgedRespData.rSeq SIP_UnacknowledgedRespData.method
//    To:SIP_DialogData.remoteUri;tag=SIP_DialogData.remoteTag
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createPRACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generatePRACK(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }

  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgPRACK)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      //v_setMsgBYE.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params); // FIXME - wrong?
      v_setMsgPRACK.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handlePRACK
// 
//  Purpose:
//    Handles an incoming PRACK request. SHOULD BE called to handle the c_SIP_eventIdx_PRACK 
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handlePRACK - test step index
//    c_SIP_stepFunction_handlePRACK - "SIPAppLib: StepFunction_handlePRACK"
////////////////////////////////////////////////////////////
public function f_SIP_step_handlePRACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  f_ETPF_SIP_CancelRetransmit(v_currentUser, vl_FSMIdx);

  var integer vl_UAS := -1;

  f_EPTF_SIP_createNewUASinDialog(v_msgToProcess,
    vl_UAS,
    v_currentSession,
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    v_currentDialog,
    INSIDE_DIALOG);

  f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateOPTIONS
// 
//  Purpose:
//    Generates a SIP OPTIONS message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//    - 2nd(optional): if -1, external templates will be disabled in the request (disableExtTemplates := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    Creates a new UAC and a message and the template parameters if used and stores them in the UAC.
//    Stores the UAC index in the FSM context data.
//    The request is sent outside of dialog.
//    
//  Call-back function reference:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateOPTIONS - test step index
//    c_SIP_stepFunction_generateOPTIONS - "SIPAppLib: StepFunction_generateOPTIONS"
//
//  SIP message passed to call-back:
//(start example)
//
//    OPTIONS _SIP_User.calledUsers[calledUser].addr.addrSpecUnion_ SIP/2.0
//    Accept:SIP_UAData.acceptList
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx OPTIONS
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:SIP_User.calledUsers[calledUser]
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_generateOPTIONS(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateOPTIONS(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateOPTIONS(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;

  f_EPTF_SIP_CreateNewUAC(
    vl_UAC,
    OPTIONS_E,
    v_db_users.data[v_currentUser].currentSession, 
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport,
    "");

  var charstring vl_callId;
  
  f_EPTF_SIP_check4xxRetry(
    OPTIONS_E,
    v_currentUser,
    vl_FSMIdx,
    vl_callId,
    v_db_users.data[v_currentUser].cSeq
  );
  
  var integer  vl_calledUser:= 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_calledUser);
  
  var integer vl_idIdx := v_db_users.data[v_currentUser].regData.currentID;

  var Addr_Union vl_from;
  f_EPTF_SIP_getUserData_id_addr(v_currentUser, v_db_users.data[v_currentUser].regData.currentID, vl_from);
  var Addr_Union vl_to := vl_from;
  
  if (0 <= vl_calledUser and sizeof(v_db_users.data[v_currentUser].calledUsers) > vl_calledUser)
  {
    f_EPTF_SIP_getCalledUser_addr(v_currentUser, vl_calledUser, vl_to);
  }
  
  var SipUrl vl_requestUri;
  f_EPTF_SIP_GetUri(vl_to, vl_requestUri);

  var charstring vl_localTag;
  f_EPTF_SIP_genLocalTag(v_currentUser, vl_localTag);

  var RouteBody_List vl_routeBody := {};
  f_EPTF_SIP_SIPRouteBodyList2Route(v_db_users.data[v_currentUser].route, vl_routeBody);

  f_EPTF_SIP_CreateNewRequest(
    vl_UAC,
    vl_requestUri, // Request-URI
    vl_callId, //Call-ID
    v_db_users.data[v_currentUser].cSeq, //CSeq
    vl_to,//To
    vl_from, //From
    vl_localTag,
    vl_routeBody); //local tag

  if (0 < sizeof(v_db_UAs.uaData.acceptList))
  {
    v_db_UAC.data[vl_UAC].request.msgHeader.accept :=
    {
      fieldName := ACCEPT_E,
      acceptArgs := v_db_UAs.uaData.acceptList
    }
  }
  
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 1, vl_disableExtTemplates);

  if (vl_disableExtTemplates != -1)
  {
    var integer vl_templateSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_templateSetIdx)
    {
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_OPTIONS, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_templateSetIdx, v_templateTypeIdx_OPTIONS_BODY, vl_templateBodyIdx);
    }
  
    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams);

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createOPTIONS
// 
//  Purpose:
//    Generates and sends a SIP OPTIONS message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): called user index (calledUser := 0)
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM. The response to this request will be reported to the FSM.
//    The request is sent outside of dialog.
//    
//  Call-back function reference:
//    v_setMsgMESSAGE
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the UAC database index
//
//  Constants:
//    c_SIP_stepIdx_createOPTIONS - test step index
//    c_SIP_stepFunction_createOPTIONS - "SIPAppLib: StepFunction_createOPTIONS"
//
//  SIP message passed to call-back:
//(start example)
//
//    OPTIONS _SIP_User.calledUsers[calledUser].addr.addrSpecUnion_ SIP/2.0
//    Accept:SIP_UAData.acceptList
//    Call-ID:TTCN3xxxxxxxxxxxx@SIP_User.localHost
//    Content-Length:0
//    CSeq:xxxxxxxxxx OPTIONS
//    From:SIP_User.iD[SIP_User.regData.currentID].addr;tag=xxxxxxxxxxxx
//    Max-Forwards:70
//    To:SIP_User.calledUsers[calledUser]
//    Via:SIP/2.0/SIP_User.preferredTransport SIP_User.localHost:SIP_User.portNumber;branch=z9hG4bKxxxxxxTxxxxxx
//
//  (end)
///////////////////////////////////////////////////////////
public function f_SIP_step_createOPTIONS(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateOPTIONS(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;
  
  var charstring vl_body := "";
  var integer vl_contentLength := 0;
  if(0 > v_db_UAC.data[vl_UAC].templateBodyIdx)
  {
    f_EPTF_SIP_applySetTemplateBody(v_currentUser, vl_FSMIdx, vl_body, vl_contentLength, pl_ptr);
    if("" != vl_body)
    {
      v_db_UAC.data[vl_UAC].request.messageBody := vl_body;
      f_EPTF_SIP_Message_CalcContentLengthRequest(v_db_UAC.data[vl_UAC].request);
    }
  }
  
  if(0 > v_db_UAC.data[vl_UAC].templateHeaderIdx)
  {
    if (null != v_setMsgOPTIONS)
    {
      var EPTF_IntegerList vl_params := {};
      f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
      v_setMsgOPTIONS.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
    }

    f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  }

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleOPTIONS
// 
//  Purpose:
//    Handles an incoming OPTIONS request. SHOULD BE called to handle the c_SIP_eventIdx_OPTIONS
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleOPTIONS - test step index
//    c_SIP_stepFunction_handleOPTIONS - "SIPAppLib: StepFunction_handleOPTIONS"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleOPTIONS(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  f_EPTF_SIP_createNewUAS(v_msgToProcess, vl_UAS, v_currentSession, v_currentUser, vl_fsmCtx, vl_FSMIdx);

}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateINFO
// 
//  Purpose:
//    Generates an INFO request in an established session.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *invalid dialog index in FSM context data*: invalid dialog index in the FSM context data. The message will not be sent out.
//    - *no INVITE UAC in FSM context data*: no transaction was found in the FSM context data. The message will
//        not be sent out.
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//
//  Call-back function references:
//    To modify message content or template parameters the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  FSM context data:
//    A valid dialog index must be stored in the FSM context data
//    before calling this test step.
//
//  Constants:
//    c_SIP_stepIdx_generateINFO - test step index
//    c_SIP_stepFunction_generateINFO - "SIPAppLib: StepFunction_generateINFO"
//
//  SIP message passed to call-back:
//    The message is created accroding to the rules and procedures defined in RFC2976.
//
///////////////////////////////////////////////////////////
public function f_SIP_step_generateINFO(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateINFO(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateINFO(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx  := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }
  
  var integer vl_disableExtTemplates := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_disableExtTemplates);

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_UAC := -1;
  var integer vl_dialog := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].dialogIdx;

  if (not f_EPTF_SIP_checkDialog(vl_dialog) or not v_db_dialog.data[vl_dialog].ACKData.ACKReady)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId,": invalid dialog index in FSM context data (",vl_dialog,"), or ACK is not ready"));
    f_SIP_Logging_WARNING(log2str(%definitionId,": current user: ", v_currentUser));
    return false;
  }

  f_EPTF_SIP_CreateNewUACInDialog(
    vl_UAC,
    INFO_E,
    v_db_users.data[v_currentUser].currentSession,
    v_currentUser,
    vl_fsmCtx,
    vl_FSMIdx,
    v_db_users.data[v_currentUser].preferredTransport,
    "",
    vl_dialog,
    INSIDE_DIALOG);

  f_EPTF_SIP_CreateNewRequestInDialog(
    vl_UAC,
    vl_dialog);

  if (vl_disableExtTemplates > -1)
  {
    var integer vl_extTempSetIdx := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].extTemplateSetIdx;
    var integer vl_templateHeaderIdx := -1, vl_templateBodyIdx := -1;

    if (0 <= vl_extTempSetIdx)
    {
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_INFO, vl_templateHeaderIdx);
      f_SIP_useExtTemplate(vl_extTempSetIdx, v_templateTypeIdx_INFO_BODY, vl_templateBodyIdx);
    }

    if (-1 != vl_templateHeaderIdx or -1 != vl_templateBodyIdx)
    {
      f_EPTF_SIP_CreateNewRequestDictionary(
        vl_UAC,
        v_db_UAC.data[vl_UAC].templateParams
      );

      v_db_UAC.data[vl_UAC].templateBodyIdx := vl_templateBodyIdx;
      v_db_UAC.data[vl_UAC].templateHeaderIdx := vl_templateHeaderIdx;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createINFO
// 
//  Purpose:
//    Generates an INFO request in an established session.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//
//  Call-back function references:
//    v_setMsgINFO
//
//  Call-back function parameter (v_setMsgINFO):
//      - pl_params[c_EPTF_SIP_cbPar_UACIdx]: the dialog database index
//    
//  FSM context data:
//    A valid dialog index must be stored in the FSM context data
//    before calling this test step.
//
//  Constants:
//    c_SIP_stepIdx_createINFO - test step index
//    c_SIP_stepFunction_createINFO - "SIPAppLib: StepFunction_createINFO"
//
//  SIP message passed to call-back:
//    The message is created accroding to the rules and procedures defined in RFC2976.
//
///////////////////////////////////////////////////////////
public function f_SIP_step_createINFO(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateINFO(pl_ptr)) { return; }
  
  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  if (null != v_setMsgINFO)
  {
    var EPTF_IntegerList vl_params := {};
    f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UACIdx, vl_UAC);
    v_setMsgINFO.apply(v_db_UAC.data[vl_UAC].request, pl_ptr, vl_params);
  }

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleINFO
// 
//  Purpose:
//    Handles an incoming INFO request. SHOULD BE called to handle the c_SIP_eventIdx_INFO
//    event.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
//
//  Errors:
//    - *FSM has not been initialized...*
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS. Stores the UAS index in the
//    FSM context data.
//
//  Constants:
//    c_SIP_stepIdx_handleINFO - test step index
//    c_SIP_stepFunction_handleINFO - "SIPAppLib: StepFunction_handleINFO"
////////////////////////////////////////////////////////////
public function f_SIP_step_handleINFO(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx := pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_UAS := -1;

  f_EPTF_SIP_createNewUASinDialog(
    v_msgToProcess,
    vl_UAS,
    v_currentSession,
    v_currentUser,
    vl_fsmCtx, 
    vl_FSMIdx, 
    v_currentDialog,
    INSIDE_DIALOG);

  f_EPTF_SIP_handleRequestInDialog(v_currentDialog, v_msgToProcess.request);

}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateRejectRequest
// 
//  Purpose:
//    Generates an error message. *WARNING*: generally this step SHOULD NOT be used to generate
//    error reponses. It SHOULD be used when the user does not want to handle a request (and therefore to
//    change the state of some context) but wants to send a response. Can be used for example in case of
//    the c_SIP_eventIdx_requestOutOfOrder event to generate 500 (Server Internal Error) response.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): status code (statusCode := 500)
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    Creates a new UAS, than creates a response to the UAS.
//    
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyResponseCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateRejectRequest - test step index
//    c_SIP_stepFunction_generateRejectRequest - "SIPAppLib: StepFunction_generateRejectRequest";
//
//  SIP message passed to call-back:
//
//    The message is created accroding to the rules and procedures defined the RFC containing
//    the request (general procedures: RFC3261 Section 8.2.6).
//
///////////////////////////////////////////////////////////
public function f_SIP_step_generateRejectRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  var integer vl_UAS := -1;
  f_EPTF_SIP_createNewUAS(v_msgToProcess, vl_UAS, v_currentSession, v_currentUser, vl_fsmCtx, vl_FSMIdx);
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx := vl_UAS;

  var integer vl_statusCodeIdx := c_status_500ServerInternalError_idx;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_statusCodeIdx);

  f_EPTF_SIP_Message_CreateResponseFromUAS(vl_UAS, c_EPTF_SIP_StatusLines[vl_statusCodeIdx], -1);
  
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode := c_SIP_ResponseCode_RejectRequest;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_rejectRequest
// 
//  Purpose:
//    Generates and sends an error message. *WARNING*: generally this step SHOULD NOT be used to generate
//    error reponses. It SHOULD be used when the user does not want to handle a request (and therefore to
//    change the state of some context) but wants to send a response. Can be used for example in case of
//    the c_SIP_eventIdx_requestOutOfOrder event to generate 500 (Server Internal Error) response.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Errors:
//    - *FSM has not been initialized...*
//
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): status code (statusCode := 500)
//
//  Detailed Comments:
//    The test step MUST BE called from an FSM.
//    
//  Call-back function reference:
//    v_setMsgReject
//
//  Call-back function parameters:
//      - pl_params[c_EPTF_SIP_cbPar_UASIdx]: the dialog database index
//
//  Constants:
//    c_SIP_stepIdx_rejectRequest - test step index
//    c_SIP_stepFunction_rejectRequest - "SIPAppLib: StepFunction_rejectRequest";
//
//  SIP message passed to call-back:
//
//    The message is created accroding to the rules and procedures defined the RFC containing
//    the request (general procedures: RFC3261 Section 8.2.6).
//
///////////////////////////////////////////////////////////
public function f_SIP_step_rejectRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  f_SIP_step_generateRejectRequest(pl_ptr);

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;

  if (null != v_setMsgReject)
  {
    var EPTF_IntegerList vl_params := {};
    f_EPTF_SIP_addInt2IntegerList(vl_params, c_EPTF_SIP_cbPar_UASIdx, vl_UAS);
    v_setMsgReject.apply(v_db_UAS.data[vl_UAS].response, pl_ptr, vl_params);
  }

  f_EPTF_SIP_applySetResponse(v_currentUser, vl_FSMIdx, v_db_UAS.data[vl_UAS].response, pl_ptr);
  
  f_SIP_step_sendResponse(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_disableGroupEvent
// 
//  Purpose:
//    Disables the group event reporting
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed Comments:
//    There are some group events that the AppLib reports:
//      - c_SIP_eventIdx_1xx
//      - c_SIP_eventIdx_2xx
//      - c_SIP_eventIdx_3xx
//      - c_SIP_eventIdx_4xx
//      - c_SIP_eventIdx_5xx
//      - c_SIP_eventIdx_6xx
//      - c_SIP_eventIdx_3xxto6xx
//
//    Upon receiving a response, the either the status code and the group is dispatched.
//    If this test step is invoked during the hendling of the "status code event",
//    the group will not be reported.
//
//  Constants:
//    c_SIP_stepIdx_disableGroupEvent - test step index
//    c_SIP_stepFunction_disableGroupEvent - "SIPAppLib: StepFunction_disableGroupEvent"
////////////////////////////////////////////////////////////
public function f_SIP_step_disableGroupEvent(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  v_dispatchGroupEvent := false;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_cleanUp
// 
//  Purpose:
//    Cleans up the FSM context data. MUST BE
//    called 
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed Comments:
//    Can be called at the end of every traffic case.
//
//  Constants:
//    c_SIP_stepIdx_cleanUp - test step index
//    c_SIP_stepFunction_cleanUp - "SIPAppLib: StepFunction_cleanUp"
////////////////////////////////////////////////////////////
public function f_SIP_step_cleanUp(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    if(c_EPTF_Common_debugSwitch and f_SIP_Logging_debugEnabled()) {
      f_SIP_Logging_DEBUG(%definitionId&": FSM has not been initialized");
    }
    return;
  }

  var integer vl_userIdx := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  f_EPTF_SIP_cleanUp(vl_userIdx, vl_FSMIdx);

  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx] := c_SIP_initFSMData;

//  f_EPTF_FBQ_moveFromBusyToFreeTail(vl_FSMIdx, v_db_users.data[vl_userIdx].FSMs.queue);
  if(-1 == f_EPTF_Common_IndexArray_freeElement(v_db_users.data[vl_userIdx].FSMs.queue, vl_FSMIdx)) { /*remove warning*/ }

  f_EPTF_LGenBase_setAppDataItemOfFsmCtx(vl_eCtx, vl_fsmCtx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx, -1);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_cleanUpDynamicData
// 
//  Purpose:
//    Cleans up dynamic data in the FSM context (dialogs, transactions, subscriptions, publiscations).
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed Comments:
//    Can be called at the end of every traffic case.
//
//  Test step parameters (and in case of an optional parameter the default value):
//    - 1st(optional): print warning (print warning := 0; don't print warning := 1) (default is to print warning)
//
//  Constants:
//    c_SIP_stepIdx_cleanUpDynamicData - test step index
//    c_SIP_stepFunction_cleanUp DynamicData- "SIPAppLib: StepFunction_cleanUpDynamicData"
////////////////////////////////////////////////////////////
public function f_SIP_step_cleanUpDynamicData(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;
  var integer vl_FSMIdx := -1;
  var boolean vl_ignore := false;
  
  if (sizeof(pl_ptr.refContext.fRefArgs) > 0)
  {
    if (pl_ptr.refContext.fRefArgs[0] == 1)
      {
       vl_ignore := true;
      }
  }

  if (not f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_FSMIdx))
  {
    f_SIP_Logging_DEBUG(log2str(%definitionId,": FSM has not been initialized"));
    return;
  }

  var integer vl_userIdx := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  f_EPTF_SIP_cleanUp(vl_userIdx, vl_FSMIdx, vl_ignore);
  
//dialog data
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].dialogIdx := -1;
//subscription data
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].subscriptionIdx := -1;
//publication data
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].publishIdx := -1;
//transaction data
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].UACs := c_SIP_initTransactionDB;
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].UASs := c_SIP_initTransactionDB;

  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].timers := {-1};
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].retransCache := c_SIP_RetransCache_init;

}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_setRetryAfterTimer
// 
//  Purpose:
//    Starts an FSM timer with the retry after time of a response. The
//    v_msgToProcess component variable must contain the response.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters:
//    - 1st: timer index
//
//  Errors:
//    - *no or invalid timer index in context parameter*: invalid timer index was provided as
//        a test step parameter.
//
//  Constants:
//    c_SIP_stepIdx_setRetryAfterTimer - test step index
//    c_SIP_stepFunction_setRetryAfterTimer - "SIPAppLib: StepFunction_setRetryAfterTimer"
//
//  Detailed comments:
//    The retry after timer is retrieved from a reponse message, i.e. which is presumed to
//    to be stored in the v_msgToProcess component variable.
////////////////////////////////////////////////////////////
public function f_SIP_step_setRetryAfterTimer(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx:=pl_ptr.eIdx;
  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;

  var integer vl_timer := -1;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_timer);

  if (0 > vl_timer)
  {
    f_SIP_Logging_WARNING(log2str(%definitionId, ":  no or invalid timer index in context parameter."));
    return;
  }

  var integer vl_time := f_EPTF_SIP_getRetryAfter();
  
  if (vl_time > 0)
  {
    f_EPTF_LGenBase_setDuration4TimerAtFsmCtx
    (
      vl_eCtx, vl_fsmCtx, vl_timer,
      int2float(vl_time)
    );
  }
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_init
// 
//  Purpose:
//    Initializes the FSM context data. MUST BE called in an FSM using SIP test steps.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Test step parameters:
//    - 1st(optional): if 1, the incoming response event will differ from method to method. In this case,
//      functions BYE, CANCEL, ... defined in <EPTF_SIP_Transaction_Functions> must be used in the FSMs to handle the responses.
//
//  Constants:
//    c_SIP_stepIdx_init - test step index
//    c_SIP_stepFunction_init - "SIPAppLib: StepFunction_init"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_init(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_eCtx:=pl_ptr.eIdx;

  var integer vl_userIdx := f_EPTF_LGenBase_getBehaviorCtxItem(vl_eCtx, v_SIP_myBIdx, 0);

  var integer vl_fsmCtx := pl_ptr.refContext.fCtxIdx;

  var integer vl_newIdx;

  if (f_EPTF_SIP_FSMInitialized(vl_eCtx, vl_fsmCtx, vl_newIdx))
  {
    return;
  }

//  vl_newIdx := f_EPTF_FBQ_getOrCreateFreeSlot(v_db_users.data[vl_userIdx].FSMs.queue);
  //  f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_db_users.data[vl_userIdx].FSMs.queue);
  vl_newIdx := f_EPTF_Common_IndexArray_setNewElement(v_db_users.data[vl_userIdx].FSMs.queue);

  if(c_EPTF_Common_debugSwitch and f_SIP_Logging_debugEnabled()) {
    f_SIP_Logging_DEBUG(log2str(%definitionId, ":  initializing fsm ", vl_fsmCtx, " for entity ",vl_eCtx));
  }

  f_EPTF_LGenBase_setAppDataItemOfFsmCtx(vl_eCtx, vl_fsmCtx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx, vl_newIdx);

  v_db_users.data[vl_userIdx].FSMs.data[vl_newIdx] := c_SIP_initFSMData;

  f_EPTF_SIP_setUserData_FSMs_fsmCtx(vl_userIdx, vl_newIdx, vl_fsmCtx);

  var integer vl_distinct := 0;
  f_EPTF_SIP_getIntValue(pl_ptr.refContext.fRefArgs, 0, vl_distinct);

  if (1 == vl_distinct)
  {
    v_db_users.data[vl_userIdx].FSMs.data[vl_newIdx].distinctResponse := true;
  }

  v_db_users.data[vl_userIdx].FSMs.data[vl_newIdx].extTemplateSetIdx := f_EPTF_LGenBase_templateSetIdxOfStep(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleRequest
// 
//  Purpose:
//    Creates an UAS and makes a copy of the incoming request.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Constants:
//    c_SIP_stepIdx_handleRequest - test step index
//    c_SIP_stepFunction_handleRequest - "SIPAppLib: StepFunction_handleRequest"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  
  var integer vl_UAS;
  f_EPTF_SIP_createNewUAS(
    v_msgToProcess,
    vl_UAS,
    0,
    v_currentUser,
    pl_ptr.refContext.fCtxIdx,
    vl_FSMIdx);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_handleTransportError
// 
//  Purpose:
//    Teststep for handling transport errors, deletes all UACs of the fsm
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Constants:
//    c_SIP_stepIdx_handleTransportError - test step index
//    c_SIP_stepFunction_handleTransportError - "SIPAppLib: StepFunction_handleTransportError"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_handleTransportError(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return;
  }

  var integer vl_userIdx := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  for(var integer vl_uacIdx:=0; vl_uacIdx<sizeof(v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].UACs.data); vl_uacIdx:=vl_uacIdx+1) {
    f_EPTF_SIP_cleanUpUAC(v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].UACs.data[vl_uacIdx]);
  }
  v_db_users.data[vl_userIdx].FSMs.data[vl_FSMIdx].UACs.data := {};
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateForwardedRequest
// 
//  Purpose:
//    See <f_SIP_forwardRequestPreprocess> and <f_SIP_createForwardedRequest>. Generates the request.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed comments:
//    An UAC is created and the message is stored in it.
//
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//    
//  Constants:
//    c_SIP_stepIdx_generateForwardedRequest - test step index
//    c_SIP_stepFunction_generateForwardedRequest - "SIPAppLib: StepFunction_generateForwardedRequest"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_generateForwardedRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateForwardedRequest(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateForwardedRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  
  var charstring vl_transactionId := "";

  f_EPTF_SIP_Transaction_GenerateId_2(v_msgToProcess.request, vl_transactionId);

  var integer vl_UAC := -1;
  //create UAC
  f_EPTF_SIP_CreateNewUAC(
    vl_UAC, 
    v_msgToProcess.request.requestLine.method,
    0,
    v_currentUser, 
    pl_ptr.refContext.fCtxIdx, 
    vl_FSMIdx, 
    v_db_users.data[v_currentUser].preferredTransport,
    vl_transactionId);

  v_db_UAC.data[vl_UAC].transactionTimeout := v_timerC;
  v_db_UAC.data[vl_UAC].state := c_SIP_TrState_ProxyUnknown;
  v_db_UAC.data[vl_UAC].request := v_msgToProcess.request;
  
  f_SIP_forwardRequestPreprocess(v_db_UAC.data[vl_UAC].request, v_currentUser, v_SIP_transportParams);

  f_SIP_createForwardedRequest(
    v_currentUser, 
    vl_transactionId, 
    v_db_users.data[v_currentUser].preferredTransport, 
    v_db_UAC.data[vl_UAC].request);
  
  v_db_UAC.data[vl_UAC].templateBodyIdx := -1;
  v_db_UAC.data[vl_UAC].templateHeaderIdx := -1;

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createForwardedRequest
// 
//  Purpose:
//    See see <f_SIP_forwardRequestPreprocess> and <f_SIP_createForwardedRequest>. Generates and sends the request.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed comments:
//    -
//    
//  Constants:
//    c_SIP_stepIdx_createForwardedRequest - test step index
//    c_SIP_stepFunction_createForwardedRequest - "SIPAppLib: StepFunction_createForwardedRequest"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_createForwardedRequest(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateForwardedRequest(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAC := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UACidx;

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_UAC.data[vl_UAC].request, pl_ptr);
  
  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateRequestStateless
// 
//  Purpose:
//    See <f_SIP_forwardRequestPreprocess> and <f_SIP_createForwardedRequest>. Generates the request.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed Comments:
//    The branch-id is generated from the forwarded request:
//      MD5(branchId)
//
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Constants:
//    c_SIP_stepIdx_generateRequestStateless - test step index
//    c_SIP_stepFunction_generateRequestStateless - "SIPAppLib: StepFunction_generateRequestStateless"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_generateRequestStateless(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateRequestStateless(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateRequestStateless(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request := v_msgToProcess.request;
  
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  f_SIP_forwardRequestPreprocess(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request, v_currentUser, v_SIP_transportParams);

  var charstring vl_branchId := "";

  if(ispresent(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request.msgHeader.via) and
      sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request.msgHeader.via.viaBody) > 0 and
      ispresent(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request.msgHeader.via.viaBody[0].viaParams)) {
    f_EPTF_SIP_GetParameter(
      v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request.msgHeader.via.viaBody[0].viaParams,
      c_SIP_BRANCH_ID,
      vl_branchId);
  }
  
  vl_branchId := f_calculateMD5(vl_branchId);

  f_SIP_createForwardedRequest(
    v_currentUser,
    vl_branchId,
    v_db_users.data[v_currentUser].preferredTransport,
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request);
  
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := c_SIP_RequestType_RequestStateless;

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createRequestStateless
// 
//  Purpose:
//    See <f_SIP_forwardRequestPreprocess> and <f_SIP_createForwardedRequest>.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Detailed Comments:
//    The branch-id is generated from the forwarded request:
//      MD5(branchId)
//
//  Constants:
//    c_SIP_stepIdx_createRequestStateless - test step index
//    c_SIP_stepFunction_createRequestStateless - "SIPAppLib: StepFunction_createRequestStateless"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_createRequestStateless(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateRequestStateless(pl_ptr)) { return; }

  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  
  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request, pl_ptr);

  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateForwardedACK
// 
//  Purpose:
//    Same as <f_SIP_step_generateForwardedRequest> but no UAC is created.
//    This step must be called in case of forwarding an ACK request after a successfully
//    finished INVITE transaction. Sends the message.
// 
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyRequestCallBack")
//
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Constants:
//    c_SIP_stepIdx_generateForwardedACK - test step index
//    c_SIP_stepFunction_generateForwardedACK - "SIPAppLib: StepFunction_generateForwardedACK"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_generateForwardedACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateForwardedACK(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateForwardedACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;
  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request := v_msgToProcess.request;

  f_SIP_forwardRequestPreprocess(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request, v_currentUser, v_SIP_transportParams);

  var charstring vl_transactionId := "";

  f_EPTF_SIP_Transaction_GenerateId_2(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request, vl_transactionId);

  f_SIP_createForwardedRequest(
    v_currentUser,
    vl_transactionId,
    v_db_users.data[v_currentUser].preferredTransport,
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request);
  
  v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].requestType := c_SIP_RequestType_ForwardedACK;

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createForwardedACK
// 
//  Purpose:
//    Same as <f_SIP_step_createForwardedRequest> but no UAC is created.
//    This step must be called in case of forwarding an ACK request after a successfully
//    finished INVITE transaction. Sends the message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Constants:
//    c_SIP_stepIdx_createForwardedACK - test step index
//    c_SIP_stepFunction_createForwardedACK - "SIPAppLib: StepFunction_createForwardedACK"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_createForwardedACK(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateForwardedACK(pl_ptr)) { return; }
  
  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  f_EPTF_SIP_applySetRequest(v_currentUser, vl_FSMIdx, v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].request, pl_ptr);
  
  f_SIP_step_sendRequest(pl_ptr);
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_generateForwardedResponse
// 
//  Purpose:
//    For the details see <f_SIP_forwardResponsePreprocess>. Generates the message.
// 
//  Call-back function reference:
//    To modify message content the call-back functions registered in
//     "v_db_modifyMsgCallBack" database could be used. (i.e. invoking "f_SIP_step_modifyResponseCallBack")
//
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Constants:
//    c_SIP_stepIdx_generateForwardedResponse - test step index
//    c_SIP_stepFunction_generateForwardedResponse - "SIPAppLib: StepFunction_generateForwardedResponse"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_generateForwardedResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(f_SIP_private_generateForwardedResponse(pl_ptr)) { /*remove warning about unused return value*/ }
}

private function f_SIP_private_generateForwardedResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
return boolean
{
  var integer vl_FSMIdx := -1;

  if (not f_EPTF_SIP_FSMInitialized(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, vl_FSMIdx))
  {
    f_SIP_Logging_WARNING(%definitionId & ": FSM has not been initialized. The f_SIP_step_init function must be called as first step in the FSMs using SIP.");
    return false;
  }

  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);

  f_SIP_forwardResponsePreprocess(v_msgToProcess.response)

  var charstring vl_transactionId := "";
  f_EPTF_SIP_GetTransactionId(v_msgToProcess.response.msgHeader, vl_transactionId);

  if ("" == vl_transactionId)
  {
    return false;
  }

  var integer vl_UAS := -1;
  
  for (var integer i := 0; i < sizeof(v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data); i := i + 1)
  {
    if (vl_transactionId == v_db_UAS.data[v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i]].transactionId)
    {
      vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASs.data[i];
      break;
    }
  }

  if (-1 == vl_UAS)
  {
    f_SIP_Logging_DEBUG(%definitionId & ": no matching UAS in FSM context data, forward statelessly");
    
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response := v_msgToProcess.response;
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode := c_SIP_ResponseCode_ForwardedResponseStateless;
  }else
  {
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx := vl_UAS;
    v_db_UAS.data[vl_UAS].response := v_msgToProcess.response;
    v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].responseCode := c_SIP_ResponseCode_ForwardedResponse;
  }

  return true;
}

///////////////////////////////////////////////////////////
//  Function: f_SIP_step_createForwardedResponse
// 
//  Purpose:
//    For the details see <f_SIP_forwardResponsePreprocess>. Generates and sends the message.
// 
//  Parameters:
//    pl_ptr - *in* <EPTF_LGenBase_TestStepArgs> - test step parameter.
// 
//  Constants:
//    c_SIP_stepIdx_createForwardedResponse - test step index
//    c_SIP_stepFunction_createForwardedResponse - "SIPAppLib: StepFunction_createForwardedResponse"
//
////////////////////////////////////////////////////////////
public function f_SIP_step_createForwardedResponse(in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  if(not f_SIP_private_generateForwardedResponse(pl_ptr)) { return; }
  
  var integer vl_FSMIdx := f_EPTF_LGenBase_getAppDataItemOfFsmCtx(pl_ptr.eIdx, pl_ptr.refContext.fCtxIdx, v_SIP_myBIdx, c_SIP_AppDataIndex_FSMIdx);
  v_currentUser := f_EPTF_LGenBase_getBehaviorCtxItem(pl_ptr.eIdx, v_SIP_myBIdx, 0);
  var integer vl_UAS := v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].UASidx;
  
  if(-1 == vl_UAS) {
    f_EPTF_SIP_applySetResponse(v_currentUser, vl_FSMIdx, v_db_users.data[v_currentUser].FSMs.data[vl_FSMIdx].response, pl_ptr);
  } else {
    f_EPTF_SIP_applySetResponse(v_currentUser, vl_FSMIdx, v_db_UAS.data[vl_UAS].response, pl_ptr);
  }
  
  f_SIP_step_sendResponse(pl_ptr);
}

private function f_SIP_useExtTemplate(
  in integer pl_templateSetIdx,
  in integer pl_templateTypeIdx, 
  inout integer pl_templateIdx)
runs on EPTF_SIP_LGen_CT
{
  pl_templateIdx := f_EPTF_LGenBase_getExtTemplIdxFromSet(pl_templateSetIdx, pl_templateTypeIdx);
}

private function f_EPTF_SIP_applySetRequest(
  in integer pl_userIdx,
  in integer pl_FSMIdx, 
  inout PDU_SIP_Request pl_request, 
  in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  for (var integer i := 0; i < sizeof(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setRequest); i := i + 1)
  {
    v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setRequest[i].func.apply(
      pl_request, pl_ptr, v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setRequest[i].params);
  }

  v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setRequest := {};
}

private function f_EPTF_SIP_applySetResponse(
  in integer pl_userIdx,
  in integer pl_FSMIdx, 
  inout PDU_SIP_Response pl_response, 
  in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  for (var integer i := 0; i < sizeof(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setResponse); i := i + 1)
  {
    v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setResponse[i].func.apply(
      pl_response, pl_ptr, v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setResponse[i].params);
  }

  v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setResponse := {};
}

private function f_EPTF_SIP_applySetTemplateBody(
  in integer pl_userIdx,
  in integer pl_FSMIdx, 
  inout charstring pl_body, 
  inout integer pl_length, 
  in EPTF_LGenBase_TestStepArgs pl_ptr)
runs on EPTF_SIP_LGen_CT
{
  for (var integer i := 0; i < sizeof(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setTemplateBody); i := i + 1)
  {
    v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setTemplateBody[i].func.apply(
      pl_body, pl_length, pl_ptr, v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setTemplateBody[i].params);
  }

  v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].setTemplateBody := {};
}

private function f_SIP_sendRequest(in integer pl_user, in integer pl_UAC, in integer pl_sessionId)
runs on EPTF_SIP_LGen_CT
{
  if(not ispresent(v_db_UAC.data[pl_UAC].request)) {
    f_SIP_Logging_WARNING(%definitionId&": request field not present in UAC.");
    return;
  }

  v_db_UAC.data[pl_UAC].requestRaw := f_EPTF_SIP_sipEncodeRequest(v_db_UAC.data[pl_UAC].request);

  f_SIP_sendRequestRaw(pl_user, pl_UAC, pl_sessionId);
}

private function f_SIP_sendRequestRaw(in integer pl_user, in integer pl_UAC, in integer pl_sessionId)
runs on EPTF_SIP_LGen_CT
{
  if(c_EPTF_Common_debugSwitch and f_SIP_Logging_debugEnabled()) {
    f_SIP_Logging_DEBUG(log2str(
      %definitionId,": user(",pl_user,")", " sessions: ", v_db_users.data[pl_user].sessions));

    f_SIP_Logging_DEBUG(log2str(
      %definitionId,": user(",pl_user,")", "sending session: ", pl_sessionId));
  }
  
  if (c_SIP_TrState_Unknown == v_db_UAC.data[pl_UAC].state)
  {
    f_EPTF_SIP_TransactionState_startUAC(pl_UAC, c_SIP_TimerIdxUAC_Retransmission, c_SIP_TimerIdxUAC_TransactionTimeout);
  }else if (c_SIP_TrState_ProxyUnknown == v_db_UAC.data[pl_UAC].state)
  {
    f_EPTF_SIP_TransactionState_startUAC(pl_UAC, c_SIP_TimerIdxUAC_Retransmission, c_SIP_TimerIdxUAC_C);
  }

  var SipUrl vl_routingURI;
  
  f_SIP_selectRoutingURI(v_db_UAC.data[pl_UAC].request, vl_routingURI);
  f_EPTF_SIP_SipUrl2FlatSipUrl(vl_routingURI, v_db_UAC.data[pl_UAC].toAddr);

  f_EPTF_SIP_Message_SendRequest(
      pl_user,
      pl_sessionId,
      v_db_UAC.data[pl_UAC].transport,
      v_db_UAC.data[pl_UAC].requestRaw,
      v_db_UAC.data[pl_UAC].toAddr,
      v_db_UAC.data[pl_UAC].request);
}


private function f_SIP_sendResponse(in integer pl_user, in integer pl_UAS)
runs on EPTF_SIP_LGen_CT
{
  v_db_UAS.data[pl_UAS].responseRaw := f_EPTF_SIP_sipEncodeResponse(v_db_UAS.data[pl_UAS].response);
  
  f_EPTF_SIP_Message_SendResponse(
    pl_user,
    v_db_UAS.data[pl_UAS].sessionIdx,
    v_db_UAS.data[pl_UAS].transport,
    v_db_UAS.data[pl_UAS].responseRaw,
    v_db_UAS.data[pl_UAS].via,
    v_db_UAS.data[pl_UAS].connId,
    v_db_UAS.data[pl_UAS].response);

}

private function f_SIP_sendResponseRaw(in integer pl_user, in integer pl_UAS, in integer pl_sessionId)
runs on EPTF_SIP_LGen_CT
{
  if(c_EPTF_Common_debugSwitch and f_SIP_Logging_debugEnabled()) {
    f_SIP_Logging_DEBUG(log2str(
      %definitionId,": user(",pl_user,")", " sessions: ", v_db_users.data[pl_user].sessions));

    f_SIP_Logging_DEBUG(log2str(
      %definitionId,": user(",pl_user,")", "sending session: ", pl_sessionId));
  }

  f_EPTF_SIP_Message_SendResponse(
    pl_user,
    v_db_UAS.data[pl_UAS].sessionIdx,
    v_db_UAS.data[pl_UAS].transport,
    v_db_UAS.data[pl_UAS].responseRaw,
    v_db_UAS.data[pl_UAS].via,
    v_db_UAS.data[pl_UAS].connId,
    v_db_UAS.data[pl_UAS].response);

}

private function f_SIP_initRegister(in integer pl_userIdx, in integer pl_idIdx, in integer pl_calledUser)
runs on EPTF_SIP_LGen_CT
{
  v_db_users.data[pl_userIdx].regData.cSeq := f_EPTF_SIP_genCSeq();
  
  f_EPTF_SIP_genCallId(pl_userIdx,
    v_db_users.data[pl_userIdx].localHost,
    v_db_users.data[pl_userIdx].regData.callId);

  if (0 <= pl_calledUser)
  {
    if (omit == v_db_users.data[pl_userIdx].regData.registrar)
    {
      var Addr_Union vl_addr;
      f_EPTF_SIP_getCalledUser_addr(pl_userIdx, pl_calledUser, vl_addr);
      f_EPTF_SIP_GetRequestUri(
        vl_addr,
        v_db_users.data[pl_userIdx].regData.registrar);
    }
    v_db_users.data[pl_userIdx].regData.toIdx.calledUser := pl_calledUser;
  }else{
    if (omit == v_db_users.data[pl_userIdx].regData.registrar)
    {
      var Addr_Union addr;
      f_EPTF_SIP_getUserData_id_addr(pl_userIdx, pl_idIdx, addr);
      f_EPTF_SIP_GetRequestUri(addr, v_db_users.data[pl_userIdx].regData.registrar);
    }
    v_db_users.data[pl_userIdx].regData.toIdx.userId := pl_idIdx;
  }
}

private function f_EPTF_SIP_cleanUp(in integer pl_userIdx, in integer pl_FSMIdx, in boolean pl_ignore := false)
runs on EPTF_SIP_LGen_CT
{
  if(c_EPTF_Common_debugSwitch and f_SIP_Logging_debugEnabled()) {
    f_SIP_Logging_DEBUG(log2str(%definitionId,": FSM database: ",v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx]));
  }
  
  f_EPTF_SIP_CancelAllTimers_FSM(pl_userIdx, pl_FSMIdx);

  f_EPTF_SIP_cleanUpTransactions(pl_userIdx, pl_FSMIdx);

  if (f_EPTF_SIP_checkPublish(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].publishIdx))
  {
    f_EPTF_SIP_removePublish(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].publishIdx);
  }

  if (f_EPTF_SIP_checkDialog(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].dialogIdx))
  {
    if (f_EPTF_SIP_checkSubscription(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].subscriptionIdx))
    {
      f_EPTF_SIP_removeSubscription(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].subscriptionIdx, 
                                      v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].dialogIdx);
    }

    f_EPTF_SIP_removeDialog(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].dialogIdx, pl_ignore);
  }else{
    if (f_EPTF_SIP_checkSubscription(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].subscriptionIdx))
    {
      f_EPTF_SIP_removeSubscription(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].subscriptionIdx, 
                                      -1);
    }
  }
}

///////////////////////////////////////////////////////////
//  Function: f_EPTF_SIP_check4xxRetryInDialog
// 
//  Purpose:
//    Checks if the next call-id should be generated or not.
// 
//  Parameters:
//    pl_method - *in* <Method> - the next method
//    pl_userIdx - *in* *integer* - the index of the SIP user
//    pl_FSMIdx - *in* *integer* - the index of the FSM context
//    pl_callId - *inout* <CallidString> - the calculated call-id
//    pl_cSeq - *inout* *integer* - the calculated cSeq
// 
//  Detailed comments:
//    If the request is a retry for a previous 4xx response
//    the call-id is re-used and the cSeq is incremented by one.
////////////////////////////////////////////////////////////
private function f_EPTF_SIP_check4xxRetry(
  in Method pl_method,
  in integer pl_userIdx,
  in integer pl_FSMIdx,
  inout CallidString pl_callId,
  inout integer pl_cSeq
  )
runs on EPTF_SIP_LGen_CT
{
  if (v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest.method != pl_method)
  {//initial MESSAGE
    f_EPTF_SIP_genCallId(pl_userIdx,
      v_db_users.data[pl_userIdx].localHost,
      pl_callId);
    pl_cSeq := f_EPTF_SIP_genCSeq();
  } else {
    pl_callId := v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest.callId;
    pl_cSeq := f_EPTF_SIP_increaseCSeq(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest.cSeq);    
  }
  v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest := cg_SIP_RetryRequest;
}

///////////////////////////////////////////////////////////
//  Function: f_EPTF_SIP_check4xxRetryInDialog
// 
//  Purpose:
//    Checks in dialog if the next call-id should be generated or not.
// 
//  Parameters:
//    pl_method - *in* <Method> - the next method
//    pl_userIdx - *in* *integer* - the index of the SIP user
//    pl_dialog - *in* *integer* - the index of the dialog
//    pl_FSMIdx - *in* *integer* - the index of the FSM context
// 
//  Detailed comments:
//    If the request is a retry for a previous 4xx response
//    the call-id is re-used and the cSeq is incremented by one.
////////////////////////////////////////////////////////////
private function f_EPTF_SIP_check4xxRetryInDialog(
    in Method pl_method,
    in integer pl_userIdx,
    in integer pl_dialog,
    in integer pl_FSMIdx
) 
runs on EPTF_SIP_LGen_CT {
    if (v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest.method == pl_method) {
    // Retry for 4xx response
    v_db_users.data[pl_userIdx].cSeq := f_EPTF_SIP_increaseCSeq(v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest.cSeq);
    v_db_dialog.data[pl_dialog].localSeqNum := v_db_users.data[pl_userIdx].cSeq;
    v_db_dialog.data[pl_dialog].initSeqNum := v_db_dialog.data[pl_dialog].localSeqNum;
    v_db_dialog.data[pl_dialog].callId := v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest.callId;
  } else {
    v_db_users.data[pl_userIdx].cSeq := v_db_dialog.data[pl_dialog].localSeqNum;
  }
  v_db_users.data[pl_userIdx].FSMs.data[pl_FSMIdx].retryRequest := cg_SIP_RetryRequest; 
}

///////////////////////////////////////////////////////////
//  Function: f_EPTF_SIP_prepareOptionsTag
// 
//  Purpose:
//    The function prepares the option tags list for the
//    Require header and the related extraHeaders external template
// 
//  Parameters:
//    pl_add100rel - *in* *integer* - indicator of 100rel options tag required or not
//    pl_addPrecond - *in* *integer* - indicator of precondition options tag required or not
//    pl_disableExtTemplates - *in* *integer* - indicator of external templates disabled or not
//    pl_optionsTags - *in* <OptionTag_List> - options tag list
//    pl_extraHeaders - *in* *charstring* - extraHeader external template value
// 
//  Detailed comments:
//    pl_optionsTags must be an initialized list.
//    pl_extraHeaders must be an initialized charstring
////////////////////////////////////////////////////////////
private function f_EPTF_SIP_prepareOptionsTag(
  in integer pl_add100rel,
  in integer pl_addPrecond,
  in integer pl_disableExtTemplates,
  inout OptionTag_List pl_optionsTags,
  inout charstring pl_extraHeaders)
{
  var integer vl_optId := 0;

  if (1 == pl_add100rel) { 
    pl_optionsTags[vl_optId] := c_SIP_EXT_100REL; 
    if (pl_disableExtTemplates != -1) {      
      if (vl_optId > 0) { pl_extraHeaders := pl_extraHeaders & ", " & c_SIP_EXT_100REL; } 
      else { pl_extraHeaders := c_SIP_EXT_100REL; }
    }
    vl_optId := vl_optId + 1; 
  }
  if (1 == pl_addPrecond) { 
    pl_optionsTags[vl_optId] := c_SIP_EXT_PRECONDITION; 
    if (pl_disableExtTemplates != -1) {            
      if (vl_optId > 0) { pl_extraHeaders := pl_extraHeaders & ", " & c_SIP_EXT_PRECONDITION; } 
      else { pl_extraHeaders := c_SIP_EXT_PRECONDITION; }
    }
    vl_optId := vl_optId + 1; 
  }
}

}//end of module
with {
extension "version <RnXnn>"
}

