module SIP_Templates { import from SIPmsg_Types all; /* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */ type record SipAddr { Addr_Union addr, SemicolonParam_List params optional } const charstring c_SIP_VERSION := "SIP/2.0"; template (value) SipUrl ts_SipUrl(charstring user_or_tel, charstring host, integer portnr) := { scheme := "sip", userInfo := { userOrTelephoneSubscriber := user_or_tel, password := omit }, hostPort := { host := host, portField := portnr }, urlParameters := omit, headers := omit } template SipUrl tr_SipUrl(template charstring user_or_tel, template charstring host, template integer portnr) := { scheme := "sip", userInfo := { userOrTelephoneSubscriber := user_or_tel, password := * }, hostPort := { host := host, portField := portnr }, urlParameters := *, headers := * } template (value) SipAddr ts_SipAddr(charstring user_or_tel, charstring host, integer portnr) := { addr := { nameAddr := { displayName := omit, addrSpec := ts_SipUrl(user_or_tel, host, portnr) } }, params := omit } template SipAddr tr_SipAddr(template charstring user_or_tel, template charstring host, template integer portnr) := { addr := { nameAddr := { displayName := *, addrSpec := tr_SipUrl(user_or_tel, host, portnr) } }, params := * } /* build a receive template from a value: substitute '*' for omit */ function tr_SipAddr_from_val(SipAddr tin) return template SipAddr { var template SipAddr ret := tin; if (tin.addr.nameAddr.displayName == omit) { ret.addr.nameAddr.displayName := *; } if (tin.addr.nameAddr.addrSpec.userInfo.password == omit) { ret.addr.nameAddr.addrSpec.userInfo.password := *; } if (tin.params == omit) { ret.params := *; } return ret; } function tr_HostPort(template HostPort hp) return template HostPort { var template HostPort hpout := hp; /* if the port number is 5060, it may be omitted */ if (isvalue(hp.portField) and valueof(hp.portField) == 5060) { hpout.portField := 5060 ifpresent; } return hpout; } template (value) RequestLine ts_SIP_ReqLine(Method method, template (value) SipUrl uri, charstring ver := c_SIP_VERSION) := { method := method, requestUri := uri, sipVersion := ver } template RequestLine tr_SIP_ReqLine(template Method method, template SipUrl uri, template charstring ver := c_SIP_VERSION) := { method := method, requestUri := uri, sipVersion := ver } template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := { sipVersion := "SIP/2.0", statusCode := status_code, reasonPhrase := reason } template StatusLine tr_SIP_StatusLine(template integer status_code, template charstring reason) := { sipVersion := "SIP/2.0", statusCode := status_code, reasonPhrase := reason } template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := { requestLine := rl, msgHeader := c_SIP_msgHeader_empty, messageBody := omit, payload := omit } const Method_List c_SIP_defaultMethods := { "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE", "NOTIFY", "REFER", "UPDATE" }; private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body) return template (omit) ContentType { /* if user explicitly stated no content type */ if (istemplatekind(ct, "omit")) { return omit; } /* if there's no body, then there's no content-type either */ if (istemplatekind(body, "omit")) { return omit; } return ct; } template (value) ContentType ts_CT_SDP := { fieldName := CONTENT_TYPE_E, mediaType := "application/sdp" }; template (value) Via ts_Via_from(SipAddr from_addr) := { fieldName := VIA_E, viaBody := { { sentProtocol := { "SIP", "2.0", "UDP" }, sentBy := from_addr.addr.nameAddr.addrSpec.hostPort, viaParams := omit } } } template (value) MessageHeader ts_SIP_msgHeader_empty :=c_SIP_msgHeader_empty; template (value) MessageHeader ts_SIP_msgh_std( CallidString call_id, SipAddr from_addr, SipAddr to_addr, template (omit) SipAddr contact_addr, charstring method, integer seq_nr, template (value) Via via, template (omit) ContentType content_type := omit, Method_List allow_methods := c_SIP_defaultMethods ) modifies ts_SIP_msgHeader_empty := { allow := { fieldName := ALLOW_E, methods := allow_methods }, callId := { fieldName := CALL_ID_E, callid := call_id }, contact := ts_Contact(contact_addr), contentType := content_type, cSeq := { fieldName := CSEQ_E, seqNumber := seq_nr, method := method }, fromField := { fieldName := FROM_E, addressField := from_addr.addr, fromParams := from_addr.params }, toField := { fieldName := TO_E, addressField := to_addr.addr, toParams := to_addr.params }, userAgent := { fieldName := USER_AGENT_E, userAgentBody := { "osmo-ttcn3-hacks/0.23" } }, via := via } private function tr_Contact(template SipAddr contact_addr) return template Contact { if (istemplatekind(contact_addr, "omit")) { return omit; } else if (istemplatekind(contact_addr, "*")) { return *; } else if (istemplatekind(contact_addr, "?")) { return ?; } var template Contact ret := { fieldName := CONTACT_E, contactBody := { contactAddresses := { { addressField := contact_addr.addr, contactParams := contact_addr.params } } } }; return ret; } private function ts_Contact(template (omit) SipAddr contact_addr) return template (omit) Contact { if (istemplatekind(contact_addr, "omit")) { return omit; } var template (omit) Contact ret := { fieldName := CONTACT_E, contactBody := { contactAddresses := { { addressField := contact_addr.addr, contactParams := contact_addr.params } } } }; return ret; } function tr_AllowMethods(template Method_List allow_methods) return template Allow { if (istemplatekind(allow_methods, "omit")) { return omit; } else if (istemplatekind(allow_methods, "*")) { return *; } else if (istemplatekind(allow_methods, "?")) { return ?; } var template Allow ret := { fieldName := ALLOW_E, methods := allow_methods } return ret } template MessageHeader tr_SIP_msgh_std( template CallidString call_id, template SipAddr from_addr, template SipAddr to_addr, template SipAddr contact_addr, template charstring method, template ContentType content_type := *, template integer seq_nr := ?, template Method_List allow_methods := * ) modifies t_SIP_msgHeader_any := { allow := tr_AllowMethods(allow_methods), callId := { fieldName := CALL_ID_E, callid := call_id }, contact := tr_Contact(contact_addr), contentType := content_type, cSeq := { fieldName := CSEQ_E, seqNumber := seq_nr, method := method }, fromField := { fieldName := FROM_E, addressField := from_addr.addr, fromParams := from_addr.params }, toField := { fieldName := TO_E, addressField := to_addr.addr, toParams := to_addr.params }, userAgent := *, via := { fieldName := VIA_E, viaBody := { { sentProtocol := { "SIP", "2.0", "UDP" }, sentBy := tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort), viaParams := * } } } } template (value) PDU_SIP_Request ts_SIP_INVITE( CallidString call_id, SipAddr from_addr, SipAddr to_addr, integer seq_nr, template (omit) charstring body ) := { requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec), msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, from_addr, "INVITE", seq_nr, ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)), messageBody := body, payload := omit } template PDU_SIP_Request tr_SIP_INVITE( template CallidString call_id, template SipAddr from_addr, template SipAddr to_addr, template integer seq_nr, template charstring body ) := { requestLine := tr_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec), msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?, "INVITE", *, seq_nr), messageBody := body, payload := omit } template (value) PDU_SIP_Request ts_SIP_BYE( CallidString call_id, SipAddr from_addr, SipAddr to_addr, integer seq_nr, template (omit) charstring body ) := { requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec), msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr, ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)), messageBody := body, payload := omit } template PDU_SIP_Request tr_SIP_BYE( template CallidString call_id, template SipAddr from_addr, template SipAddr to_addr, template integer seq_nr, template charstring body ) := { requestLine := tr_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec), msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", *, seq_nr), messageBody := body, payload := omit } template (value) PDU_SIP_Request ts_SIP_ACK( CallidString call_id, SipAddr from_addr, SipAddr to_addr, integer seq_nr, template (omit) charstring body ) := { requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec), msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, from_addr, "ACK", seq_nr, ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)), messageBody := body, payload := omit } template PDU_SIP_Request tr_SIP_ACK( template CallidString call_id, template SipAddr from_addr, template SipAddr to_addr, template integer seq_nr, template charstring body ) := { requestLine := tr_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec), msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *, "ACK", *, seq_nr), messageBody := body, payload := omit } template (value) PDU_SIP_Response ts_SIP_Response( CallidString call_id, SipAddr from_addr, SipAddr to_addr, charstring method, integer status_code, integer seq_nr, charstring reason, Via via, template (omit) charstring body := omit ) := { statusLine := ts_SIP_StatusLine(status_code, reason), msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr, via, f_ContentTypeOrOmit(ts_CT_SDP, body)), messageBody := body, payload := omit } template PDU_SIP_Response tr_SIP_Response( template CallidString call_id, template SipAddr from_addr, template SipAddr to_addr, template SipAddr contact_addr, template charstring method, template integer status_code, template integer seq_nr := ?, template charstring reason := ?, template charstring body := ? ) := { statusLine := tr_SIP_StatusLine(status_code, reason), msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact_addr, method, *, seq_nr), messageBody := body, payload := omit } }