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
This commit is contained in:
Richard Mudgett 2011-02-04 19:59:45 +00:00
parent d0dbd5b3f2
commit ed0d76d538
5 changed files with 609 additions and 67 deletions

View File

@ -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.
*

96
pri.c
View File

@ -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);
}

View File

@ -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);

View File

@ -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);

392
q931.c
View File

@ -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_notify_ies[] = {
static int facility_ies[] = {
Q931_IE_FACILITY,
Q931_IE_NOTIFY_IND,
Q931_IE_REDIRECTION_NUMBER,
-1
};
return send_message(ctrl, call, Q931_FACILITY, facility_ies);
}
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,6 +7057,7 @@ 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));
@ -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;