diff --git a/Makefile b/Makefile index 69cc314..aa99059 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ STATIC_OBJS= \ rose_etsi_cc.o \ rose_etsi_diversion.o \ rose_etsi_ect.o \ + rose_etsi_mwi.o \ rose_other.o \ rose_q931.o \ rose_qsig_aoc.o \ @@ -82,6 +83,7 @@ DYNAMIC_OBJS= \ rose_etsi_cc.lo \ rose_etsi_diversion.lo \ rose_etsi_ect.lo \ + rose_etsi_mwi.lo \ rose_other.lo \ rose_q931.lo \ rose_qsig_aoc.lo \ diff --git a/libpri.h b/libpri.h index 4573daa..35f72b8 100644 --- a/libpri.h +++ b/libpri.h @@ -1523,6 +1523,25 @@ int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan /* Send an MWI deactivate request to a remote location */ int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan); +/*! + * \brief Send a MWI indication on the specified D channel. + * + * \param ctrl D channel controller. + * \param mailbox Controlling party number (NULL if not present). + * \param basic_service Basic service enum (-1 if not present). + * \param num_messages NumberOfMessages (-1 if not present). + * \param caller_id Controlling party privided number (NULL if not present). + * \param timestamp Generalized Time format (NULL if not present). + * \param message_reference Message reference number (-1 if not present). + * \param message_status Message status: added(0), removed(1). + * + * \retval 0 on success. + * \retval -1 on error. + */ +int pri_mwi_indicate(struct pri *ctrl, const struct pri_party_id *mailbox, + int basic_service, int num_messages, const struct pri_party_id *caller_id, + const char *timestamp, int message_reference, int message_status); + /* Set service message support flag */ int pri_set_service_message_support(struct pri *pri, int supportflag); diff --git a/pri_facility.c b/pri_facility.c index 5194ae1..572ff0e 100644 --- a/pri_facility.c +++ b/pri_facility.c @@ -1738,6 +1738,146 @@ int mwi_message_send(struct pri *ctrl, q931_call *call, struct pri_sr *req, int return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL); } + +/*! + * \internal + * \brief Encode a MWI indication. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param pos Starting position to encode the facility ie contents. + * \param end End of facility ie contents encoding data buffer. + * \param mailbox Controlling party number (NULL if not present). + * \param basic_service Basic service enum (-1 if not present). + * \param num_messages NumberOfMessages (-1 if not present). + * \param caller_id Controlling party privided number (NULL if not present). + * \param timestamp Generalized Time format (NULL if not present). + * \param message_reference Message reference number (-1 if not present). + * \param message_status Message status: added(0), removed(1). + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *enc_etsi_mwi_indicate_message(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const struct pri_party_id *mailbox, int basic_service, + int num_messages, const struct pri_party_id *caller_id, const char *timestamp, + int message_reference, int message_status) +{ + struct rose_msg_invoke msg; + struct q931_party_number number; + + pos = facility_encode_header(ctrl, pos, end, NULL); + if (!pos) { + return NULL; + } + + memset(&msg, 0, sizeof(msg)); + msg.operation = ROSE_ETSI_MWIIndicate; + msg.invoke_id = get_invokeid(ctrl); + + if (mailbox && mailbox->number.valid) { + pri_copy_party_number_to_q931(&number, &mailbox->number); + q931_copy_number_to_rose(ctrl, &msg.args.etsi.MWIIndicate.controlling_user_number, + &number); + } + if (-1 < basic_service) { + msg.args.etsi.MWIIndicate.basic_service_present = 1; + msg.args.etsi.MWIIndicate.basic_service = basic_service; + } + if (-1 < num_messages) { + msg.args.etsi.MWIIndicate.number_of_messages_present = 1; + msg.args.etsi.MWIIndicate.number_of_messages = num_messages; + } + if (caller_id && caller_id->number.valid) { + pri_copy_party_number_to_q931(&number, &caller_id->number); + q931_copy_number_to_rose(ctrl, + &msg.args.etsi.MWIIndicate.controlling_user_provided_number, &number); + } + if (timestamp && timestamp[0]) { + msg.args.etsi.MWIIndicate.time_present = 1; + libpri_copy_string((char *) msg.args.etsi.MWIIndicate.time.str, timestamp, + sizeof(msg.args.etsi.MWIIndicate.time.str)); + } + if (-1 < message_reference) { + msg.args.etsi.MWIIndicate.message_id_present = 1; + msg.args.etsi.MWIIndicate.message_id.reference_number = message_reference; + msg.args.etsi.MWIIndicate.message_id.status = message_status; + } + + pos = rose_encode_invoke(ctrl, pos, end, &msg); + + return pos; +} + +/*! + * \internal + * \brief Encode and queue a MWI indication. + * + * \param ctrl D channel controller. + * \param call Call leg to queue message. + * \param mailbox Controlling party number (NULL if not present). + * \param basic_service Basic service enum (-1 if not present). + * \param num_messages NumberOfMessages (-1 if not present). + * \param caller_id Controlling party privided number (NULL if not present). + * \param timestamp Generalized Time format (NULL if not present). + * \param message_reference Message reference number (-1 if not present). + * \param message_status Message status: added(0), removed(1). + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int rose_mwi_indicate_encode(struct pri *ctrl, struct q931_call *call, + const struct pri_party_id *mailbox, int basic_service, int num_messages, + const struct pri_party_id *caller_id, const char *timestamp, int message_reference, + int message_status) +{ + unsigned char buffer[255]; + unsigned char *end; + + end = enc_etsi_mwi_indicate_message(ctrl, buffer, buffer + sizeof(buffer), mailbox, + basic_service, num_messages, caller_id, timestamp, message_reference, + message_status); + if (!end) { + return -1; + } + + return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL); +} + +int pri_mwi_indicate(struct pri *ctrl, const struct pri_party_id *mailbox, + int basic_service, int num_messages, const struct pri_party_id *caller_id, + const char *timestamp, int message_reference, int message_status) +{ + struct q931_call *call; + + if (!ctrl) { + return -1; + } + + switch (ctrl->switchtype) { + case PRI_SWITCH_EUROISDN_E1: + case PRI_SWITCH_EUROISDN_T1: + if (!BRI_NT_PTMP(ctrl)) { + return -1; + } + call = PRI_MASTER(ctrl)->dummy_call; + if (!call) { + return -1; + } + break; + default: + return -1; + } + + if (rose_mwi_indicate_encode(ctrl, call, mailbox, basic_service, num_messages, + caller_id, timestamp, message_reference, message_status) + || q931_facility(ctrl, call)) { + pri_message(ctrl, + "Could not schedule facility message for MWI indicate message.\n"); + return -1; + } + + return 0; +} /* End MWI */ /* EECT functions */ @@ -4558,6 +4698,14 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie break; } break; +#if 0 /* Not handled yet */ + case ROSE_ETSI_MWIActivate: + break; + case ROSE_ETSI_MWIDeactivate: + break; + case ROSE_ETSI_MWIIndicate: + break; +#endif /* Not handled yet */ case ROSE_QSIG_CallingName: /* CallingName is put in remote_id.name */ rose_copy_name_to_q931(ctrl, &call->remote_id.name, diff --git a/rose.c b/rose.c index 65341cb..25697d7 100644 --- a/rose.c +++ b/rose.c @@ -240,6 +240,14 @@ static const struct asn1_oid rose_etsi_ccnr_t = { /* *INDENT-ON* */ }; +/*! \brief ETSI Message Waiting Indication OID prefix. */ +static const struct asn1_oid rose_etsi_mwi = { +/* *INDENT-OFF* */ + /* {ccitt(0) identified-organization(4) etsi(0) 745 operations-and-errors(1)} */ + 4, { 4, 0, 745, 1 } +/* *INDENT-ON* */ +}; + /*! \brief ETSI specific invoke/result encode/decode message table */ static const struct rose_convert_msg rose_etsi_msgs[] = { /* *INDENT-OFF* */ @@ -541,6 +549,26 @@ static const struct rose_convert_msg rose_etsi_msgs[] = { NULL, NULL, NULL, NULL }, + + /* + * globalValue's (OIDs) from MWI-Operations-and-Errors + * {ccitt identified-organization etsi(0) 745 operations-and-errors(1)} + */ + { + ROSE_ETSI_MWIActivate, &rose_etsi_mwi, 1, + rose_enc_etsi_MWIActivate_ARG, NULL, + rose_dec_etsi_MWIActivate_ARG, NULL + }, + { + ROSE_ETSI_MWIDeactivate, &rose_etsi_mwi, 2, + rose_enc_etsi_MWIDeactivate_ARG, NULL, + rose_dec_etsi_MWIDeactivate_ARG, NULL + }, + { + ROSE_ETSI_MWIIndicate, &rose_etsi_mwi, 3, + rose_enc_etsi_MWIIndicate_ARG, NULL, + rose_dec_etsi_MWIIndicate_ARG, NULL + }, /* *INDENT-ON* */ }; @@ -697,6 +725,35 @@ static const struct rose_convert_error rose_etsi_errors[] = { ROSE_ERROR_CCBS_T_ShortTermDenial, &rose_etsi_ccbs_t, 21, NULL, NULL }, + + /* + * globalValue's (OIDs) from MWI-Operations-and-Errors + * {ccitt identified-organization etsi(0) 745 operations-and-errors(1)} + */ + { + ROSE_ERROR_MWI_InvalidReceivingUserNr, &rose_etsi_mwi, 10, + NULL, NULL + }, + { + ROSE_ERROR_MWI_ReceivingUserNotSubscribed, &rose_etsi_mwi, 11, + NULL, NULL + }, + { + ROSE_ERROR_MWI_ControllingUserNotRegistered,&rose_etsi_mwi, 12, + NULL, NULL + }, + { + ROSE_ERROR_MWI_IndicationNotDelivered, &rose_etsi_mwi, 13, + NULL, NULL + }, + { + ROSE_ERROR_MWI_MaxNumOfControllingUsersReached,&rose_etsi_mwi, 14, + NULL, NULL + }, + { + ROSE_ERROR_MWI_MaxNumOfActiveInstancesReached,&rose_etsi_mwi, 15, + NULL, NULL + }, /* *INDENT-ON* */ }; @@ -1403,6 +1460,10 @@ const char *rose_operation2str(enum rose_operation operation) { ROSE_ETSI_MCIDRequest, "ROSE_ETSI_MCIDRequest" }, + { ROSE_ETSI_MWIActivate, "ROSE_ETSI_MWIActivate" }, + { ROSE_ETSI_MWIDeactivate, "ROSE_ETSI_MWIDeactivate" }, + { ROSE_ETSI_MWIIndicate, "ROSE_ETSI_MWIIndicate" }, + { ROSE_QSIG_CallingName, "ROSE_QSIG_CallingName" }, { ROSE_QSIG_CalledName, "ROSE_QSIG_CalledName" }, { ROSE_QSIG_ConnectedName, "ROSE_QSIG_ConnectedName" }, @@ -1517,6 +1578,13 @@ const char *rose_error2str(enum rose_error_code code) { ROSE_ERROR_CCBS_T_LongTermDenial, "CCBS-T: Long Term Denial" }, { ROSE_ERROR_CCBS_T_ShortTermDenial, "CCBS-T: Short Term Denial" }, + { ROSE_ERROR_MWI_InvalidReceivingUserNr, "MWI: Invalid Receiving User Number" }, + { ROSE_ERROR_MWI_ReceivingUserNotSubscribed, "MWI: Receiving User Not Subscribed" }, + { ROSE_ERROR_MWI_ControllingUserNotRegistered,"MWI: Controlling User Not Registered" }, + { ROSE_ERROR_MWI_IndicationNotDelivered, "MWI: Indication Not Delivered" }, + { ROSE_ERROR_MWI_MaxNumOfControllingUsersReached,"MWI: Max Num Of Controlling Users Reached" }, + { ROSE_ERROR_MWI_MaxNumOfActiveInstancesReached,"MWI: Max Num Of Active Instances Reached" }, + /* Q.SIG specific errors */ { ROSE_ERROR_QSIG_Unspecified, "Unspecified" }, diff --git a/rose.h b/rose.h index 4d5132f..e95d54d 100644 --- a/rose.h +++ b/rose.h @@ -137,6 +137,11 @@ enum rose_operation { /* ETSI MCID-Operations */ ROSE_ETSI_MCIDRequest, /*!< Invoke/Result */ + /* ETSI MWI-Operations-and-Errors */ + ROSE_ETSI_MWIActivate, /*!< Invoke/Result */ + ROSE_ETSI_MWIDeactivate, /*!< Invoke/Result */ + ROSE_ETSI_MWIIndicate, /*!< Invoke only */ + /* Q.SIG Name-Operations */ ROSE_QSIG_CallingName, /*!< Invoke only */ ROSE_QSIG_CalledName, /*!< Invoke only */ @@ -257,6 +262,14 @@ enum rose_error_code { ROSE_ERROR_CCBS_T_LongTermDenial, ROSE_ERROR_CCBS_T_ShortTermDenial, + /* ETSI MWI-Operations-and-Errors */ + ROSE_ERROR_MWI_InvalidReceivingUserNr, + ROSE_ERROR_MWI_ReceivingUserNotSubscribed, + ROSE_ERROR_MWI_ControllingUserNotRegistered, + ROSE_ERROR_MWI_IndicationNotDelivered, + ROSE_ERROR_MWI_MaxNumOfControllingUsersReached, + ROSE_ERROR_MWI_MaxNumOfActiveInstancesReached, + /* Q.SIG from various specifications */ ROSE_ERROR_QSIG_Unspecified, @@ -390,6 +403,31 @@ enum { /* ------------------------------------------------------------------- */ +/* + * Comment obtained from ECMA-242 ASN.1 source. + * a VisibleString containing: + * - the (local) date in 8 digits (YYYYMMDD), + * - followed by (local) time of day in 4 or 6 digits (HHMM[SS]), + * - optionally followed by the letter "Z" or + * by a local time differential in 5 digits ("+"HHMM or "-"HHMM); + * this date and time representation follows ISO 8601 + * Examples: + * 1) 19970621194530, meaning 21 June 1997, 19:45:30; + * 2) 19970621194530Z, meaning the same as 1); + * 3) 19970621194530-0500, meaning the same as 1), + * 5 hours retarded in relation to UTC time + * + * GeneralizedTime ::= [UNIVERSAL 24] IMPLICIT VisibleString + */ +struct roseGeneralizedTime { + /*! GeneralizedTime (SIZE (12..19)) */ + unsigned char str[19 + 1]; +}; + + +/* ------------------------------------------------------------------- */ + + /* * PartyNumber ::= CHOICE { * -- the numbering plan is the default numbering plan of @@ -2082,6 +2120,206 @@ struct roseEtsiCCBS_T_Request_RES { /* ------------------------------------------------------------------- */ +/* + * MessageID ::= SEQUENCE { + * messageRef MessageRef, + * status MessageStatus + * } + */ +struct roseEtsiMessageID { + /*! \brief Message reference number. (INTEGER (0..65535)) */ + u_int16_t reference_number; + /*! + * \brief Message status + * \details + * added_message(0), + * removed_message(1) + */ + u_int8_t status; +}; + +/* + * ARGUMENT SEQUENCE { + * receivingUserNr PartyNumber, + * basicService BasicService, + * controllingUserNr [1] EXPLICIT PartyNumber OPTIONAL, + * numberOfMessages [2] EXPLICIT MessageCounter OPTIONAL, + * controllingUserProvidedNr [3] EXPLICIT PartyNumber OPTIONAL, + * time [4] EXPLICIT GeneralizedTime OPTIONAL, + * messageId [5] EXPLICIT MessageID OPTIONAL, + * mode [6] EXPLICIT InvocationMode OPTIONAL + * } + */ +struct roseEtsiMWIActivate_ARG { + /*! \brief Number of messages in mailbox. (INTEGER (0..65535)) (Optional) */ + u_int16_t number_of_messages; + + /*! \brief Message ID (Status of this message) (Optional)*/ + struct roseEtsiMessageID message_id; + + /*! \brief Receiving user number (Who the message is for.) */ + struct rosePartyNumber receiving_user_number; + /*! \brief Controlling user number (Mailbox number) (Optional) */ + struct rosePartyNumber controlling_user_number; + /*! \brief Controlling user provided number (Caller-ID of party leaving message) (Optional) */ + struct rosePartyNumber controlling_user_provided_number; + + /*! \brief When message left. (optional) */ + struct roseGeneralizedTime time; + + /*! + * \brief Type of call leaving message. + * \details + * allServices(0), + * speech(1), + * unrestrictedDigitalInformation(2), + * audio3k1Hz(3), + * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), + * multirate(5), + * telephony3k1Hz(32), + * teletex(33), + * telefaxGroup4Class1(34), + * videotexSyntaxBased(35), + * videotelephony(36), + * telefaxGroup2-3(37), + * telephony7kHz(38), + * euroFileTransfer(39), + * fileTransferAndAccessManagement(40), + * videoconference(41), + * audioGraphicConference(42) + */ + u_int8_t basic_service; + /*! + * \brief Invocation mode (When it should be delivered.) (Optional) + * \details + * deferred(0), + * immediate(1), + * combined(2) + */ + u_int8_t mode; + + /*! \brief TRUE if NumberOfMessages present */ + u_int8_t number_of_messages_present; + /*! \brief TRUE if time present */ + u_int8_t time_present; + /*! \brief TRUE if MessageId present */ + u_int8_t message_id_present; + /*! \brief TRUE if invocation mode present */ + u_int8_t mode_present; +}; + +/* + * ARGUMENT SEQUENCE { + * receivingUserNr PartyNumber, + * basicService BasicService, + * controllingUserNr PartyNumber OPTIONAL, + * mode InvocationMode OPTIONAL + * } + */ +struct roseEtsiMWIDeactivate_ARG { + /*! \brief Receiving user number (Who the message is for.) */ + struct rosePartyNumber receiving_user_number; + /*! \brief Controlling user number (Mailbox number) (Optional) */ + struct rosePartyNumber controlling_user_number; + + /*! + * \brief Type of call leaving message. + * \details + * allServices(0), + * speech(1), + * unrestrictedDigitalInformation(2), + * audio3k1Hz(3), + * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), + * multirate(5), + * telephony3k1Hz(32), + * teletex(33), + * telefaxGroup4Class1(34), + * videotexSyntaxBased(35), + * videotelephony(36), + * telefaxGroup2-3(37), + * telephony7kHz(38), + * euroFileTransfer(39), + * fileTransferAndAccessManagement(40), + * videoconference(41), + * audioGraphicConference(42) + */ + u_int8_t basic_service; + + /*! + * \brief Invocation mode (When it should be delivered.) (Optional) + * \details + * deferred(0), + * immediate(1), + * combined(2) + */ + u_int8_t mode; + + /*! \brief TRUE if invocation mode present */ + u_int8_t mode_present; +}; + +/* + * ARGUMENT SEQUENCE { + * controllingUserNr [1] EXPLICIT PartyNumber OPTIONAL, + * basicService [2] EXPLICIT BasicService OPTIONAL, + * numberOfMessages [3] EXPLICIT MessageCounter OPTIONAL, + * controllingUserProvidedNr [4] EXPLICIT PartyNumber OPTIONAL, + * time [5] EXPLICIT GeneralizedTime OPTIONAL, + * messageId [6] EXPLICIT MessageID OPTIONAL + * } + */ +struct roseEtsiMWIIndicate_ARG { + /*! \brief Number of messages in mailbox. (INTEGER (0..65535)) (Optional) */ + u_int16_t number_of_messages; + + /*! \brief Message ID (Status of this message) (Optional)*/ + struct roseEtsiMessageID message_id; + + /*! \brief Controlling user number (Mailbox number) (Optional) */ + struct rosePartyNumber controlling_user_number; + /*! \brief Controlling user provided number (Caller-ID of party leaving message) (Optional) */ + struct rosePartyNumber controlling_user_provided_number; + + /*! \brief When message left. (optional) */ + struct roseGeneralizedTime time; + + /*! + * \brief Type of call leaving message. + * \details + * allServices(0), + * speech(1), + * unrestrictedDigitalInformation(2), + * audio3k1Hz(3), + * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), + * multirate(5), + * telephony3k1Hz(32), + * teletex(33), + * telefaxGroup4Class1(34), + * videotexSyntaxBased(35), + * videotelephony(36), + * telefaxGroup2-3(37), + * telephony7kHz(38), + * euroFileTransfer(39), + * fileTransferAndAccessManagement(40), + * videoconference(41), + * audioGraphicConference(42) + */ + u_int8_t basic_service; + + /*! \brief TRUE if basic_service present */ + u_int8_t basic_service_present; + /*! \brief TRUE if NumberOfMessages present */ + u_int8_t number_of_messages_present; + /*! \brief TRUE if time present */ + u_int8_t time_present; + /*! \brief TRUE if MessageId present */ + u_int8_t message_id_present; +}; + + +/* ------------------------------------------------------------------- */ + + /* * Name ::= CHOICE { * -- iso8859-1 is implied in namePresentationAllowedSimple. @@ -3450,7 +3688,7 @@ struct roseQsigMWIActivateArg { struct rosePartyNumber originating_number; /*! \brief GeneralizedTime (SIZE (12..19)) (optional) */ - unsigned char timestamp[19 + 1]; + struct roseGeneralizedTime timestamp; /*! * \details @@ -3675,7 +3913,7 @@ struct roseQsigMWIInterrogateResElt { struct rosePartyNumber originating_number; /*! \brief GeneralizedTime (SIZE (12..19)) (optional) */ - unsigned char timestamp[19 + 1]; + struct roseGeneralizedTime timestamp; /*! * \details @@ -3862,6 +4100,11 @@ union rose_msg_invoke_etsi_args { /* ETSI CCNR-T */ struct roseEtsiCCBS_T_Request_ARG CCNR_T_Request; + + /* ETSI Message Waiting Indication (MWI) */ + struct roseEtsiMWIActivate_ARG MWIActivate; + struct roseEtsiMWIDeactivate_ARG MWIDeactivate; + struct roseEtsiMWIIndicate_ARG MWIIndicate; }; /*! \brief Facility ie result etsi messages with arguments. */ diff --git a/rose_etsi_mwi.c b/rose_etsi_mwi.c new file mode 100644 index 0000000..9adcca5 --- /dev/null +++ b/rose_etsi_mwi.c @@ -0,0 +1,686 @@ +/* + * libpri: An implementation of Primary Rate ISDN + * + * Copyright (C) 2010 Digium, Inc. + * + * Richard Mudgett + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2 as published by the + * Free Software Foundation. See the LICENSE file included with + * this program for more details. + * + * In addition, when this program is distributed with Asterisk in + * any form that would qualify as a 'combined work' or as a + * 'derivative work' (but not mere aggregation), you can redistribute + * and/or modify the combination under the terms of the license + * provided with that copy of Asterisk, instead of the license + * terms granted here. + */ + +/*! + * \file + * \brief ROSE Message Waiting Indication (MWI) operations + * + * Message Waiting Indication (MWI) supplementary service EN 300 745-1 + * + * \author Richard Mudgett + */ + + +#include "compat.h" +#include "libpri.h" +#include "pri_internal.h" +#include "rose.h" +#include "rose_internal.h" +#include "asn1.h" + + +/* ------------------------------------------------------------------- */ + +/*! + * \internal + * \brief Encode the MessageID type. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param pos Starting position to encode ASN.1 component. + * \param end End of ASN.1 encoding data buffer. + * \param msg_id + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +static unsigned char *rose_enc_etsi_message_id(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const struct roseEtsiMessageID *msg_id) +{ + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg_id->reference_number)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, msg_id->status)); + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the MWIActivate invoke facility ie arguments. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param pos Starting position to encode ASN.1 component. + * \param end End of ASN.1 encoding data buffer. + * \param args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_etsi_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + const struct roseEtsiMWIActivate_ARG *mwi_activate; + unsigned char *seq_len; + unsigned char *explicit_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + mwi_activate = &args->etsi.MWIActivate; + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_activate->receiving_user_number)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + mwi_activate->basic_service)); + if (mwi_activate->controlling_user_number.length) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_activate->controlling_user_number)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_activate->number_of_messages_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, + mwi_activate->number_of_messages)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_activate->controlling_user_provided_number.length) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3); + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_activate->controlling_user_provided_number)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_activate->time_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4); + ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME, + mwi_activate->time.str, sizeof(mwi_activate->time.str) - 1)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_activate->message_id_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5); + ASN1_CALL(pos, rose_enc_etsi_message_id(ctrl, pos, end, + &mwi_activate->message_id)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_activate->mode_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 6); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + mwi_activate->mode)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the MWIDeactivate invoke facility ie arguments. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param pos Starting position to encode ASN.1 component. + * \param end End of ASN.1 encoding data buffer. + * \param args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_etsi_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + const struct roseEtsiMWIDeactivate_ARG *mwi_deactivate; + unsigned char *seq_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + mwi_deactivate = &args->etsi.MWIDeactivate; + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_deactivate->receiving_user_number)); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + mwi_deactivate->basic_service)); + if (mwi_deactivate->controlling_user_number.length) { + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_deactivate->controlling_user_number)); + } + if (mwi_deactivate->mode_present) { + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + mwi_deactivate->mode)); + } + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \brief Encode the MWIIndicate invoke facility ie arguments. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param pos Starting position to encode ASN.1 component. + * \param end End of ASN.1 encoding data buffer. + * \param args Arguments to encode in the buffer. + * + * \retval Start of the next ASN.1 component to encode on success. + * \retval NULL on error. + */ +unsigned char *rose_enc_etsi_MWIIndicate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args) +{ + const struct roseEtsiMWIIndicate_ARG *mwi_indicate; + unsigned char *seq_len; + unsigned char *explicit_len; + + ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); + + mwi_indicate = &args->etsi.MWIIndicate; + if (mwi_indicate->controlling_user_number.length) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1); + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_indicate->controlling_user_number)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_indicate->basic_service_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, + mwi_indicate->basic_service)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_indicate->number_of_messages_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3); + ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, + mwi_indicate->number_of_messages)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_indicate->controlling_user_provided_number.length) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4); + ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, + &mwi_indicate->controlling_user_provided_number)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_indicate->time_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5); + ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME, + mwi_indicate->time.str, sizeof(mwi_indicate->time.str) - 1)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + if (mwi_indicate->message_id_present) { + /* EXPLICIT tag */ + ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 6); + ASN1_CALL(pos, rose_enc_etsi_message_id(ctrl, pos, end, + &mwi_indicate->message_id)); + ASN1_CONSTRUCTED_END(explicit_len, pos, end); + } + + ASN1_CONSTRUCTED_END(seq_len, pos, end); + + return pos; +} + +/*! + * \internal + * \brief Decode the MessageID argument parameters. + * + * \param ctrl D channel controller for any diagnostic messages. + * \param name Field name + * \param tag Component tag that identified this production. + * \param pos Starting position of the ASN.1 component length. + * \param end End of ASN.1 decoding data buffer. + * \param msg_id Parameter storage to fill. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +static const unsigned char *rose_dec_etsi_message_id(struct pri *ctrl, const char *name, + unsigned tag, const unsigned char *pos, const unsigned char *end, + struct roseEtsiMessageID *msg_id) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " %s MessageID %s\n", name, asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); + ASN1_CALL(pos, asn1_dec_int(ctrl, "messageRef", tag, pos, seq_end, &value)); + msg_id->reference_number = value; + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "status", tag, pos, seq_end, &value)); + msg_id->status = value; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the MWIActivate invoke argument parameters. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param tag Component tag that identified this structure. + * \param pos Starting position of the ASN.1 component length. + * \param end End of ASN.1 decoding data buffer. + * \param args Arguments to fill in from the decoded buffer. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +const unsigned char *rose_dec_etsi_MWIActivate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args) +{ + int32_t value; + size_t str_len; + int length; + int seq_offset; + int explicit_offset; + const unsigned char *explicit_end; + const unsigned char *seq_end; + const unsigned char *save_pos; + struct roseEtsiMWIActivate_ARG *mwi_activate; + + mwi_activate = &args->etsi.MWIActivate; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " MWIActivate %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "receivingUserNr", tag, pos, seq_end, + &mwi_activate->receiving_user_number)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); + mwi_activate->basic_service = value; + + /* + * A sequence specifies an ordered list of component types. + * However, for simplicity we are not checking the order of + * the remaining optional components. + */ + mwi_activate->controlling_user_number.length = 0; + mwi_activate->number_of_messages_present = 0; + mwi_activate->controlling_user_provided_number.length = 0; + mwi_activate->time_present = 0; + mwi_activate->message_id_present = 0; + mwi_activate->mode_present = 0; + while (pos < seq_end && *pos != ASN1_INDEF_TERM) { + save_pos = pos; + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + switch (tag) { + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserNr", tag, pos, + explicit_end, &mwi_activate->controlling_user_number)); + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); + ASN1_CALL(pos, asn1_dec_int(ctrl, "numberOfMessages", tag, pos, explicit_end, + &value)); + mwi_activate->number_of_messages = value; + mwi_activate->number_of_messages_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserProvidedNr", tag, + pos, explicit_end, &mwi_activate->controlling_user_provided_number)); + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_TYPE_GENERALIZED_TIME); + ASN1_CALL(pos, asn1_dec_string_max(ctrl, "time", tag, pos, explicit_end, + sizeof(mwi_activate->time.str), mwi_activate->time.str, &str_len)); + mwi_activate->time_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_etsi_message_id(ctrl, "messageId", tag, pos, + explicit_end, &mwi_activate->message_id)); + mwi_activate->message_id_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "mode", tag, pos, explicit_end, &value)); + mwi_activate->mode = value; + mwi_activate->mode_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + default: + pos = save_pos; + goto cancel_options; + } + } +cancel_options:; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the MWIDeactivate invoke argument parameters. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param tag Component tag that identified this structure. + * \param pos Starting position of the ASN.1 component length. + * \param end End of ASN.1 decoding data buffer. + * \param args Arguments to fill in from the decoded buffer. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +const unsigned char *rose_dec_etsi_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args) +{ + int32_t value; + int length; + int seq_offset; + const unsigned char *seq_end; + struct roseEtsiMWIDeactivate_ARG *mwi_deactivate; + + mwi_deactivate = &args->etsi.MWIDeactivate; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " MWIDeactivate %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "receivingUserNr", tag, pos, seq_end, + &mwi_deactivate->receiving_user_number)); + + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); + mwi_deactivate->basic_service = value; + + /* + * A sequence specifies an ordered list of component types. + * However, for simplicity we are not checking the order of + * the remaining optional components. + */ + mwi_deactivate->controlling_user_number.length = 0; + mwi_deactivate->mode_present = 0; + while (pos < seq_end && *pos != ASN1_INDEF_TERM) { + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + switch (tag) { + default: + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserNr", tag, pos, + seq_end, &mwi_deactivate->controlling_user_number)); + break; + case ASN1_TYPE_ENUMERATED: + ASN1_CALL(pos, asn1_dec_int(ctrl, "mode", tag, pos, seq_end, &value)); + mwi_deactivate->mode = value; + mwi_deactivate->mode_present = 1; + break; + } + } + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + +/*! + * \brief Decode the MWIIndicate invoke argument parameters. + * + * \param ctrl D channel controller for diagnostic messages or global options. + * \param tag Component tag that identified this structure. + * \param pos Starting position of the ASN.1 component length. + * \param end End of ASN.1 decoding data buffer. + * \param args Arguments to fill in from the decoded buffer. + * + * \retval Start of the next ASN.1 component on success. + * \retval NULL on error. + */ +const unsigned char *rose_dec_etsi_MWIIndicate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args) +{ + int32_t value; + size_t str_len; + int length; + int seq_offset; + int explicit_offset; + const unsigned char *explicit_end; + const unsigned char *seq_end; + const unsigned char *save_pos; + struct roseEtsiMWIIndicate_ARG *mwi_indicate; + + mwi_indicate = &args->etsi.MWIIndicate; + + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " MWIIndicate %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); + ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); + + /* + * A sequence specifies an ordered list of component types. + * However, for simplicity we are not checking the order of + * the remaining optional components. + */ + mwi_indicate->controlling_user_number.length = 0; + mwi_indicate->basic_service_present = 0; + mwi_indicate->number_of_messages_present = 0; + mwi_indicate->controlling_user_provided_number.length = 0; + mwi_indicate->time_present = 0; + mwi_indicate->message_id_present = 0; + while (pos < seq_end && *pos != ASN1_INDEF_TERM) { + save_pos = pos; + ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); + switch (tag) { + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserNr", tag, pos, + explicit_end, &mwi_indicate->controlling_user_number)); + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); + ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, explicit_end, + &value)); + mwi_indicate->basic_service = value; + mwi_indicate->basic_service_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); + ASN1_CALL(pos, asn1_dec_int(ctrl, "numberOfMessages", tag, pos, explicit_end, + &value)); + mwi_indicate->number_of_messages = value; + mwi_indicate->number_of_messages_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "controllingUserProvidedNr", tag, + pos, explicit_end, &mwi_indicate->controlling_user_provided_number)); + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_TYPE_GENERALIZED_TIME); + ASN1_CALL(pos, asn1_dec_string_max(ctrl, "time", tag, pos, explicit_end, + sizeof(mwi_indicate->time.str), mwi_indicate->time.str, &str_len)); + mwi_indicate->time_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6: + /* Remove EXPLICIT tag */ + if (ctrl->debug & PRI_DEBUG_APDU) { + pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); + } + ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); + ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); + + ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); + ASN1_CALL(pos, rose_dec_etsi_message_id(ctrl, "messageId", tag, pos, + explicit_end, &mwi_indicate->message_id)); + mwi_indicate->message_id_present = 1; + + ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); + break; + default: + pos = save_pos; + goto cancel_options; + } + } +cancel_options:; + + ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); + + return pos; +} + + +/* ------------------------------------------------------------------- */ +/* end rose_etsi_mwi.c */ diff --git a/rose_internal.h b/rose_internal.h index ed8e369..adf7237 100644 --- a/rose_internal.h +++ b/rose_internal.h @@ -367,6 +367,24 @@ const unsigned char *rose_dec_etsi_CCNR_T_Request_RES(struct pri *ctrl, unsigned const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args); +/* ETSI Message Waiting Indication (MWI) */ +unsigned char *rose_enc_etsi_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_etsi_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); +unsigned char *rose_enc_etsi_MWIIndicate_ARG(struct pri *ctrl, unsigned char *pos, + unsigned char *end, const union rose_msg_invoke_args *args); + +const unsigned char *rose_dec_etsi_MWIActivate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_etsi_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); +const unsigned char *rose_dec_etsi_MWIIndicate_ARG(struct pri *ctrl, unsigned tag, + const unsigned char *pos, const unsigned char *end, + union rose_msg_invoke_args *args); + /* Q.SIG Name-Operations */ unsigned char *rose_enc_qsig_Name(struct pri *ctrl, unsigned char *pos, unsigned char *end, const struct roseQsigName *name); diff --git a/rose_qsig_mwi.c b/rose_qsig_mwi.c index 98280db..887a81a 100644 --- a/rose_qsig_mwi.c +++ b/rose_qsig_mwi.c @@ -126,7 +126,7 @@ unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *po } if (mwi_activate->timestamp_present) { ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME, - mwi_activate->timestamp, sizeof(mwi_activate->timestamp) - 1)); + mwi_activate->timestamp.str, sizeof(mwi_activate->timestamp.str) - 1)); } if (mwi_activate->priority_present) { ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5, @@ -254,7 +254,7 @@ static unsigned char *rose_enc_qsig_MWIInterrogateResElt(struct pri *ctrl, } if (record->timestamp_present) { ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME, - record->timestamp, sizeof(record->timestamp) - 1)); + record->timestamp.str, sizeof(record->timestamp.str) - 1)); } if (record->priority_present) { ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5, @@ -450,7 +450,8 @@ const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned ta break; case ASN1_TYPE_GENERALIZED_TIME: ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end, - sizeof(mwi_activate->timestamp), mwi_activate->timestamp, &str_len)); + sizeof(mwi_activate->timestamp.str), mwi_activate->timestamp.str, + &str_len)); mwi_activate->timestamp_present = 1; break; case ASN1_CLASS_CONTEXT_SPECIFIC | 5: @@ -710,7 +711,7 @@ static const unsigned char *rose_dec_qsig_MWIInterrogateResElt(struct pri *ctrl, break; case ASN1_TYPE_GENERALIZED_TIME: ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end, - sizeof(record->timestamp), record->timestamp, &str_len)); + sizeof(record->timestamp.str), record->timestamp.str, &str_len)); record->timestamp_present = 1; break; case ASN1_CLASS_CONTEXT_SPECIFIC | 5: diff --git a/rosetest.c b/rosetest.c index 49fd02b..2a8bbd8 100644 --- a/rosetest.c +++ b/rosetest.c @@ -1396,6 +1396,91 @@ static const struct rose_message rose_etsi_msgs[] = { .component.invoke.operation = ROSE_ETSI_MCIDRequest, .component.invoke.invoke_id = 54, }, + + /* MWI */ + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_ETSI_MWIActivate, + .component.invoke.invoke_id = 55, + .component.invoke.args.etsi.MWIActivate.receiving_user_number.plan = 8, + .component.invoke.args.etsi.MWIActivate.receiving_user_number.length = 4, + .component.invoke.args.etsi.MWIActivate.receiving_user_number.str = "6229", + .component.invoke.args.etsi.MWIActivate.basic_service = 3, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_ETSI_MWIActivate, + .component.invoke.invoke_id = 56, + .component.invoke.args.etsi.MWIActivate.receiving_user_number.plan = 8, + .component.invoke.args.etsi.MWIActivate.receiving_user_number.length = 4, + .component.invoke.args.etsi.MWIActivate.receiving_user_number.str = "6229", + .component.invoke.args.etsi.MWIActivate.basic_service = 3, + .component.invoke.args.etsi.MWIActivate.controlling_user_number.plan = 8, + .component.invoke.args.etsi.MWIActivate.controlling_user_number.length = 4, + .component.invoke.args.etsi.MWIActivate.controlling_user_number.str = "6229", + .component.invoke.args.etsi.MWIActivate.number_of_messages_present = 1, + .component.invoke.args.etsi.MWIActivate.number_of_messages = 7, + .component.invoke.args.etsi.MWIActivate.controlling_user_provided_number.plan = 8, + .component.invoke.args.etsi.MWIActivate.controlling_user_provided_number.length = 4, + .component.invoke.args.etsi.MWIActivate.controlling_user_provided_number.str = "6229", + .component.invoke.args.etsi.MWIActivate.time_present = 1, + .component.invoke.args.etsi.MWIActivate.time.str = "19970621194530", + .component.invoke.args.etsi.MWIActivate.message_id_present = 1, + .component.invoke.args.etsi.MWIActivate.message_id.reference_number = 98, + .component.invoke.args.etsi.MWIActivate.message_id.status = 1, + .component.invoke.args.etsi.MWIActivate.mode_present = 1, + .component.invoke.args.etsi.MWIActivate.mode = 2, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_ETSI_MWIDeactivate, + .component.invoke.invoke_id = 57, + .component.invoke.args.etsi.MWIDeactivate.receiving_user_number.plan = 8, + .component.invoke.args.etsi.MWIDeactivate.receiving_user_number.length = 4, + .component.invoke.args.etsi.MWIDeactivate.receiving_user_number.str = "6229", + .component.invoke.args.etsi.MWIDeactivate.basic_service = 3, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_ETSI_MWIDeactivate, + .component.invoke.invoke_id = 58, + .component.invoke.args.etsi.MWIDeactivate.receiving_user_number.plan = 8, + .component.invoke.args.etsi.MWIDeactivate.receiving_user_number.length = 4, + .component.invoke.args.etsi.MWIDeactivate.receiving_user_number.str = "6229", + .component.invoke.args.etsi.MWIDeactivate.basic_service = 3, + .component.invoke.args.etsi.MWIDeactivate.controlling_user_number.plan = 8, + .component.invoke.args.etsi.MWIDeactivate.controlling_user_number.length = 4, + .component.invoke.args.etsi.MWIDeactivate.controlling_user_number.str = "6229", + .component.invoke.args.etsi.MWIDeactivate.mode_present = 1, + .component.invoke.args.etsi.MWIDeactivate.mode = 2, + }, + + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_ETSI_MWIIndicate, + .component.invoke.invoke_id = 59, + }, + { + .type = ROSE_COMP_TYPE_INVOKE, + .component.invoke.operation = ROSE_ETSI_MWIIndicate, + .component.invoke.invoke_id = 60, + .component.invoke.args.etsi.MWIIndicate.controlling_user_number.plan = 8, + .component.invoke.args.etsi.MWIIndicate.controlling_user_number.length = 4, + .component.invoke.args.etsi.MWIIndicate.controlling_user_number.str = "6229", + .component.invoke.args.etsi.MWIIndicate.basic_service_present = 1, + .component.invoke.args.etsi.MWIIndicate.basic_service = 3, + .component.invoke.args.etsi.MWIIndicate.number_of_messages_present = 1, + .component.invoke.args.etsi.MWIIndicate.number_of_messages = 7, + .component.invoke.args.etsi.MWIIndicate.controlling_user_provided_number.plan = 8, + .component.invoke.args.etsi.MWIIndicate.controlling_user_provided_number.length = 4, + .component.invoke.args.etsi.MWIIndicate.controlling_user_provided_number.str = "6229", + .component.invoke.args.etsi.MWIIndicate.time_present = 1, + .component.invoke.args.etsi.MWIIndicate.time.str = "19970621194530", + .component.invoke.args.etsi.MWIIndicate.message_id_present = 1, + .component.invoke.args.etsi.MWIIndicate.message_id.reference_number = 98, + .component.invoke.args.etsi.MWIIndicate.message_id.status = 1, + }, /* *INDENT-ON* */ }; @@ -2610,7 +2695,7 @@ static const struct rose_message rose_qsig_msgs[] = { .component.invoke.args.qsig.MWIActivate.originating_number.length = 4, .component.invoke.args.qsig.MWIActivate.originating_number.str = "9838", .component.invoke.args.qsig.MWIActivate.timestamp_present = 1, - .component.invoke.args.qsig.MWIActivate.timestamp = "19970621194530", + .component.invoke.args.qsig.MWIActivate.timestamp.str = "19970621194530", .component.invoke.args.qsig.MWIActivate.priority_present = 1, .component.invoke.args.qsig.MWIActivate.priority = 7, }, @@ -2690,7 +2775,7 @@ static const struct rose_message rose_qsig_msgs[] = { .component.result.args.qsig.MWIInterrogate.list[0].originating_number.length = 4, .component.result.args.qsig.MWIInterrogate.list[0].originating_number.str = "9838", .component.result.args.qsig.MWIInterrogate.list[0].timestamp_present = 1, - .component.result.args.qsig.MWIInterrogate.list[0].timestamp = "19970621194530", + .component.result.args.qsig.MWIInterrogate.list[0].timestamp.str = "19970621194530", .component.result.args.qsig.MWIInterrogate.list[0].priority_present = 1, .component.result.args.qsig.MWIInterrogate.list[0].priority = 7, .component.result.args.qsig.MWIInterrogate.list[1].basic_service = 1,