From ed0d76d53863468b00518274e549d474b56ee6dd Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 4 Feb 2011 19:59:45 +0000 Subject: [PATCH] Add display ie text handling options. The display ie handling can be controlled independently in the send and receive directions with the following options: * Block display text data. * Use display text in SETUP/CONNECT messages for name. * Use display text for COLP name updates (FACILITY/NOTIFY as appropriate). * Pass arbitrary display text during a call. Sent in INFORMATION messages. Received from any message that the display text was not used as a name. If the display options are not set then the options default to legacy behavior. git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2190 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- libpri.h | 80 ++++++++++ pri.c | 96 +++++++++++- pri_facility.c | 62 +++++++- pri_internal.h | 42 +++++- q931.c | 396 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 609 insertions(+), 67 deletions(-) diff --git a/libpri.h b/libpri.h index d8ea12f..3361ff6 100644 --- a/libpri.h +++ b/libpri.h @@ -547,6 +547,7 @@ struct pri_rerouting_data { #define PRI_SUBCMD_AOC_CHARGING_REQ_RSP 22 /*!< Advice Of Charge Request Response information */ #define PRI_SUBCMD_MCID_REQ 23 /*!< Malicious Call ID Request */ #define PRI_SUBCMD_MCID_RSP 24 /*!< Malicious Call ID Request response */ +#define PRI_SUBCMD_DISPLAY_TEXT 25 /*!< Received display ie text */ #if defined(STATUS_REQUEST_PLACE_HOLDER) struct pri_subcmd_status_request { @@ -967,6 +968,35 @@ struct pri_subcmd_mcid_rsp { int fail_code; }; +struct pri_subcmd_display_txt { + /*! + * \brief Character set the text is using. + * \details + * unknown(0), + * iso8859-1(1), + * enum-value-withdrawn-by-ITU-T(2) + * iso8859-2(3), + * iso8859-3(4), + * iso8859-4(5), + * iso8859-5(6), + * iso8859-7(7), + * iso10646-BmpString(8), + * iso10646-utf-8String(9) + */ + int char_set; + /*! + * \brief Number of octets in the display message. + * \note Not including any added null terminator. + */ + int length; + /*! + * \brief Display text data. + * \note Null terminated on receive. + * \note Does not need to be null terminated on send. + */ + char text[128]; +}; + struct pri_subcommand { /*! PRI_SUBCMD_xxx defined values */ int cmd; @@ -999,6 +1029,7 @@ struct pri_subcommand { struct pri_subcmd_aoc_e aoc_e; struct pri_subcmd_mcid_req mcid_req; struct pri_subcmd_mcid_rsp mcid_rsp; + struct pri_subcmd_display_txt display; } u; }; @@ -1840,6 +1871,55 @@ int pri_transfer_rsp(struct pri *ctrl, q931_call *call, int invoke_id, int is_su */ void pri_aoc_events_enable(struct pri *ctrl, int enable); +#define PRI_DISPLAY_OPTION_BLOCK (1 << 0) /*!< Do not pass display text. */ +#define PRI_DISPLAY_OPTION_NAME_INITIAL (1 << 1) /*!< Use display in SETUP/CONNECT for name. */ +#define PRI_DISPLAY_OPTION_NAME_UPDATE (1 << 2) /*!< Use display in FACILITY/NOTIFY for COLP name if appropriate. */ +#define PRI_DISPLAY_OPTION_TEXT (1 << 3) /*!< Pass arbitrary display text in INFORMATION messages during call. */ + +/*! + * \brief Set the display ie send policy options. + * + * \param ctrl D channel controller. + * \param flags Option flags to apply. + * + * \note + * If no flags set then legacy default behaviour. + * + * \note + * Not all options are supported by all switches. + * + * \return Nothing + */ +void pri_display_options_send(struct pri *ctrl, unsigned long flags); + +/*! + * \brief Set the display ie receive policy options. + * + * \param ctrl D channel controller. + * \param flags Option flags to apply. + * + * \note + * If no flags set then legacy default behaviour. + * + * \note + * Not all options are supported by all switches. + * + * \return Nothing + */ +void pri_display_options_receive(struct pri *ctrl, unsigned long flags); + +/*! + * \brief Send display text during a call. + * + * \param ctrl D channel controller. + * \param call Q.931 call leg + * \param display Display text to send. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int pri_display_text(struct pri *ctrl, q931_call *call, const struct pri_subcmd_display_txt *display); + /*! * \brief Set the call hold feature enable flag. * diff --git a/pri.c b/pri.c index 854001b..1c66338 100644 --- a/pri.c +++ b/pri.c @@ -288,6 +288,60 @@ static int __pri_write(struct pri *pri, void *buf, int buflen) return res; } +/*! + * \internal + * \brief Determine the default display text send options. + * + * \param ctrl D channel controller. + * + * \return Default display text send options. (legacy behaviour defaults) + */ +static unsigned long pri_display_options_send_default(struct pri *ctrl) +{ + unsigned long flags; + + switch (ctrl->switchtype) { + case PRI_SWITCH_QSIG: + flags = PRI_DISPLAY_OPTION_BLOCK; + break; + case PRI_SWITCH_EUROISDN_E1: + case PRI_SWITCH_EUROISDN_T1: + if (ctrl->localtype == PRI_CPE) { + flags = PRI_DISPLAY_OPTION_BLOCK; + break; + } + flags = PRI_DISPLAY_OPTION_NAME_INITIAL; + break; + default: + flags = PRI_DISPLAY_OPTION_NAME_INITIAL; + break; + } + return flags; +} + +/*! + * \internal + * \brief Determine the default display text receive options. + * + * \param ctrl D channel controller. + * + * \return Default display text receive options. (legacy behaviour defaults) + */ +static unsigned long pri_display_options_receive_default(struct pri *ctrl) +{ + unsigned long flags; + + switch (ctrl->switchtype) { + case PRI_SWITCH_QSIG: + flags = PRI_DISPLAY_OPTION_BLOCK; + break; + default: + flags = PRI_DISPLAY_OPTION_NAME_INITIAL; + break; + } + return flags; +} + /*! * \brief Destroy the given link. * @@ -481,6 +535,8 @@ static struct pri *pri_ctrl_new(int fd, int node, int switchtype, pri_io_cb rd, ctrl->q931_rxcount = 0; ctrl->q931_txcount = 0; + ctrl->display_flags.send = pri_display_options_send_default(ctrl); + ctrl->display_flags.receive = pri_display_options_receive_default(ctrl); switch (switchtype) { case PRI_SWITCH_GR303_EOC: ctrl->protodisc = GR303_PROTOCOL_DISCRIMINATOR; @@ -999,7 +1055,7 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr */ if (new_number) { q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE, - &party_id.number); + &party_id.name, &party_id.number); } if (new_subaddress || (party_id.subaddress.valid && new_number)) { q931_subaddress_transfer(ctrl, call); @@ -1050,10 +1106,10 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr * connected yet. */ q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE, - &party_id.number); + &party_id.name, &party_id.number); #else q931_request_subaddress(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE, - &party_id.number); + &party_id.name, &party_id.number); #endif /* defined(USE_NOTIFY_FOR_ECT) */ } if (new_subaddress || (party_id.subaddress.valid && new_number)) { @@ -1167,7 +1223,7 @@ int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_p * themselves. Well... If you consider someone else picking up * the handset a redirection then how is the network to know? */ - q931_notify_redirection(ctrl, call, PRI_NOTIFY_CALL_DIVERTING, + q931_notify_redirection(ctrl, call, PRI_NOTIFY_CALL_DIVERTING, NULL, &call->redirecting.to.number); } break; @@ -2050,3 +2106,35 @@ void pri_cc_retain_signaling_rsp(struct pri *ctrl, int signaling_retention) ctrl->cc.option.signaling_retention_rsp = signaling_retention ? 1 : 0; } } + +void pri_display_options_send(struct pri *ctrl, unsigned long flags) +{ + if (!ctrl) { + return; + } + if (!flags) { + flags = pri_display_options_send_default(ctrl); + } + ctrl->display_flags.send = flags; +} + +void pri_display_options_receive(struct pri *ctrl, unsigned long flags) +{ + if (!ctrl) { + return; + } + if (!flags) { + flags = pri_display_options_receive_default(ctrl); + } + ctrl->display_flags.receive = flags; +} + +int pri_display_text(struct pri *ctrl, q931_call *call, const struct pri_subcmd_display_txt *display) +{ + if (!ctrl || !display || display->length <= 0 + || sizeof(display->text) < display->length || !pri_is_call_valid(ctrl, call)) { + /* Parameter sanity checks failed. */ + return -1; + } + return q931_display_text(ctrl, call, display); +} diff --git a/pri_facility.c b/pri_facility.c index e3d72bd..6ce1e1e 100644 --- a/pri_facility.c +++ b/pri_facility.c @@ -3355,8 +3355,18 @@ int pri_call_add_standard_apdus(struct pri *ctrl, q931_call *call) */ int send_call_transfer_complete(struct pri *ctrl, q931_call *call, int call_status) { - if (rose_call_transfer_complete_encode(ctrl, call, call_status) - || q931_facility(ctrl, call)) { + int status; + + status = rose_call_transfer_complete_encode(ctrl, call, call_status); + if (!status) { + if (!call_status && call->local_id.number.valid + && (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_UPDATE)) { + status = q931_facility_display_name(ctrl, call, &call->local_id.name); + } else { + status = q931_facility(ctrl, call); + } + } + if (status) { pri_message(ctrl, "Could not schedule facility message for call transfer completed.\n"); return -1; @@ -3574,6 +3584,7 @@ int send_subaddress_transfer(struct pri *ctrl, struct q931_call *call) */ static void etsi_request_subaddress(struct pri *ctrl, struct q931_call *call) { + struct q931_party_name name; int changed = 0; switch (call->notify) { @@ -3585,6 +3596,15 @@ static void etsi_request_subaddress(struct pri *ctrl, struct q931_call *call) } /* Fall through */ case PRI_NOTIFY_TRANSFER_ALERTING: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + if (q931_display_name_get(call, &name)) { + if (q931_party_name_cmp(&call->remote_id.name, &name)) { + /* The remote party name information changed. */ + call->remote_id.name = name; + changed = 1; + } + } + } if (call->redirection_number.valid && q931_party_number_cmp(&call->remote_id.number, &call->redirection_number)) { /* The remote party number information changed. */ @@ -3626,6 +3646,7 @@ static void etsi_request_subaddress(struct pri *ctrl, struct q931_call *call) static void handle_subaddress_transfer(struct pri *ctrl, struct q931_call *call, const struct rosePartySubaddress *subaddr) { int changed = 0; + struct q931_party_name name; struct q931_party_subaddress q931_subaddress; q931_party_subaddress_init(&q931_subaddress); @@ -3640,6 +3661,15 @@ static void handle_subaddress_transfer(struct pri *ctrl, struct q931_call *call, call->remote_id.number = call->redirection_number; changed = 1; } + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + if (q931_display_name_get(call, &name)) { + if (q931_party_name_cmp(&call->remote_id.name, &name)) { + /* The remote party name information changed. */ + call->remote_id.name = name; + changed = 1; + } + } + } if (changed) { call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE; } @@ -4684,6 +4714,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie send_ect_link_id_rsp(ctrl, call, invoke->invoke_id); break; case ROSE_ETSI_EctInform: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &call->remote_id.name); + } + /* redirectionNumber is put in remote_id.number */ if (invoke->args.etsi.EctInform.redirection_present) { rose_copy_presented_number_unscreened_to_q931(ctrl, @@ -5002,6 +5036,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie break; #endif /* Not handled yet */ case ROSE_QSIG_CallingName: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &call->remote_id.name); + } + /* CallingName is put in remote_id.name */ rose_copy_name_to_q931(ctrl, &call->remote_id.name, &invoke->args.qsig.CallingName.name); @@ -5023,6 +5061,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie } break; case ROSE_QSIG_CalledName: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &call->remote_id.name); + } + /* CalledName is put in remote_id.name */ rose_copy_name_to_q931(ctrl, &call->remote_id.name, &invoke->args.qsig.CalledName.name); @@ -5044,6 +5086,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie } break; case ROSE_QSIG_ConnectedName: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &call->remote_id.name); + } + /* ConnectedName is put in remote_id.name */ rose_copy_name_to_q931(ctrl, &call->remote_id.name, &invoke->args.qsig.ConnectedName.name); @@ -5095,6 +5141,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie break; #endif /* Not handled yet */ case ROSE_QSIG_CallTransferActive: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &call->remote_id.name); + } + call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE; /* connectedAddress is put in remote_id */ @@ -5108,6 +5158,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie } break; case ROSE_QSIG_CallTransferComplete: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &call->remote_id.name); + } + /* redirectionNumber is put in remote_id.number */ rose_copy_presented_number_screened_to_q931(ctrl, &call->remote_id.number, &invoke->args.qsig.CallTransferComplete.redirection); @@ -5139,6 +5193,10 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie case ROSE_QSIG_CallTransferUpdate: party_id = call->remote_id; + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + q931_display_name_get(call, &party_id.name); + } + /* redirectionNumber is put in party_id.number */ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number, &invoke->args.qsig.CallTransferUpdate.redirection); diff --git a/pri_internal.h b/pri_internal.h index e496b98..691cc6f 100644 --- a/pri_internal.h +++ b/pri_internal.h @@ -60,6 +60,9 @@ struct pri_sched { /*! Maximum number of facility ie's to handle per incoming message. */ #define MAX_FACILITY_IES 8 +/*! Maximum length of sent display text string. (No null terminator.) */ +#define MAX_DISPLAY_TEXT 80 + /*! Accumulated pri_message() line until a '\n' is seen on the end. */ struct pri_msg_line { /*! Accumulated buffer used. */ @@ -177,6 +180,13 @@ struct pri { /*! Number of facility ie's in the array from the current received message. */ unsigned char count; } facility; + /*! Display text policy handling options. */ + struct { + /*! Send display text policy option flags. */ + unsigned long send; + /*! Receive display text policy option flags. */ + unsigned long receive; + } display_flags; }; /*! \brief Maximum name length plus null terminator (From ECMA-164) */ @@ -603,6 +613,29 @@ struct q931_call { unsigned char initially_redirected; } cc; + /*! Display text ie contents. */ + struct { + /*! Display ie text. NULL if not present or consumed as remote name. */ + const char *text; + /*! Length of display text. */ + unsigned char length; + /*! + * \brief Character set the text is using. + * \details + * unknown(0), + * iso8859-1(1), + * enum-value-withdrawn-by-ITU-T(2) + * iso8859-2(3), + * iso8859-3(4), + * iso8859-4(5), + * iso8859-5(6), + * iso8859-7(7), + * iso10646-BmpString(8), + * iso10646-utf-8String(9) + */ + unsigned char char_set; + } display; + /* AOC charge requesting on Setup */ int aoc_charging_request; }; @@ -938,6 +971,11 @@ void pri_copy_party_id_to_q931(struct q931_party_id *q931_id, const struct pri_p void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id); int q931_party_id_presentation(const struct q931_party_id *id); +int q931_display_name_get(struct q931_call *call, struct q931_party_name *name); +int q931_display_text(struct pri *ctrl, struct q931_call *call, const struct pri_subcmd_display_txt *display); + +int q931_facility_display_name(struct pri *ctrl, struct q931_call *call, const struct q931_party_name *name); + const char *q931_call_state_str(enum Q931_CALL_STATE callstate); const char *msg2str(int msg); @@ -948,9 +986,9 @@ struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl); struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id); struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call); -int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number); +int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number); int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call); -int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number); +int q931_notify_redirection(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number); struct pri_cc_record *pri_cc_find_by_reference(struct pri *ctrl, unsigned reference_id); struct pri_cc_record *pri_cc_find_by_linkage(struct pri *ctrl, unsigned linkage_id); diff --git a/q931.c b/q931.c index 9669723..9407dd6 100644 --- a/q931.c +++ b/q931.c @@ -936,6 +936,125 @@ int q931_party_id_presentation(const struct q931_party_id *id) return number_value | number_screening; } +/*! + * \internal + * \brief Clear the display text. + * + * \param call Q.931 call to clear display text. + * + * \return Nothing + */ +static void q931_display_clear(struct q931_call *call) +{ + call->display.text = NULL; +} + +/*! + * \internal + * \brief Set the display text for the party name. + * + * \param call Q.931 call to set display text to the party name. + * + * \return Nothing + */ +static void q931_display_name_send(struct q931_call *call, const struct q931_party_name *name) +{ + if (name->valid) { + switch (name->presentation & PRI_PRES_RESTRICTION) { + case PRI_PRES_ALLOWED: + call->display.text = (char *) name->str; + call->display.length = strlen(name->str); + call->display.char_set = name->char_set; + break; + default: + call->display.text = NULL; + break; + } + } else { + call->display.text = NULL; + } +} + +/*! + * \brief Get the display text into the party name. + * + * \param call Q.931 call to get the display text into the party name. + * \param name Party name to fill if there is display text. + * + * \note + * The party name is not touched if there is no display text. + * + * \note + * The display text is consumed. + * + * \return TRUE if party name filled. + */ +int q931_display_name_get(struct q931_call *call, struct q931_party_name *name) +{ + if (!call->display.text) { + return 0; + } + + name->valid = 1; + name->char_set = call->display.char_set; + if (call->display.length < sizeof(name->str)) { + memcpy(name->str, call->display.text, call->display.length); + name->str[call->display.length] = '\0'; + } else { + name->str[0] = '\0'; + } + if (name->str[0]) { + name->presentation = PRI_PRES_ALLOWED; + } else { + name->presentation = PRI_PRES_RESTRICTED; + } + + /* Mark the display text as consumed. */ + call->display.text = NULL; + + return 1; +} + +/*! + * \internal + * \brief Fill a subcmd with any display text. + * + * \param ctrl D channel controller. + * \param call Q.931 call leg. + * + * \note + * The display text is consumed. + * + * \return Nothing + */ +static void q931_display_subcmd(struct pri *ctrl, struct q931_call *call) +{ + struct pri_subcommand *subcmd; + + if (call->display.text && call->display.length + && (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_TEXT)) { + subcmd = q931_alloc_subcommand(ctrl); + if (subcmd) { + /* Setup display text subcommand */ + subcmd->cmd = PRI_SUBCMD_DISPLAY_TEXT; + subcmd->u.display.char_set = call->display.char_set; + if (call->display.length < sizeof(subcmd->u.display.text)) { + subcmd->u.display.length = call->display.length; + } else { + /* Truncate display text and leave room for a null terminator. */ + subcmd->u.display.length = sizeof(subcmd->u.display.text) - 1; + } + memcpy(subcmd->u.display.text, call->display.text, subcmd->u.display.length); + + /* Make sure display text is null terminated. */ + subcmd->u.display.text[subcmd->u.display.length] = '\0'; + } + } + + /* Mark the display text as consumed. */ + call->display.text = NULL; +} + /*! * \brief Find the winning subcall if it exists or current call if not outboundbroadcast. * @@ -2435,36 +2554,22 @@ static void dump_progress_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, static int receive_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) { - unsigned char *data; + u_int8_t *data; - switch (msgtype) { - case Q931_SETUP: - case Q931_CONNECT: - /* - * Only keep the display message on SETUP and CONNECT messages - * as the remote name. - */ - break; - default: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_BLOCK) { return 0; } - call->remote_id.name.valid = 1; - data = ie->data; if (data[0] & 0x80) { /* Skip over character set */ data++; len--; } - call->remote_id.name.char_set = PRI_CHAR_SET_ISO8859_1; - q931_get_number((unsigned char *) call->remote_id.name.str, sizeof(call->remote_id.name.str), data, len - 2); - if (call->remote_id.name.str[0]) { - call->remote_id.name.presentation = PRI_PRES_ALLOWED; - } else { - call->remote_id.name.presentation = PRI_PRES_RESTRICTED; - } + call->display.text = (char *) data; + call->display.length = len - 2; + call->display.char_set = PRI_CHAR_SET_ISO8859_1; return 0; } @@ -2473,30 +2578,31 @@ static int transmit_display(int full_ie, struct pri *ctrl, q931_call *call, int size_t datalen; int i; - i = 0; - - if (!call->local_id.name.valid || !call->local_id.name.str[0]) { + if (!call->display.text || !call->display.length) { return 0; } + if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_BLOCK) { + return 0; + } + + i = 0; switch (ctrl->switchtype) { case PRI_SWITCH_QSIG: - /* Q.SIG supports names */ - return 0; case PRI_SWITCH_EUROISDN_E1: case PRI_SWITCH_EUROISDN_T1: - if (ctrl->localtype == PRI_CPE) { - return 0; - } break; default: - /* Prefix name with character set indicator. */ + /* Prefix text with character set indicator. */ ie->data[0] = 0xb1; ++i; break; } - datalen = strlen(call->local_id.name.str); - memcpy(ie->data + i, call->local_id.name.str, datalen); + datalen = call->display.length; + if (MAX_DISPLAY_TEXT < datalen + i) { + datalen = MAX_DISPLAY_TEXT - i; + } + memcpy(ie->data + i, call->display.text, datalen); return 2 + i + datalen; } @@ -4742,20 +4848,27 @@ int maintenance_service(struct pri *ctrl, int span, int channel, int changestatu return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies); } -static int status_ies[] = { Q931_CAUSE, Q931_IE_CALL_STATE, -1 }; - static int q931_status(struct pri *ctrl, q931_call *call, int cause) { + static int status_ies[] = { + Q931_CAUSE, + Q931_IE_CALL_STATE, + -1 + }; + call->cause = cause; call->causecode = CODE_CCITT; call->causeloc = LOC_USER; return send_message(ctrl, call, Q931_STATUS, status_ies); } -static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 }; - int q931_information(struct pri *ctrl, q931_call *c, char digit) { + static int information_ies[] = { + Q931_CALLED_PARTY_NUMBER, + -1 + }; + c->overlap_digits[0] = digit; c->overlap_digits[1] = '\0'; @@ -4772,6 +4885,84 @@ int q931_information(struct pri *ctrl, q931_call *c, char digit) return send_message(ctrl, c, Q931_INFORMATION, information_ies); } +/*! + * \internal + * \brief Actually send display text if in the right call state. + * + * \param ctrl D channel controller. + * \param call Q.931 call leg + * \param display Display text to send. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int q931_display_text_helper(struct pri *ctrl, struct q931_call *call, const struct pri_subcmd_display_txt *display) +{ + int status; + static int information_display_ies[] = { + Q931_DISPLAY, + -1 + }; + + switch (call->ourcallstate) { + case Q931_CALL_STATE_OVERLAP_SENDING: + case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: + case Q931_CALL_STATE_CALL_DELIVERED: + case Q931_CALL_STATE_CALL_RECEIVED: + case Q931_CALL_STATE_CONNECT_REQUEST: + case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: + case Q931_CALL_STATE_ACTIVE: + case Q931_CALL_STATE_OVERLAP_RECEIVING: + call->display.text = display->text; + call->display.length = display->length; + call->display.char_set = display->char_set; + status = send_message(ctrl, call, Q931_INFORMATION, information_display_ies); + q931_display_clear(call); + break; + default: + status = 0; + break; + } + + return status; +} + +/*! + * \brief Send display text during a call. + * + * \param ctrl D channel controller. + * \param call Q.931 call leg + * \param display Display text to send. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int q931_display_text(struct pri *ctrl, struct q931_call *call, const struct pri_subcmd_display_txt *display) +{ + int status; + unsigned idx; + struct q931_call *subcall; + + if ((ctrl->display_flags.send & (PRI_DISPLAY_OPTION_BLOCK | PRI_DISPLAY_OPTION_TEXT)) + != PRI_DISPLAY_OPTION_TEXT) { + /* Not enabled */ + return 0; + } + if (call->outboundbroadcast && call->master_call == call) { + status = 0; + for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) { + subcall = call->subcalls[idx]; + if (subcall && q931_display_text_helper(ctrl, subcall, display)) { + status = -1; + } + } + } else { + status = q931_display_text_helper(ctrl, call, display); + } + return status; +} + + static int keypad_facility_ies[] = { Q931_IE_KEYPAD_FACILITY, -1 }; int q931_keypad_facility(struct pri *ctrl, q931_call *call, const char *digits) @@ -4789,41 +4980,66 @@ static int restart_ack(struct pri *ctrl, q931_call *c) return send_message(ctrl, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies); } -static int facility_ies[] = { Q931_IE_FACILITY, -1 }; - -int q931_facility(struct pri*ctrl, q931_call *c) +int q931_facility(struct pri *ctrl, struct q931_call *call) { - return send_message(ctrl, c, Q931_FACILITY, facility_ies); + static int facility_ies[] = { + Q931_IE_FACILITY, + -1 + }; + + return send_message(ctrl, call, Q931_FACILITY, facility_ies); } -static int facility_notify_ies[] = { - Q931_IE_FACILITY, - Q931_IE_NOTIFY_IND, - Q931_IE_REDIRECTION_NUMBER, - -1 -}; +int q931_facility_display_name(struct pri *ctrl, struct q931_call *call, const struct q931_party_name *name) +{ + int status; + static int facility_display_ies[] = { + Q931_IE_FACILITY, + Q931_DISPLAY, + -1 + }; + + q931_display_name_send(call, name); + status = send_message(ctrl, call, Q931_FACILITY, facility_display_ies); + q931_display_clear(call); + return status; +} /*! - * \brief Send a FACILITY RequestSubaddress with optional redirection number. + * \brief Send a FACILITY RequestSubaddress with optional redirection name and number. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param notify Notification indicator + * \param name Redirection name to send if not NULL. * \param number Redirection number to send if not NULL. * * \retval 0 on success. * \retval -1 on error. */ -int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number) +int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number) { + int status; struct q931_call *winner; + static int facility_notify_ies[] = { + Q931_IE_FACILITY, + Q931_IE_NOTIFY_IND, + Q931_DISPLAY, + Q931_IE_REDIRECTION_NUMBER, + -1 + }; winner = q931_find_winning_call(call); if (!winner) { return -1; } + q931_display_clear(winner); if (number) { winner->redirection_number = *number; + if (number->valid && name + && (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_UPDATE)) { + q931_display_name_send(winner, name); + } } else { q931_party_number_init(&winner->redirection_number); } @@ -4832,10 +5048,13 @@ int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify || send_message(ctrl, winner, Q931_FACILITY, facility_notify_ies)) { pri_message(ctrl, "Could not schedule facility message for request subaddress.\n"); - return -1; + status = -1; + } else { + status = 0; } + q931_display_clear(winner); - return 0; + return status; } /*! @@ -4878,43 +5097,58 @@ int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call) return status; } -static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 }; - /*! * \internal - * \brief Actually send a NOTIFY message with optional redirection number. + * \brief Actually send a NOTIFY message with optional redirection name and number. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param notify Notification indicator + * \param name Redirection display name to send if not NULL. * \param number Redirection number to send if not NULL. * * \retval 0 on success. * \retval -1 on error. */ -static int q931_notify_redirection_helper(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number) +static int q931_notify_redirection_helper(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number) { + int status; + static int notify_ies[] = { + Q931_IE_NOTIFY_IND, + Q931_DISPLAY, + Q931_IE_REDIRECTION_NUMBER, + -1 + }; + + q931_display_clear(call); if (number) { call->redirection_number = *number; + if (number->valid && name + && (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_UPDATE)) { + q931_display_name_send(call, name); + } } else { q931_party_number_init(&call->redirection_number); } call->notify = notify; - return send_message(ctrl, call, Q931_NOTIFY, notify_ies); + status = send_message(ctrl, call, Q931_NOTIFY, notify_ies); + q931_display_clear(call); + return status; } /*! - * \brief Send a NOTIFY message with optional redirection number. + * \brief Send a NOTIFY message with optional redirection name and number. * * \param ctrl D channel controller. * \param call Q.931 call leg * \param notify Notification indicator + * \param name Redirection display name to send if not NULL. * \param number Redirection number to send if not NULL. * * \retval 0 on success. * \retval -1 on error. */ -int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number) +int q931_notify_redirection(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_name *name, const struct q931_party_number *number) { int status; unsigned idx; @@ -4930,7 +5164,7 @@ int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: case Q931_CALL_STATE_CALL_DELIVERED: case Q931_CALL_STATE_ACTIVE: - if (q931_notify_redirection_helper(ctrl, subcall, notify, number)) { + if (q931_notify_redirection_helper(ctrl, subcall, notify, name, number)) { status = -1; } break; @@ -4940,7 +5174,7 @@ int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const } } } else { - status = q931_notify_redirection_helper(ctrl, call, notify, number); + status = q931_notify_redirection_helper(ctrl, call, notify, name, number); } return status; } @@ -4964,7 +5198,7 @@ int q931_notify(struct pri *ctrl, q931_call *c, int channel, int info) /* Cannot send NOTIFY message if the mandatory ie is not going to be present. */ return -1; } - return q931_notify_redirection(ctrl, c, info, NULL); + return q931_notify_redirection(ctrl, c, info, NULL, NULL); } #ifdef ALERTING_NO_PROGRESS @@ -5278,6 +5512,11 @@ int q931_connect(struct pri *ctrl, q931_call *c, int channel, int nonisdn) default: break; } + if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_INITIAL) { + q931_display_name_send(c, &c->local_id.name); + } else { + q931_display_clear(c); + } if (ctrl->localtype == PRI_NETWORK) { /* networks may send date/time */ return send_message(ctrl, c, Q931_CONNECT, connect_net_ies); @@ -5473,6 +5712,11 @@ static void t303_expiry(void *data) * retransmits will lose the facility ies. */ pri_call_add_standard_apdus(ctrl, c); + if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_INITIAL) { + q931_display_name_send(c, &c->local_id.name); + } else { + q931_display_clear(c); + } c->cc.saved_ie_contents.length = 0; c->cc.saved_ie_flags = 0; if (ctrl->link.next && !ctrl->bri) @@ -5567,6 +5811,11 @@ int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req) c->aoc_charging_request = req->aoc_charging_request; pri_call_add_standard_apdus(ctrl, c); + if (ctrl->display_flags.send & PRI_DISPLAY_OPTION_NAME_INITIAL) { + q931_display_name_send(c, &c->local_id.name); + } else { + q931_display_clear(c); + } /* Save the initial cc-parties. */ c->cc.party_a = c->local_id; @@ -6808,7 +7057,8 @@ int q931_receive(struct q921_link *link, q931_h *h, int len) break; } q931_clr_subcommands(ctrl); - + q931_display_clear(c); + /* Handle IEs */ memset(mandies, 0, sizeof(mandies)); for (x = 0; x < ARRAY_LEN(msgs); ++x) { @@ -6830,6 +7080,7 @@ int q931_receive(struct q921_link *link, q931_h *h, int len) /* Allow the message anyway. We have already processed an ie. */ break; } + q931_display_clear(c); return -1; } for (y = 0; y < ARRAY_LEN(mandies); ++y) { @@ -6907,6 +7158,17 @@ int q931_receive(struct q921_link *link, q931_h *h, int len) } if (!missingmand) { + switch (mh->msg) { + case Q931_SETUP: + case Q931_CONNECT: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_INITIAL) { + q931_display_name_get(c, &c->remote_id.name); + } + break; + default: + break; + } + /* Now handle the facility ie's after all the other ie's were processed. */ q931_handle_facilities(ctrl, c, mh->msg); } @@ -6939,6 +7201,8 @@ int q931_receive(struct q921_link *link, q931_h *h, int len) } break; } + q931_display_subcmd(ctrl, c); + q931_display_clear(c); return res; } @@ -7888,6 +8152,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct default: break; } + q931_display_subcmd(ctrl, c); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, c); return Q931_RES_HAVEEVENT; @@ -8294,6 +8559,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct } } + q931_display_subcmd(ctrl, c); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, c); res = Q931_RES_HAVEEVENT; @@ -8307,6 +8573,17 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct } /* Fall through */ case PRI_NOTIFY_TRANSFER_ALERTING: + if (ctrl->display_flags.receive & PRI_DISPLAY_OPTION_NAME_UPDATE) { + struct q931_party_name name; + + if (q931_display_name_get(c, &name)) { + if (q931_party_name_cmp(&c->remote_id.name, &name)) { + /* The remote party name information changed. */ + c->remote_id.name = name; + changed = 1; + } + } + } if (c->redirection_number.valid && q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) { /* The remote party number information changed. */ @@ -8331,6 +8608,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct } } + q931_display_subcmd(ctrl, c); if (ctrl->subcmds.counter_subcmd) { q931_fill_facility_event(ctrl, c); res = Q931_RES_HAVEEVENT;