Rev

Rev 205 | Rev 209 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | SVN | Bug Tracker

/**
 * @author STF471
 * @version $Id: LibIms_Steps.ttcn 207 2014-08-21 10:09:05Z rennoch $
 * @desc This module provides the steps used by the test component for SIP-IMS tests.
 *       This module is part of LibImsV3.
 */

module LibIms_Steps {
    // LibSip
    import from LibSip_SIPTypesAndValues all;
    import from LibSip_Templates all;
    import from LibSip_Steps all;
    import from LibSip_PIXITS all;
    import from LibSip_Interface all;
    import from LibSip_MessageBodyTypes all;
    // LibIms
    import from LibIms_Templates all;
    import from LibIms_Interface all;
    import from LibIms_SIPTypesAndValues all;

    group externalfunctions {
    } // end group externalfunctions
    group parameterOperations {

        /**
         * @desc Adds new Via parameter
         * @param p_message (request) SIP message to be used to prepair via header
         */

        function f_addNewViaParameter(
            in Request p_message
        ) runs on ImsComponent  {
            var integer v_intVia;
            var integer i := 0;
            if (isvalue(p_message.msgHeader.via)) {

                v_intVia := lengthof(p_message.msgHeader.via.viaBody);
                while (i < v_intVia) {
                    p_message.msgHeader.via.viaBody[v_intVia] := p_message.msgHeader.via.viaBody[v_intVia - 1];
                    v_intVia := v_intVia - 1;
                }
                vc_branch := c_branchCookie & f_getRndTag();
                p_message.msgHeader.via.viaBody[0] := valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile));
                vc_via := p_message.msgHeader.via;
            }
        }

        /**
         * @desc Removes own Via parameter
         * @param p_message (request) SIP message to be used to prepair via header
         */

        function f_removeOwnViaParameter(
            in Response p_message
        ) runs on ImsComponent  {
            var integer v_intVia;
            var Via v_via := c_empty_Via;
            var integer i := 0;

            if (ispresent(p_message.msgHeader.via)) {

                v_intVia := lengthof(p_message.msgHeader.via.viaBody) - 1;

                for (i := 0; i < v_intVia; i := i + 1) {
                    v_via.viaBody[i] := p_message.msgHeader.via.viaBody[i + 1];
                }
                vc_via := v_via;
            }
        }

        /**
         * @desc Adds new RecordRoute parameter and removes Route parameter
         * @param p_message (request) SIP message to be used to prepair via header
         */

        function f_addNewRecordRouteAndRemoveRoutParameter(
            in Request p_message
        ) runs on ImsComponent  {
            var integer v_intRoute, v_intRecordRoute;
            var integer i := 1;
            var RouteBody v_route1;
            var Route v_newRoute;
            v_newRoute.fieldName := ROUTE_E;
            if (isvalue(p_message.msgHeader.route)) {
                v_intRoute := lengthof(p_message.msgHeader.route.routeBody);
                v_route1 := p_message.msgHeader.route.routeBody[0];
                while (i < v_intRoute) {
                    v_newRoute.routeBody[i - 1] := p_message.msgHeader.route.routeBody[i];
                    i := i + 1;
                }
                vc_route := v_newRoute;
            }

            if (isvalue(p_message.msgHeader.recordRoute)) {

                v_intRecordRoute := lengthof(p_message.msgHeader.recordRoute.routeBody);
                while (0 < v_intRecordRoute) {
                    p_message.msgHeader.recordRoute.routeBody[v_intRecordRoute] := p_message.msgHeader.recordRoute.routeBody[v_intRecordRoute - 1];
                    v_intRecordRoute := v_intRecordRoute - 1;
                }
                p_message.msgHeader.recordRoute.routeBody[0] := v_route1;
                vc_recordRoute := valueof(p_message.msgHeader.recordRoute);
            }
        }

        /**
         * @desc Adds new RecordRoute parameter (IMS)
         * @param p_rr The recordRoute parameter to add
         */

        function f_addNewRecordRouteIMS(
            in RecordRoute p_rr
        ) runs on ImsComponent
        return template RecordRoute  {
            var integer v_intRecordRoute;
            var template RecordRoute v_recordRoute := omit;

            v_intRecordRoute := lengthof(p_rr.routeBody);
            if (v_intRecordRoute > 0) {
                while (0 < v_intRecordRoute) {
                    p_rr.routeBody[v_intRecordRoute] := p_rr.routeBody[v_intRecordRoute - 1];
                    v_intRecordRoute := v_intRecordRoute - 1;
                }
                p_rr.routeBody[0] := valueof(m_routeBody_currIpAddr(vc_userprofile));
                vc_recordRoute := p_rr;
                return vc_recordRoute;
            }
            else {
                return (v_recordRoute);
            }
        }

    } // end group parameterOperations

    group fieldOperations {

        /**
         * @desc Sets BYE header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersBYE(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            vc_route := f_route(); // update the route header field depending on vc_boo_route
            vc_recordRoute := f_recordroute(); // update the route header field depending on vc_boo_route
            LibSip_Steps.f_setHeadersBYE(p_cSeq_s);
        } // end f_setHeadersBYE

        /**
         * @desc Sets CANCEL header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         */

        function f_setHeadersCANCEL(
            inout CSeq p_cSeq_s
        ) runs on ImsComponent  {
            vc_route := f_route(); // update the route header field depending on vc_boo_route
            vc_recordRoute := f_recordroute(); // update the route header field depending on vc_boo_route
            LibSip_Steps.f_setHeadersCANCEL(p_cSeq_s);
        } // end f_setHeadersCANCEL

        /**
         * @desc Sets headers for forward request from AS in case if AS acts as Proxy
         * @param p_cSeq_s The current cSeq
         * @param p_proxyMode true = proxyMode, false = B2BMode
         */

        function f_setHeadersForwardRequestFromAS(
            inout CSeq p_cSeq_s,
            boolean p_proxyMode
        ) runs on ImsComponent  {
            var Request v_request;
            v_request := vc_request;

            if (p_proxyMode) {
                vc_requestUri2 := v_request.requestLine.requestUri;
                vc_to := v_request.msgHeader.toField;
                vc_contact := v_request.msgHeader.contact;
                f_addNewViaParameter(v_request);
                f_addNewRecordRouteAndRemoveRoutParameter(v_request);
            }
            else {
                // B2Bmode
                vc_contact := m_Contact(m_SipUrl_contactIpaddr(vc_userprofile));
                vc_callId := {
                    fieldName := CALL_ID_E,
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
                };
            }
        } // end function f_setHeadersForwardRequest

        /**
         * @desc Sets header fields for forward request from AS in case if AS acts as Proxy
         */

        function f_setHeadersForwardResponseFromAS(
        ) runs on ImsComponent  {
            var Response v_response;
            v_response := vc_response;

            vc_caller_To := v_response.msgHeader.toField;
            vc_to := v_response.msgHeader.toField;
            vc_contact := v_response.msgHeader.contact;

            if (ispresent(v_response.msgHeader.recordRoute)) {
                vc_recordRoute := v_response.msgHeader.recordRoute;
            }
            f_removeOwnViaParameter(v_response);
        } // end function f_setHeadersForwardResponse

        /**
         * @desc Sets Invite header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersINVITE(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            vc_to := f_initToHeader(p_to_user); // init of vc_to using userProfile identifier
            vc_from := f_initFromHeader(p_to_user, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            if (vc_boo_route) {
                vc_route := m_route_interface(vc_interfaceprofile);
            }
            if (vc_boo_recordRoute) {
                vc_recordRoute := m_recordRoute_currIpAddr(vc_userprofile);
            }

            LibSip_Steps.f_setHeadersINVITE(p_cSeq_s);
        } // end f_setHeadersINVITE

        /**
         * @desc Sets Invite header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersUPDATE(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            vc_to := f_initToHeader(p_to_user); // init of vc_to using userProfile identifier
            vc_from := f_initFromHeader(p_to_user, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            if (vc_boo_route) {
                vc_route := m_route_interface(vc_interfaceprofile);
            }
            if (vc_boo_recordRoute) {
                vc_recordRoute := m_recordRoute_currIpAddr(vc_userprofile);
            }

            LibSip_Steps.f_setHeadersUPDATE(p_cSeq_s);
        } // end f_setHeadersUPDATE

        /**
         * @desc Sets Message header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersMESSAGE(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            vc_to := f_initToHeader(p_to_user); // init of vc_to using userProfile identifier
            vc_from := f_initFromHeader(p_to_user, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            LibSip_Steps.f_setHeadersMESSAGE(p_cSeq_s);
        } // end f_setHeadersMESSAGE

        /**
         * @desc Sets Notify header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersNOTIFY(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            LibSip_Steps.f_setHeadersNOTIFY(p_cSeq_s);

            vc_branch := c_branchCookie & f_getRndTag();
            vc_via := {
                fieldName := VIA_E,
                viaBody := {valueof(m_ViaBody_virtual_XCSCF(vc_branch, vc_userprofile))}
            };

            vc_to := f_initToHeader(p_to_user); // init of vc_to using userProfile identifier
            vc_from := f_initFromHeader(p_to_user, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            // contact header initialization for sending of NOTIFY from CSCF component
            vc_contact := m_Contact(m_SipUrl_currIpaddr_CSCF(vc_userprofile));
        } // end f_setHeadersNOTIFY

        /**
         * @desc Sets Publish header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersPUBLISH(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            LibSip_Steps.f_setHeadersPUBLISH(p_cSeq_s);

            vc_branch := c_branchCookie & f_getRndTag();
            vc_via := {
                fieldName := VIA_E,
                viaBody := {valueof(m_ViaBody_virtual_XCSCF(vc_branch, vc_userprofile))}
            };

            vc_to := f_initToHeader(p_to_user); // init of vc_to using userProfile identifier
            vc_from := f_initFromHeader(p_to_user, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            if (vc_boo_route) {
                vc_route := m_route_interface(vc_interfaceprofile);
            }
            if (vc_boo_recordRoute) {
                vc_recordRoute := m_recordRoute_currIpAddr(vc_userprofile);
            }

            // contact header initialization for sending of PUBLISH from CSCF component
            vc_contact := m_Contact(m_SipUrl_currIpaddr_CSCF(vc_userprofile));
        } // end f_setHeadersPUBLISH

        /**
         * @desc Sets Subscribe header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersSUBSCRIBE(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            vc_to := {
                fieldName := TO_E,
                addressField := {
                    nameAddr := {
                        displayName := omit,  // optional charstring
                        addrSpec := p_to_user // SipUrl
                    }
                },  // end addressField
                toParams := omit
            };
            vc_from := f_initFromHeader(p_to_user, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            LibSip_Steps.f_setHeadersSUBSCRIBE(p_cSeq_s);
        } // end f_setHeadersSUBSCRIBE

        /**
         * @desc Sets headers for ReINVITE method
         * @param p_cSeq_s The current cSeq
         * @param p_orginatingSide true in case of Re-INVITE is send from the orgination endpoint otherwise false.
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersReINVITE(
            inout CSeq p_cSeq_s,
            in boolean p_orginatingSide,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            var integer v_tmp, i, j, v_nbroute;
            var Request v_request;
            v_request := vc_request;

            f_setHeadersGeneral(p_cSeq_s, "INVITE"); // cseq, contact, branch, via
            vc_reqHostPort := vc_requestUri.components.sip.hostPort;

            vc_requestUri := p_to_user;

            if (p_orginatingSide) {
                vc_to := vc_caller_To;
                vc_from := vc_caller_From;
            }
            else {
                vc_to := vc_callee_To;
                vc_from := vc_callee_From;

                // get route from previous ACK request
                // Route Management
                if (isvalue(v_request.msgHeader.recordRoute)) {
                    vc_recordRoute := valueof(v_request.msgHeader.recordRoute);
                    v_nbroute := lengthof(vc_recordRoute.routeBody);
                    // copy and reverse the order of the routes in route header
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
                        j := v_nbroute - 1 - i;
                        vc_route.routeBody[j] := vc_recordRoute.routeBody[i];
                    }
                    vc_route.fieldName := ROUTE_E;
                    vc_boo_recordRoute := true;
                    vc_boo_route := true;
                }
                else {
                    vc_boo_recordRoute := false;
                    vc_boo_route := false;
                }
            }

            v_tmp := str2int(vc_sdp_local.origin.session_id);
            vc_sdp_local.origin.session_id := int2str(v_tmp + 1);
            v_tmp := str2int(vc_sdp_local.origin.session_version);
            vc_sdp_local.origin.session_version := int2str(v_tmp + 1);
        } // end function f_setHeadersReINVITE

        /**
         * @desc Sets component variables related to message header fields when sending requests from the home I-CSCF (TS) to the visited P-CSCF (SUT) (message type independent: CSeq, contact, via), function uses information from userprofile and interfaceprofile
         * @param p_cSeq_s The CSeq parameter
         * @param p_method The method name for cSeq header field
         */

        function f_setHeadersGeneral_ICSCF(
            inout CSeq p_cSeq_s,
            in charstring p_method
        ) runs on SipComponent  {
            p_cSeq_s.fieldName := CSEQ_E;
            p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1;
            p_cSeq_s.method := p_method;
            vc_cSeq := p_cSeq_s;

            vc_contact := m_Contact(m_SipUrl_contactIpaddr(vc_userprofile));

            vc_branch := c_branchCookie & f_getRndTag();
            vc_branch_ICSCF := c_branchCookie & f_getRndTag();

            vc_via := {
                fieldName := VIA_E,
                viaBody := {
                    valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile)),
                    valueof(m_ViaBody_virtualUEinPCSCF(vc_branch_ICSCF, vc_userprofile))
                }
            };
        } // end function f_setHeadersGeneral_ICSCF

        /**
         * @desc Sets header field for the next outgoing REGISTER message from the visited P-CSCF to the home I-CSCF
         * @param p_cSeq_s The CSeq parameter to be applied
         */

        function f_setHeaders_REGISTER_PCSCF(
            inout CSeq p_cSeq_s
        ) runs on SipComponent  {
            var SemicolonParam_List v_params;

            f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via
            vc_requestUri := {
                scheme := c_sipScheme,
                components := {
                    sip := {
                        userInfo := omit,
                        hostPort := {
                            host := vc_userprofile.registrarDomain,
                            portField := omit
                        }
                    }
                },
                urlParameters := omit,
                headers := omit
            };

            vc_reqHostPort := vc_requestUri.components.sip.hostPort;

            vc_callId := {
                fieldName := CALL_ID_E,
                callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
            };
            vc_callIdReg := vc_callId;

            vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
            v_params := {
                {
                    id := c_tagId,
                    paramValue := {
                        tokenOrHost := f_getRndTag()
                    }
                }
            };
            vc_from := {
                fieldName := FROM_E,
                addressField := vc_to.addressField,
                fromParams := v_params
            };

            if (not vc_firstREGISTER_sent) {
                v_params := {
                    {
                        id := c_expiresId,
                        paramValue := {
                            tokenOrHost := c_shortRegistration
                        }
                    }
                };
                vc_contact.contactBody.contactAddresses[0].contactParams := v_params;
            }

            vc_firstREGISTER_sent := true; // f_setHeaders_Register is called in deREGISTER function
            vc_authorization := {
                fieldName := AUTHORIZATION_E,
                body := {f_calculatecCredentials_empty(vc_userprofile)}
            };
        } // end function setHeaders_REGISTER_PCSCF

        /**
         * @desc Sets REFER header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_to_user The selected user's SIP URL
         */

        function f_setHeadersREFER(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user
        ) runs on ImsComponent  {
            vc_requestUri := p_to_user; // Request URI of Invite is identical with To header
            if (vc_boo_route) {
                vc_route := m_route_interface(vc_interfaceprofile);
            }
            if (vc_boo_recordRoute) {
                vc_recordRoute := m_recordRoute_currIpAddr(vc_userprofile);
            }

            LibSip_Steps.f_setHeadersREFER(p_cSeq_s);
        } // end f_setHeadersREFER

        /**
         * @desc Sets REFER header fields (IMS addresses) extension of general settings from LibSip basic function
         * @param p_cSeq_s The current cSeq
         * @param p_uri The SipUrl for request URI and To header
         */

        function f_setHeadersREFER_conf(
            inout CSeq p_cSeq_s,
            in SipUrl p_uri
        ) runs on ImsComponent  {
            vc_to := {
                fieldName := TO_E,
                addressField := {
                    nameAddr := {
                        displayName := omit,  // optional charstring
                        addrSpec := p_uri // SipUrl
                    }
                },  // end addressField
                toParams := omit
            };

            vc_from := f_initFromHeader(p_uri, f_getRndTag()); // init of vc_from using userProfile identifier
            vc_requestUri := p_uri; // Request URI of Invite is identical with To header
            if (vc_boo_route) {
                vc_route := m_route_interface(vc_interfaceprofile);
            }
            if (vc_boo_recordRoute) {
                vc_recordRoute := m_recordRoute_currIpAddr(vc_userprofile);
            }

            LibSip_Steps.f_setHeadersREFER(p_cSeq_s);
        } // end f_setHeadersREFER_conf

    } // end group fieldOperations

    group awaitingMessage {
    }
   
    group sendMessage {

        /**
         * @desc Sends PRACK message
         * @param p_mb The message body of the PRACK message
         * @param p_rack_cseq The cSeq of the PRACK message
         */

        function f_sendPRACK_sdp(
            template(value) MessageBody p_mb,
            CSeq p_rack_cseq
        ) runs on SipComponent  {
            var integer v_responseNum := 1;
            var template(value) PRACK_Request v_prackReq;

            f_setHeadersGeneral(vc_cSeq, "PRACK"); // cseq, contact, branch, via
            if (isvalue(vc_response.msgHeader.rSeq.responseNum)) {
                v_responseNum := vc_response.msgHeader.rSeq.responseNum;
            }
            vc_rAck := m_RAck(v_responseNum, p_rack_cseq.seqNumber, p_rack_cseq.method);

            v_prackReq := m_PRACK_Request_sdp(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via, vc_rAck, p_mb);

            // added route header if required
            if (isvalue(vc_response.msgHeader.recordRoute)) {
                v_prackReq.msgHeader.route := f_route();
            }

            SIPP.send(v_prackReq) to vc_sent_label;
        }

    }
    group globalSteps {

        //NOTE STF471: removed function f_init_userprofile, have to move up to specific ATS

        /**
         * @desc Initializes the To header
         * @param p_user Identifies the selected user's SIP URL
         * @return The To header
         */

        function f_initToHeader(
            in SipUrl p_user
        ) runs on ImsComponent
        return To  {
            var To v_to := c_empty_To;
            v_to := {
                fieldName := TO_E,
                addressField := {
                    nameAddr := {
                        displayName := omit,  // optional charstring
                        addrSpec := p_user // SipUrl
                    }
                },  // end addressField
                toParams := omit
            };
            return (v_to);
        }

        /**
         * @desc Initializes the From header
         * @param p_user Identifies the selected user' SIP URL
         * @param p_tag_str The string value of the tag id
         * @return The From header
         */

        function f_initFromHeader(
            in SipUrl p_user,
            charstring p_tag_str
        ) runs on ImsComponent
        return From  {
            var From v_from := c_empty_From;
            v_from := {
                fieldName := FROM_E,
                addressField := {
                    nameAddr := {
                        displayName := omit,  // optional charstring
                        addrSpec := p_user // SipUrl
                    }
                },  // end addressField
                fromParams := {
                    {
                        id := c_tagId,
                        paramValue := {
                            tokenOrHost := p_tag_str
                        }
                    }
                }
            };
            return v_from;
        }

        //NOTE STF471: removed function f_initSipUrl, have to move up to specific ATS

        //NOTE STF471: removed function f_init_interfaceprofile, have to move up to specific ATS

        /**
         * @desc Retrieves user DomainPort value of the user profile
         * @param p_userProfile Identifies the selected user profile
         * @return The Domain HostPort
         */

        function f_get_userDomainPort(
            in SipUserProfile p_userProfile
        ) runs on ImsComponent
        return HostPort  {
            return
                {
                    p_userProfile.homeDomain,
                    p_userProfile.currPort
                };
        }

        /**
         * @desc Retrieves HostPort value of the interface profile
         * @param p_interface Identifies the selected interface
         * @return The HostPort
         */

        function f_get_interfaceHostPort(
            in ImsInterfaceProfile p_interface
        ) runs on ImsComponent
        return HostPort  {
            return
                {
                    p_interface.SUTIpaddr,
                    p_interface.SUTPort
                };
        }

        /**
         * @desc Retrieves DomainPort value of the interface profile
         * @param p_interface Identifies the selected interface
         * @return The Domain HostPort
         */

        function f_get_interfaceDomainPort(
            in ImsInterfaceProfile p_interface
        ) runs on ImsComponent
        return  HostPort  {
            return
                {
                    p_interface.SUTHomeDomain,
                    p_interface.SUTPort
                };
        }

        /**
         * @desc Gets the receive template for the NameAddr of the interface
         * @param p_interface Identifies the selected interface
         * @return The NameAddr template
         */

        function f_get_interfaceNameAddr(
            in ImsInterfaceProfile p_interface
        ) runs on ImsComponent
        return template NameAddr  {
            return mw_SipUrl_SUTinterface(p_interface.SUTIpaddr, p_interface.SUTPort);
        }

    }
   
    group registration {

        /**
         * @desc Registration and authentication
         * @param p_cSeq_s The current cseq
         * @param p_auth flag indicating if authentication is needed
         * @param p_host P-CSCF domain name (formerly value from module parameter PX_IMS_TS_PCSCF_HOME_DOMAIN)
         * @param p_port P-CSCF port number (formerly value from module parameter PX_IMS_TS_PCSCF_PORT)
         */

        function f_Registration_IMS(
            inout CSeq p_cSeq_s,
            in boolean p_auth,
            template(value) charstring p_host,
            template(value) integer p_port
        ) runs on SipComponent  {
            f_setHeaders_REGISTER(p_cSeq_s);
            f_SendREGISTER(m_REGISTER_Request_IMS(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via_REG, vc_contact, m_add_Authorization_digest(vc_authorization, {c_Integrity_protected_no}), p_host, p_port)); // LibSip
            // awaiting of 401 and sending 2nd REGISTER and awaiting 200 OK REGISTER
            if (p_auth) {
                // receiving 401 Unauthorized response.
                // and Re-send REGISTER request with Authorization header
                tc_ack.start;
                alt {
                    [] SIPP.receive(mw_Response_Base(c_statusLine401, vc_callId, p_cSeq_s)) -> value vc_response {
                        tc_ack.stop;
                        // set headers via, cseq and authorization
                        f_setHeaders_2ndREGISTER(p_cSeq_s);
                        f_SendREGISTER(m_REGISTER_Request_IMS(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via_REG, vc_contact, m_add_Authorization_digest(vc_authorization, {c_Integrity_protected_yes}), p_host, p_port)); // LibSip
                        // awaiting 200 OK REGISTER
                        f_awaitingOkResponse(p_cSeq_s);
                        f_getServiceRouteMapIntoRouteInRegistration(vc_response);
                    }
                    [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, p_cSeq_s)) {
                        tc_ack.stop;
                        log("*** " & __SCOPE__ & ": INCONC: Authorization was not requested as expected ***");
                        setverdict(inconc);
                    }
                }
            }
            else {
                f_awaitingOkResponse(p_cSeq_s);
                f_getServiceRouteMapIntoRouteInRegistration(vc_response);
            }
        } // end function f_Registration_IMS

        /**
         * @desc awaiting UE1 registration (with authentication)
         * @param p_cSeq_s The current cseq
         * @param p_to_user The selected user's SIP URL
         * @param p_qop of the peer UE (alternatively)
         * @param p_register The expected REGISTER_Request - default: mw_REGISTER_authorizedRequest_IMS
         */

        function f_awaitingRegistration_IMS(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user,
            in charstring p_qop,
            in template(present) REGISTER_Request p_register :=
                mw_REGISTER_authorizedRequest_IMS(
                    mw_Authorization_digest(
                        mw_digestResponse(
                            (c_Integrity_protected_yes, c_Integrity_protected_ip_assoc_pending)
                        )
                    )
                )
        ) runs on ImsComponent  {
            var SipUrl v_passociated_url;
           
            // Awaiting 1st REGISTER
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);

            // 401 response
            f_sendResponse(
                m_Response_WWWauthenticate_IMS(
                    c_statusLine401,
                    vc_callId,
                    p_cSeq_s,
                    vc_caller_From,
                    vc_caller_To,
                    vc_via,
                    m_wwwAuthenticate(
                        f_calculatecChallenge_forWWWAuthorization(
                            p_qop,
                            valueof(vc_authorization.body[0].digestResponse)
                        )
                    )
                )
            );

            // Awaiting 2nd REGISTER with authorization header
            f_awaitingREGISTER(p_register);

            // 200OK to complete the request
            if (isvalue(vc_request.msgHeader.contact)) {
                vc_contact := valueof(vc_request.msgHeader.contact);
                vc_contact.contactBody.contactAddresses[0].contactParams := {
                    {
                        "expires",
                        {
                            tokenOrHost := int2str(3600)
                        }
                    }
                };
            }
            v_passociated_url := vc_caller_From.addressField.nameAddr.addrSpec;
            f_sendResponse(m_Response_2xxonREGISTER_IMS(c_statusLine200, vc_callId, p_cSeq_s, vc_callee_From, vc_callee_To, vc_via, vc_contact, p_to_user, v_passociated_url));
        } // end function f_awaitingRegistration_IMS

        /**
         * @desc Awaiting UE1 registration (with authentication, without security headers)
         * @param p_cSeq_s The current cseq
         * @param p_to_user The selected user's SIP URL
         * @param p_qop of the peer UE (alternatively)
         */

        function f_awaitingRegistration_IMS_gm(
            inout CSeq p_cSeq_s,
            in SipUrl p_to_user,
            in charstring p_qop
        ) runs on ImsComponent  {
            vc_ignore_subscribe := true; // handle SUBSCRIBE during the call
           
            f_awaitingRegistration_IMS(p_cSeq_s, p_to_user, p_qop, mw_REGISTER_authorizedRequest_wo_securityheaders_IMS);
           
            vc_DeregDone := false;
        } // end function f_awaitingRegistration_IMS_gm

        /**
         * @desc Remove registration
         * @param p_cSeq_s The current cseq
         * @param p_host P-CSCF domain name (formerly value from module parameter PX_IMS_TS_PCSCF_HOME_DOMAIN)
         * @param p_port P-CSCF port number (formerly value from module parameter PX_IMS_TS_PCSCF_PORT)
         */

        function f_removeRegistration_IMS(
            inout CSeq p_cSeq_s,
            template(value) charstring p_host,
            template(value) integer p_port
        ) runs on SipComponent  {
            var template(value) REGISTER_Request v_request;

            if (PX_SIP_REGISTRATION) {
                f_setHeaders_deREGISTER(p_cSeq_s);
                v_request := m_REGISTER_Request_expires_IMS(vc_requestUri, vc_callIdReg, p_cSeq_s, vc_from, vc_to, vc_via, vc_contact, vc_authorization, p_host, p_port, "0");
                v_request.msgHeader.route := f_route();

                f_SendREGISTER(v_request);
                if (PX_SIP_REGISTER_AUTHENTICATION_ENABLED) {
                    // receiving 401 Unauthorized response.
                    // and Re-send REGISTER request with Authorization header
                    tc_ack.start;
                    alt {
                        [] SIPP.receive(mw_Response_Base(c_statusLine401, vc_callIdReg, p_cSeq_s)) -> value vc_response {
                            tc_ack.stop;
                            // set headers via, cseq and authorization
                            f_setHeaders_2ndREGISTER(p_cSeq_s);
                            v_request := m_REGISTER_Request_expires_IMS(vc_requestUri, vc_callIdReg, p_cSeq_s, vc_from, vc_to, vc_via, vc_contact, vc_authorization, p_host, p_port, "0");
                            v_request.msgHeader.route := f_route();
                            // Re-send protected REGISTER
                            f_SendREGISTER(v_request); // LibSip
                            // awaiting 200 OK REGISTER
                            f_awaitingResponse(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq_s));
                        }
                        [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq_s)) -> value vc_response {
                            tc_ack.stop;
                            f_setHeadersOnReceiptOfResponse(vc_response);
                            log("*** " & __SCOPE__ & ": INFO: Authorization was not requested as expected ***");
                        }
                    }
                }
                else {
                    f_awaitingResponse(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq_s));
                }
            }
        } // end f_RemoveRegistration_IMS

    } // end group registration

    group preambles {

        /**
         * @desc Sets variables and default initialization for user profile where proxy role is present
         * @param p_userprofile User profile of call
         * @param p_cSeq_s The current cseq
         */

        function f_IMS_preamble_MGCF(
            inout CSeq p_cSeq_s
        ) runs on ImsComponent  {
            vc_boo_recordRoute := true;
            vc_boo_route := true;
            //NOTE STF471: removed f_init_interfaceprofile(c_interfaceProfile_IMS_SUT_MGCF);

            f_IMS_preamble_woRegistration(p_cSeq_s);
        }

        /**
         * @desc Sets variables and default initialization for user profile
         * @param p_cSeq_s The current cseq
         */

        function f_IMS_preamble_woRegistration(
            inout CSeq p_cSeq_s
        ) runs on ImsComponent  {
            // avoid deregistration in default behavior
            vc_DeregDone := true;
            vc_boo_route := true;
            vc_boo_recordRoute := true;

            // Variables & defaults initialization
            LibSip_Steps.f_init_component(p_cSeq_s);

            // Preamble
            //NOTE STF471: removed f_init_userprofile(p_userprofile); // assignment of PIXIT values to component variable
            vc_sdp_local := valueof(m_SDP_bandwidth(m_media_dynPT(PX_SIP_SDP_DYN, PX_SIP_SDP_ENCODING, PX_SIP_SDP_CLOCKRATE, omit), vc_userprofile));
            vc_contact := m_Contact(m_SipUrl_contactIpaddr(vc_userprofile));
        }

        //NOTE STF471 added
        /**
         * @desc Sets variables and default initialization for user profile
         * @param p_cSeq_s The current cseq
         */

        function f_IMS_preamble_woRegistration_as(
            inout CSeq p_cSeq_s
        ) runs on ImsComponent  {
            // avoid deregistration in default behavior
            vc_DeregDone := true;
            vc_boo_route := true;
            vc_boo_recordRoute := true;

            // Variables & defaults initialization
            LibSip_Steps.f_init_component(p_cSeq_s);

            // Preamble
            //NOTE STF471: removed f_init_userprofile(p_userprofile); // assignment of PIXIT values to component variable
            vc_sdp_local := valueof(m_SDP_bandwidth(m_media_dynPT(PX_SIP_SDP_DYN, PX_SIP_SDP_ENCODING, PX_SIP_SDP_CLOCKRATE, omit), vc_userprofile));
        }

        /**
         * @desc Sets variables and default initialization for user profile and handle registration and authentication with MD5
         * @param p_cSeq_s The current cseq
         * @param p_register Register template
         */

        function f_IMS_preamble_withEmergencyRegistration(
            inout CSeq p_cSeq_s,
            template REGISTER_Request p_register
        ) runs on ImsComponent  {

            //NOTE STF471: removed f_init_interfaceprofile(p_interface);
            // Variables & defaults initialization
            f_IMS_preamble_woRegistration(p_cSeq_s);
            // Preamble
            f_Registration(p_cSeq_s, p_register, PX_SIP_REGISTER_AUTHENTICATION_ENABLED, true);

            // deregistration in case of successful registration
            vc_DeregDone := false;
        }

        /**
         * @desc Sets variables and default initialization for user profile and handle registration and authentication with MD5
         * @param p_cSeq_s The current cseq
         * @param p_register Register template
         */

        function f_IMS_preamble_withRegistration(
            inout CSeq p_cSeq_s,
            out template REGISTER_Request p_register
        ) runs on ImsComponent  {

            //NOTE STF471: removed f_init_interfaceprofile(p_interface);
            // Variables & defaults initialization
            f_IMS_preamble_woRegistration(p_cSeq_s);

            // Preamble
            f_Registration(p_cSeq_s, p_register, PX_SIP_REGISTER_AUTHENTICATION_ENABLED);

            // deregistration in case of successful registration
            vc_DeregDone := false;

            f_setHeaders_SUBSCRIBE(p_cSeq_s);
            f_Subscription(p_cSeq_s, m_SUBSCRIBE_Request_UE(vc_requestUri, vc_callId, p_cSeq_s, vc_from, vc_to, vc_via, vc_contact, vc_route_REG));
        }

        //NOTE STF471 added
        /**
         * @desc Sets variables and default initialization for user profile and handle registration and authentication with MD5
         * @param p_cSeq_s The current cseq
         * @param p_register Register template
         */

        function f_IMS_preamble_withRegistrationWoSubscription(
            inout CSeq p_cSeq_s,
            out template REGISTER_Request p_register
        ) runs on ImsComponent  {
            //NOTE STF471: removed f_init_interfaceprofile(p_interface);

            // Variables & defaults initialization
            f_IMS_preamble_woRegistration(p_cSeq_s);

            // Preamble
            f_Registration(p_cSeq_s, p_register, PX_SIP_REGISTER_AUTHENTICATION_ENABLED);

            // deregistration in case of successful registration
            vc_DeregDone := false;
        }

        /**
         * @desc Sets variables and default initialization for user profile and handle registration and authentication with MD5 (basic registration template)
         * @param p_cSeq_s The current cseq
         * @param p_host P-CSCF domain name (formerly value from module parameter PX_IMS_TS_PCSCF_HOME_DOMAIN)
         * @param p_port P-CSCF port number (formerly value from module parameter PX_IMS_TS_PCSCF_PORT)
         */

        function f_IMS_preamble_withRegistrationBasic(
            inout CSeq p_cSeq_s,
            template(value) charstring p_host,
            template(value) integer p_port
        ) runs on ImsComponent  {
            //NOTE STF471: removed f_init_interfaceprofile(p_interface);
            // Variables & defaults initialization
            f_IMS_preamble_woRegistration(p_cSeq_s);

            // Preamble
            f_Registration_IMS(p_cSeq_s, PX_SIP_REGISTER_AUTHENTICATION_ENABLED, p_host, p_port);
            f_setHeaders_SUBSCRIBE(p_cSeq_s);
            f_Subscription(p_cSeq_s, m_SUBSCRIBE_Request_UE(vc_requestUri, vc_callId, p_cSeq_s, vc_from, vc_to, vc_via, vc_contact, vc_route_REG));
        }

        /**
         * @desc Sets variables and default initialization for user profile and handle registration and authentication with MD5 (basic registration template)
         * @param p_cSeq_s The current cseq
         */

        function f_IMS_preamble_AS(
            inout CSeq p_cSeq_s
        ) runs on ImsComponent  {
            // avoid deregistration in default behavior
            vc_DeregDone := true;
            vc_boo_route := true;
            vc_boo_recordRoute := true;
            vc_cSeq := p_cSeq_s;

            // Defaults
            vc_def_catchSyncStop := activate(a_Sip_catchSyncStop());
            vc_default := activate(a_altstep_AS());

            // Preamble
            //NOTE STF471: removed f_init_interfaceprofile(p_interface);
            //NOTE STF471: removed f_init_userprofile(p_userprofile); // assignment of PIXIT values to component variable
            vc_sdp_local := valueof(m_SDP_bandwidth(m_media_dynPT(PX_SIP_SDP_DYN, PX_SIP_SDP_ENCODING, PX_SIP_SDP_CLOCKRATE, omit), vc_userprofile));
            vc_contact := m_Contact(m_SipUrl_contactIpaddr(vc_userprofile));
        }

    } // end group preambles

    group postambles {

        /**
         * @desc Terminates component and handles deregistration
         * @param p_cSeq_s The current cseq
         */

        function f_IMS_postamble_withDeRegistration(
            CSeq p_cSeq_s
        ) runs on ImsComponent  {
            f_RemoveRegistration(p_cSeq_s);
            f_terminate_component();
        }

        /**
         * @desc Terminates component and optionally handles deregistration on AS as TS
         * @param p_deRegistration Handle deregistration?
         */

        function f_IMS_postamble_AS_withDeRegistration(
            boolean p_deRegistration
        ) runs on ImsComponent  {

            if (p_deRegistration == true) {
                f_awaitingREGISTER_sendReply(mw_REGISTER_Request_Base, true);
            }
            f_terminate_component();
        }

        /**
         * @desc Terminates component without registration
         */

        function f_SIP_postamble_IMS1_withoutRegistration(
        ) runs on ImsComponent  {
            f_terminate_component();
        }

        /**
         * @desc Terminates component without de-registration
         */

        function f_IMS_postamble_withoutDeRegistration(
        ) runs on ImsComponent  {
            f_terminate_component();
        }

        /**
         * @desc Terminates component with de-registration
         * @param p_to_user The selected user's SIP URL
         * @param p_qop of the peer UE (alternatively)
         */

        function f_SIP_postamble_IMS1_awaitDeRegistration(
            in SipUrl p_to_user,
            in charstring p_qop
        ) runs on ImsComponent  {
            var SipUrl v_passociated_url;
            // Awaiting 1st REGISTER
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);

            // 401 response
            f_sendResponse(m_Response_WWWauthenticate_IMS(c_statusLine401, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, m_wwwAuthenticate(f_calculatecChallenge_forWWWAuthorization(p_qop, valueof(vc_authorization.body[0].digestResponse)))));

            // Awaiting 2nd REGISTER with authorization header
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);
           
            // 200OK to complete the request
            v_passociated_url := vc_caller_From.addressField.nameAddr.addrSpec;
            f_sendResponse(m_Response_2xxonREGISTER_IMS(c_statusLine200, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact, p_to_user, v_passociated_url));

            f_terminate_component();
        }

        /**
         * @desc Terminates component with de-registration
         * @param p_to_user The selected user's SIP URL
         * @param p_qop of the peer UE (alternatively)
         */

        function f_IMS_postamble_awaitDeRegistration(
            in SipUrl p_to_user,
            in charstring p_qop
        ) runs on ImsComponent  {
            var SipUrl v_passociated_url;
            // Awaiting 1st REGISTER
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);

            // 401 response
            f_sendResponse(m_Response_WWWauthenticate_IMS(c_statusLine401, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, m_wwwAuthenticate(f_calculatecChallenge_forWWWAuthorization(p_qop, valueof(vc_authorization.body[0].digestResponse)))));

            // Awaiting 2nd REGISTER with authorization header
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);
           
            // 200OK to complete the request
            v_passociated_url := vc_caller_From.addressField.nameAddr.addrSpec;
            f_sendResponse(m_Response_2xxonREGISTER_IMS(c_statusLine200, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact, p_to_user, v_passociated_url));

            f_terminate_component();
        }


        /**
         * @desc Awaits de-registration
         * @param p_to_user The selected user's SIP URL
         * @param p_qop of the peer UE (alternatively)
         */

        function f_IMS_awaitDeRegistration(
            in SipUrl p_to_user,
            in charstring p_qop
        ) runs on ImsComponent  {
            var SipUrl v_passociated_url;
            // Awaiting 1st REGISTER
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);

            // 401 response
            f_sendResponse(m_Response_WWWauthenticate_IMS(c_statusLine401, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, m_wwwAuthenticate(f_calculatecChallenge_forWWWAuthorization(p_qop, valueof(vc_authorization.body[0].digestResponse)))));

            // Awaiting 2nd REGISTER with authorization header
            f_awaitingREGISTER(mw_REGISTER_unauthorizedRequest_IMS);
           
            // 200OK to complete the request
            v_passociated_url := vc_caller_From.addressField.nameAddr.addrSpec;
            f_sendResponse(m_Response_2xxonREGISTER_IMS(c_statusLine200, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact, p_to_user, v_passociated_url));
        }

        //NOTE STF471: renamed f_SIP_postamble_UE(1|2)_withoutRegistration to f_SIP_postamble_UE_withoutRegistration
        /**
         * @desc Terminates component without registration
         */

        function f_SIP_postamble_UE_withoutRegistration(
        ) runs on ImsComponent  {
            f_terminate_component();
        }

        /**
         * @desc Sends BYE and awaits response (IMS)
         * @param p_requestUri The Request URI
         * @param p_callId CallId parameter for outgoing BYE
         * @param p_cSeq_s CSeq parameter for outgoing BYE
         * @param p_from From parameter for outgoing BYE
         * @param p_to To parameter for outgoing BYE
         */

        function f_terminateCall_IMS(
            SipUrl p_requestUri,
            CallId p_callId,
            inout CSeq p_cSeq_s,
            From p_from,
            template(value) To p_to
        ) runs on ImsComponent  {
            LibSip_Steps.f_setHeadersBYE(p_cSeq_s);
            // Sending of a BYE request to release the call and expect a final response
            f_SendBYE(m_BYE_Request_IMS(p_requestUri, p_callId, p_cSeq_s, p_from, p_to, vc_via, vc_route));

            tc_resp.start;
            alt {
                [] SIPP.receive(mw_Response_Base(mw_statusLine1xx, p_callId, p_cSeq_s)) {
                    repeat;
                }
                [] SIPP.receive(mw_Response_Base(mw_statusLineFinal, p_callId, p_cSeq_s)) {
                    tc_resp.stop;
                }
            // timeout should be handled in default_alt_step
            }
        } // end function f_terminateCall_IMS

        /**
         * @desc Sends BYE and awaits response (UE)
         * @param p_requestUri The Request URI
         * @param p_callId CallId parameter for outgoing BYE
         * @param p_cSeq_s CSeq parameter for outgoing BYE
         * @param p_from From parameter for outgoing BYE
         * @param p_to To parameter for outgoing BYE
         * @param p_recordRoute RecordRoute parameter for outgoing BYE - default: omit
         */

        function f_terminateCall_UE(
            SipUrl p_requestUri,
            CallId p_callId,
            inout CSeq p_cSeq_s,
            From p_from,
            template(value) To p_to,
            template RecordRoute p_recordRoute := omit
        ) runs on ImsComponent  {
            var Route v_route;
            LibSip_Steps.f_setHeadersBYE(p_cSeq_s);
            // Sending of a BYE request to release the call and expect a final response
            if (ispresent(p_recordRoute)) {
                v_route := {ROUTE_E, valueof(p_recordRoute.routeBody)};
                f_SendBYE(m_BYE_Request_UE(p_requestUri, p_callId, p_cSeq_s, p_from, valueof(p_to), vc_via, v_route));
            }
            else {
                f_SendBYE(m_BYE_Request_UE(p_requestUri, p_callId, p_cSeq_s, p_from, valueof(p_to), vc_via, vc_route));
            }

            tc_resp.start;
            alt {
                [] SIPP.receive(mw_Response_Base(mw_statusLine1xx, p_callId, p_cSeq_s)) {
                    repeat;
                }
                [] SIPP.receive(mw_Response_Base(mw_statusLineFinal, p_callId, p_cSeq_s)) {
                    tc_resp.stop;
                }
            // timeout should be handled in default_alt_step
            }
        } // end function f_terminateCall_UE

        /**
         * @desc Sends BYE and awaits response and De-registration
         * @param p_requestUri The Request URI
         * @param p_callId CallId parameter for outgoing BYE
         * @param p_cSeq_s CSeq parameter for outgoing BYE
         * @param p_from From parameter for outgoing BYE
         * @param p_to To parameter for outgoing BYE
         * @param p_qop of the peer UE (alternatively)
         */

        function f_terminateCall_UE_withDeReg(
            SipUrl p_requestUri,
            CallId p_callId,
            inout CSeq p_cSeq_s,
            From p_from,
            template(value) To p_to,
            in charstring p_qop
        ) runs on ImsComponent  {
            LibSip_Steps.f_setHeadersBYE(p_cSeq_s);
            // Sending of a BYE request to release the call and expect a final response
            f_SendBYE(m_BYE_Request_UE(p_requestUri, p_callId, p_cSeq_s, p_from, p_to, vc_via, vc_route));

            tc_resp.start;
            alt {
                [] SIPP.receive(mw_Response_Base(mw_statusLine1xx, p_callId, p_cSeq_s)) {
                    repeat;
                }
                [] SIPP.receive(mw_Response_Base(mw_statusLineFinal, p_callId, p_cSeq_s)) {
                    tc_resp.stop;
                }
            // timeout should be handled in default_alt_step
            }
            action("Please de-register");
            f_IMS_awaitDeRegistration(p_requestUri, p_qop);
        } // end function f_terminateCall_UE_withDeReg

    }
    group defaults {

        /**
         * @desc Altstep for clearing registration (IMS user)
         * @param p_to_user The selected user's SIP URL
         * @param p_qop of the peer UE (alternatively)
         * @verdict fail for all unexpected branches
         */

        altstep a_clearRegistration_IMSuser(
            in SipUrl p_to_user,
            in charstring p_qop
        ) runs on ImsComponent {
            var Response v_response;
            var Request v_request;
            var CSeq v_cSeq;
            [] any timer.timeout {
                log("*** " & testcasename() & ": FAIL: Timeout while waiting for message. ***");
                setverdict(fail);
                all timer.stop;
                vc_callId := vc_callIdReg;
                action("Please de-register");
                f_IMS_awaitDeRegistration(p_to_user, p_qop);
                f_componentStop();
            }
            // allow repeated INVITEs
            [vc_ignore_invite] SIPP.receive(mw_INVITE_Request_Base) {
                repeat;
            }
            // allow repeated BYEs after ack of the first BYE
            [vc_ignore_bye] SIPP.receive(mw_BYE_Request_Base(?)) {
                repeat;
            }
            [] SIPP.receive(mw_ACK_Request_Base(?)) {
                repeat;
            }
            // allow 100 replies
            [] SIPP.receive(mw_Response_Base(c_statusLine100, ?, ?)) {
                repeat;
            }
            // ignore 181 if flag is set (following TS 183004 §4.5.2.1)
            [vc_ignore181] SIPP.receive(mw_Response_Base(c_statusLine181, vc_callId, vc_cSeq)) -> value v_response sender vc_sent_label {
                v_cSeq := valueof(v_response.msgHeader.cSeq);
                f_setHeadersOnReceiptOfResponse(v_response);
                repeat;
            }
            // according to SIP chap.8.1.3.2
            [] SIPP.receive(mw_Response_Base(c_statusLine183, vc_callId, vc_cSeq)) {
                repeat;
            }
            // ignore 484 if flag is set
            [vc_ignore484] SIPP.receive(mw_Response_Base(c_statusLine484, vc_callId, vc_cSeq)) {
                repeat;
            }
            [vc_ignore4xx] SIPP.receive(mw_Response_Base(mw_statusLine4xx, vc_callId, ?)) -> value v_response sender vc_sent_label {
                v_cSeq := valueof(v_response.msgHeader.cSeq);
                f_setHeadersOnReceiptOfResponse(v_response);
                f_SendACK(m_ACK_Request_route(vc_requestUri, vc_callId, v_response.msgHeader.cSeq, vc_from, vc_to, vc_via, vc_route));
                repeat;
            }
            [vc_ignore200OKinv] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, ?)) {
                repeat;
            }
            [] SIPP.receive(mw_INFO_Request_Base(vc_callId)) -> value v_request sender vc_sent_label {
                f_setHeadersOnReceiptOfRequest(v_request);
                f_send200OK();
                repeat;
            }
            // awaiting of Notify
            [] SIPP.receive(mw_NOTIFY_Request_Base(vc_callId)) -> value v_request sender vc_sent_label {
                f_setHeadersOnReceiptOfRequest(v_request);
                f_send200OK();
                repeat;
            }
            // awaiting of subscribe from UE
            [vc_ignore_subscribe] SIPP.receive(mw_SUBSCRIBE_Request_Base) -> value v_request sender vc_sent_label {
                f_setHeadersOnReceiptOfSUBSCRIBE(v_request);
                f_send200OK();
                repeat;
            }
            // awaiting of subscribe on proxy
            [] SIPP.receive(mw_SUBSCRIBE_Request_Base) -> value v_request sender vc_sent_label {
                f_setHeadersOnReceiptOfRequest(v_request);
                f_sendResponse(m_Response_Contact(c_statusLine200, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact));
                f_SendNOTIFY(m_NOTIFY_Request_contact(v_request.msgHeader.contact.contactBody.contactAddresses[0].addressField.nameAddr.addrSpec, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact));
                f_awaitingOkResponse(vc_cSeq);
                repeat;
            }
            // unexpected BYE is acknowledged to avoid retransmissions
            [] SIPP.receive(mw_BYE_Request_Base(?)) -> value v_request sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected BYE message received. ***");
                setverdict(fail);
                f_setHeadersOnReceiptOfRequest(v_request);
                f_send200OK();
                action("Please de-register");
                f_IMS_awaitDeRegistration(p_to_user, p_qop);
                f_componentStop();
            }
            // unexpected CANCEL is acknowledged to avoid retransmissions
            [] SIPP.receive(mw_CANCEL_Request_Base(?)) -> value v_request sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected CANCEL message received. ***");
                setverdict(fail);
                f_setHeadersOnReceiptOfRequest(v_request);
                // Answer to the CANCEL
                f_send200OK();
                action("Please de-register");
                f_IMS_awaitDeRegistration(p_to_user, p_qop);
                f_componentStop();
            }
            // catch 4xx response
            [] SIPP.receive(mw_Response_Base(mw_statusLine4xx, vc_callId, ?)) -> value v_response sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected 4xx response received. ***");
                setverdict(fail);
                v_cSeq := valueof(v_response.msgHeader.cSeq);
                f_setHeadersOnReceiptOfResponse(v_response);
                LibSip_Steps.f_setHeadersACK();
                f_SendACK(m_ACK_Request_route(vc_requestUri, vc_callId, v_response.msgHeader.cSeq, vc_from, vc_to, vc_via, vc_route));
                action("Please de-register");
                f_IMS_awaitDeRegistration(p_to_user, p_qop);
                f_componentStop();
            }
            // catch 5xx response
            [] SIPP.receive(mw_Response_Base(mw_statusLine5xx, vc_callId, ?)) -> value v_response sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected 5xx response received. ***");
                setverdict(fail);
                v_cSeq := valueof(v_response.msgHeader.cSeq);
                f_setHeadersOnReceiptOfResponse(v_response);
                LibSip_Steps.f_setHeadersACK();
                f_SendACK(m_ACK_Request_route(vc_requestUri, vc_callId, v_response.msgHeader.cSeq, vc_from, vc_to, vc_via, vc_route));
                action("Please de-register");
                f_IMS_awaitDeRegistration(p_to_user, p_qop);
                f_componentStop();
            }
            // catch invalid REGISTER
            [] SIPP.receive(mw_REGISTER_Request_Base) -> value v_request sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected REGISTER received. ***");
                setverdict(fail);
                f_componentStop();
            }
            // any
            [] SIPP.receive {
                log("*** " & testcasename() & ": FAIL: Unexpected message received. ***");
                setverdict(fail);
                all timer.stop;
                action("Please de-register");
                f_IMS_awaitDeRegistration(p_to_user, p_qop);
                f_componentStop();
            }
        }

        /**
         * @desc Main default altstep to handle unexpected messages and timeout
         * @verdict fail for all unexpected branches
         */

        altstep a_altstep_AS(
        ) runs on SipComponent {
            var Request v_request;
            [] any timer.timeout {
                log("*** " & testcasename() & ": FAIL: Timeout while waiting for message. ***");
                setverdict(fail);
                all timer.stop;
            }
            // allow repeated INVITEs
            [vc_ignore_invite] SIPP.receive(mw_INVITE_Request_Base) {
                repeat;
            }
            // handle REGISTER requests
            [] SIPP.receive(mw_REGISTER_Request_Base) -> value v_request sender vc_sent_label {
                f_setHeadersOnReceiptOfREGISTER(v_request);
                // vc_contact := vc_request.msgHeader.contact;
                f_sendResponse(m_Response_Contact(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, vc_contact));
                repeat;
            }
            // according to SIP chap.8.1.3.2
            [] SIPP.receive(mw_Response_Base(c_statusLine183, vc_callId, vc_cSeq)) {
                repeat;
            }
            // unexpected CANCEL is acknowledged to avoid retransmissions
            [] SIPP.receive(mw_CANCEL_Request_Base(?)) -> value v_request sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected CANCEL message received. ***");
                setverdict(fail);
                f_setHeadersOnReceiptOfRequest(v_request);
                f_send200OK();
            }
            // unexpected BYE is acknowledged to avoid retransmissions
            [] SIPP.receive(mw_BYE_Request_Base(?)) -> value v_request sender vc_sent_label {
                log("*** " & testcasename() & ": FAIL: Unexpected BYE message received. ***");
                setverdict(fail);
                f_setHeadersOnReceiptOfRequest(v_request);
                f_send200OK();
            }
            [] SIPP.receive(mw_Response_Base(?, vc_callId, vc_cSeq)) -> value vc_response {
                log("*** " & testcasename() & ": FAIL: Unexpected response message in " & __SCOPE__ & " received. ***");
                setverdict(fail);
                repeat;
            }
            // any
            [] SIPP.receive {
                log("*** " & testcasename() & ": FAIL: Unexpected message received. ***");
                setverdict(fail);
                all timer.stop;
            }
        }
    }
} // module LibIms_Steps