mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-13 16:21:01 +00:00
Merge "SIP diversion: Fix REDIRECTING(reason) value inconsistencies." into 13
This commit is contained in:
30
CHANGES
30
CHANGES
@@ -29,6 +29,36 @@ app_confbridge
|
|||||||
conference state and made the locked column a yes/no value instead of a
|
conference state and made the locked column a yes/no value instead of a
|
||||||
locked/unlocked value.
|
locked/unlocked value.
|
||||||
|
|
||||||
|
REDIRECTING(reason)
|
||||||
|
------------------
|
||||||
|
* The REDIRECTING(reason) value is now treated consistently between
|
||||||
|
chan_sip and chan_pjsip.
|
||||||
|
|
||||||
|
Both channel drivers match incoming reason values with values documented
|
||||||
|
by REDIRECTING(reason) and values documented by RFC5806 regardless of
|
||||||
|
whether they are quoted or not. RFC5806 values are mapped to the
|
||||||
|
equivalent REDIRECTING(reason) documented value and is set in
|
||||||
|
REDIRECTING(reason). e.g., an incoming RFC5806 'unconditional' value or a
|
||||||
|
quoted string version ('"unconditional"') is converted to
|
||||||
|
REDIRECTING(reason)'s 'cfu' value. The user's dialplan only needs to deal
|
||||||
|
with 'cfu' instead of any of the aliases.
|
||||||
|
|
||||||
|
The incoming 480 response reason text supported by chan_sip checks for
|
||||||
|
known reason values and if not matched then puts quotes around the reason
|
||||||
|
string and assigns that to REDIRECTING(reason).
|
||||||
|
|
||||||
|
Both channel drivers send outgoing known REDIRECTING(reason) values as the
|
||||||
|
unquoted RFC5806 equivalent. User custom values are either sent as is or
|
||||||
|
with added quotes if SIP doesn't allow a character within the value as
|
||||||
|
part of a RFC3261 Section 25.1 token. Note that there are still
|
||||||
|
limitations on what characters can be put in a custom user value. e.g.,
|
||||||
|
embedding quotes in the middle of the reason string is just going to cause
|
||||||
|
you grief.
|
||||||
|
|
||||||
|
* Setting a REDIRECTING(reason) value now recognizes RFC5806 aliases.
|
||||||
|
e.g., Setting REDIRECTING(reason) to 'unconditional' is converted to the
|
||||||
|
'cfu' value.
|
||||||
|
|
||||||
res_pjproject
|
res_pjproject
|
||||||
------------------
|
------------------
|
||||||
* This module is the successor of res_pjsip_log_forwarder. As well as
|
* This module is the successor of res_pjsip_log_forwarder. As well as
|
||||||
|
@@ -28,6 +28,9 @@ res_pjsip:
|
|||||||
res_pjproject must be explicitly loaded or res_pjsip and all of its
|
res_pjproject must be explicitly loaded or res_pjsip and all of its
|
||||||
dependents will fail to load.
|
dependents will fail to load.
|
||||||
|
|
||||||
|
REDIRECTING(reason):
|
||||||
|
- See the CHANGES file for a description of the behavior change.
|
||||||
|
|
||||||
ODBC:
|
ODBC:
|
||||||
- Connection pooling/sharing has been completely removed from Asterisk
|
- Connection pooling/sharing has been completely removed from Asterisk
|
||||||
in favor of letting ODBC take care of it instead. It is strongly
|
in favor of letting ODBC take care of it instead. It is strongly
|
||||||
|
@@ -710,7 +710,7 @@ static const struct cfsip_methods {
|
|||||||
*/
|
*/
|
||||||
static const struct sip_reasons {
|
static const struct sip_reasons {
|
||||||
enum AST_REDIRECTING_REASON code;
|
enum AST_REDIRECTING_REASON code;
|
||||||
char * const text;
|
const char *text;
|
||||||
} sip_reason_table[] = {
|
} sip_reason_table[] = {
|
||||||
{ AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
|
{ AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
|
||||||
{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
|
{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
|
||||||
@@ -723,8 +723,8 @@ static const struct sip_reasons {
|
|||||||
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
|
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
|
||||||
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
|
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
|
||||||
{ AST_REDIRECTING_REASON_AWAY, "away" },
|
{ AST_REDIRECTING_REASON_AWAY, "away" },
|
||||||
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"},
|
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte" }, /* Non-standard */
|
||||||
{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"},
|
{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm" }, /* Non-standard */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2370,52 +2370,54 @@ static int map_s_x(const struct _map_x_s *table, const char *s, int errorvalue)
|
|||||||
return errorvalue;
|
return errorvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text)
|
/*!
|
||||||
|
* \internal
|
||||||
|
* \brief Determine if the given string is a SIP token.
|
||||||
|
* \since 13.8.0
|
||||||
|
*
|
||||||
|
* \param str String to determine if is a SIP token.
|
||||||
|
*
|
||||||
|
* \note A token is defined by RFC3261 Section 25.1
|
||||||
|
*
|
||||||
|
* \return Non-zero if the string is a SIP token.
|
||||||
|
*/
|
||||||
|
static int sip_is_token(const char *str)
|
||||||
{
|
{
|
||||||
enum AST_REDIRECTING_REASON ast = AST_REDIRECTING_REASON_UNKNOWN;
|
int is_token;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LEN(sip_reason_table); ++i) {
|
if (ast_strlen_zero(str)) {
|
||||||
if (!strcasecmp(text, sip_reason_table[i].text)) {
|
/* An empty string is not a token. */
|
||||||
ast = sip_reason_table[i].code;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ast;
|
is_token = 1;
|
||||||
|
do {
|
||||||
|
if (!isalnum(*str)
|
||||||
|
&& !strchr("-.!%*_+`'~", *str)) {
|
||||||
|
/* The character is not allowed in a token. */
|
||||||
|
is_token = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (*++str);
|
||||||
|
|
||||||
|
return is_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *reason, int *table_lookup)
|
static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *reason)
|
||||||
{
|
{
|
||||||
int code = reason->code;
|
int idx;
|
||||||
|
int code;
|
||||||
|
|
||||||
/* If there's a specific string set, then we just
|
/* use specific string if given */
|
||||||
* use it.
|
|
||||||
*/
|
|
||||||
if (!ast_strlen_zero(reason->str)) {
|
if (!ast_strlen_zero(reason->str)) {
|
||||||
/* If we care about whether this can be found in
|
|
||||||
* the table, then we need to check about that.
|
|
||||||
*/
|
|
||||||
if (table_lookup) {
|
|
||||||
/* If the string is literally "unknown" then don't bother with the lookup
|
|
||||||
* because it can lead to a false negative.
|
|
||||||
*/
|
|
||||||
if (!strcasecmp(reason->str, "unknown") ||
|
|
||||||
sip_reason_str_to_code(reason->str) != AST_REDIRECTING_REASON_UNKNOWN) {
|
|
||||||
*table_lookup = TRUE;
|
|
||||||
} else {
|
|
||||||
*table_lookup = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return reason->str;
|
return reason->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table_lookup) {
|
code = reason->code;
|
||||||
*table_lookup = TRUE;
|
for (idx = 0; idx < ARRAY_LEN(sip_reason_table); ++idx) {
|
||||||
}
|
if (code == sip_reason_table[idx].code) {
|
||||||
|
return sip_reason_table[idx].text;
|
||||||
if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) {
|
}
|
||||||
return sip_reason_table[code].text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
@@ -14218,7 +14220,7 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
|
|||||||
{
|
{
|
||||||
struct ast_party_id diverting_from;
|
struct ast_party_id diverting_from;
|
||||||
const char *reason;
|
const char *reason;
|
||||||
int found_in_table;
|
const char *quote_str;
|
||||||
char header_text[256];
|
char header_text[256];
|
||||||
char encoded_number[SIPBUFSIZE/2];
|
char encoded_number[SIPBUFSIZE/2];
|
||||||
|
|
||||||
@@ -14243,17 +14245,18 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
|
|||||||
ast_copy_string(encoded_number, diverting_from.number.str, sizeof(encoded_number));
|
ast_copy_string(encoded_number, diverting_from.number.str, sizeof(encoded_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
reason = sip_reason_code_to_str(&ast_channel_redirecting(pvt->owner)->reason, &found_in_table);
|
reason = sip_reason_code_to_str(&ast_channel_redirecting(pvt->owner)->reason);
|
||||||
|
|
||||||
|
/* Reason is either already quoted or it is a token to not need quotes added. */
|
||||||
|
quote_str = *reason == '\"' || sip_is_token(reason) ? "" : "\"";
|
||||||
|
|
||||||
/* We at least have a number to place in the Diversion header, which is enough */
|
/* We at least have a number to place in the Diversion header, which is enough */
|
||||||
if (!diverting_from.name.valid
|
if (!diverting_from.name.valid
|
||||||
|| ast_strlen_zero(diverting_from.name.str)) {
|
|| ast_strlen_zero(diverting_from.name.str)) {
|
||||||
snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s%s%s",
|
snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s%s%s",
|
||||||
encoded_number,
|
encoded_number,
|
||||||
ast_sockaddr_stringify_host_remote(&pvt->ourip),
|
ast_sockaddr_stringify_host_remote(&pvt->ourip),
|
||||||
found_in_table ? "" : "\"",
|
quote_str, reason, quote_str);
|
||||||
reason,
|
|
||||||
found_in_table ? "" : "\"");
|
|
||||||
} else {
|
} else {
|
||||||
char escaped_name[SIPBUFSIZE/2];
|
char escaped_name[SIPBUFSIZE/2];
|
||||||
if (sip_cfg.pedanticsipchecking) {
|
if (sip_cfg.pedanticsipchecking) {
|
||||||
@@ -14262,12 +14265,10 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
|
|||||||
ast_copy_string(escaped_name, diverting_from.name.str, sizeof(escaped_name));
|
ast_copy_string(escaped_name, diverting_from.name.str, sizeof(escaped_name));
|
||||||
}
|
}
|
||||||
snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s%s%s",
|
snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s%s%s",
|
||||||
escaped_name,
|
escaped_name,
|
||||||
encoded_number,
|
encoded_number,
|
||||||
ast_sockaddr_stringify_host_remote(&pvt->ourip),
|
ast_sockaddr_stringify_host_remote(&pvt->ourip),
|
||||||
found_in_table ? "" : "\"",
|
quote_str, reason, quote_str);
|
||||||
reason,
|
|
||||||
found_in_table ? "" : "\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_header(req, "Diversion", header_text);
|
add_header(req, "Diversion", header_text);
|
||||||
@@ -17696,6 +17697,9 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
|
|||||||
char *params, *reason_param = NULL;
|
char *params, *reason_param = NULL;
|
||||||
struct sip_request *req;
|
struct sip_request *req;
|
||||||
|
|
||||||
|
ast_assert(reason_code != NULL);
|
||||||
|
ast_assert(reason_str != NULL);
|
||||||
|
|
||||||
req = oreq ? oreq : &p->initreq;
|
req = oreq ? oreq : &p->initreq;
|
||||||
|
|
||||||
ast_copy_string(tmp, sip_get_header(req, "Diversion"), sizeof(tmp));
|
ast_copy_string(tmp, sip_get_header(req, "Diversion"), sizeof(tmp));
|
||||||
@@ -17729,16 +17733,6 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
|
|||||||
if ((end = strchr(reason_param, ';'))) {
|
if ((end = strchr(reason_param, ';'))) {
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
}
|
}
|
||||||
/* Remove enclosing double-quotes */
|
|
||||||
if (*reason_param == '"')
|
|
||||||
reason_param = ast_strip_quoted(reason_param, "\"", "\"");
|
|
||||||
if (!ast_strlen_zero(reason_param)) {
|
|
||||||
sip_set_redirstr(p, reason_param);
|
|
||||||
if (p->owner) {
|
|
||||||
pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause);
|
|
||||||
pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17770,12 +17764,27 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ast_strlen_zero(reason_param)) {
|
if (!ast_strlen_zero(reason_param)) {
|
||||||
if (reason_code) {
|
*reason_str = ast_strdup(reason_param);
|
||||||
*reason_code = sip_reason_str_to_code(reason_param);
|
|
||||||
|
/* Remove any enclosing double-quotes */
|
||||||
|
if (*reason_param == '"') {
|
||||||
|
reason_param = ast_strip_quoted(reason_param, "\"", "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason_str) {
|
*reason_code = ast_redirecting_reason_parse(reason_param);
|
||||||
*reason_str = ast_strdup(reason_param);
|
if (*reason_code < 0) {
|
||||||
|
*reason_code = AST_REDIRECTING_REASON_UNKNOWN;
|
||||||
|
} else {
|
||||||
|
ast_free(*reason_str);
|
||||||
|
*reason_str = ast_strdup("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(reason_param)) {
|
||||||
|
sip_set_redirstr(p, reason_param);
|
||||||
|
if (p->owner) {
|
||||||
|
pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause);
|
||||||
|
pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22650,10 +22659,11 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
|
|||||||
redirecting->to.name.str = redirecting_to_name;
|
redirecting->to.name.str = redirecting_to_name;
|
||||||
}
|
}
|
||||||
redirecting->reason.code = reason;
|
redirecting->reason.code = reason;
|
||||||
|
ast_free(redirecting->reason.str);
|
||||||
|
redirecting->reason.str = reason_str;
|
||||||
if (reason_str) {
|
if (reason_str) {
|
||||||
ast_debug(3, "Got redirecting reason %s\n", reason_str);
|
ast_debug(3, "Got redirecting reason %s\n", ast_strlen_zero(reason_str)
|
||||||
ast_free(redirecting->reason.str);
|
? sip_reason_code_to_str(&redirecting->reason) : reason_str);
|
||||||
redirecting->reason.str = reason_str;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23453,14 +23463,22 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
|
|||||||
if (p->owner && !req->ignore) {
|
if (p->owner && !req->ignore) {
|
||||||
struct ast_party_redirecting redirecting;
|
struct ast_party_redirecting redirecting;
|
||||||
struct ast_set_party_redirecting update_redirecting;
|
struct ast_set_party_redirecting update_redirecting;
|
||||||
|
char *quoted_rest = ast_alloca(strlen(rest) + 3);
|
||||||
|
|
||||||
ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(p->owner));
|
ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(p->owner));
|
||||||
memset(&update_redirecting, 0, sizeof(update_redirecting));
|
memset(&update_redirecting, 0, sizeof(update_redirecting));
|
||||||
|
|
||||||
redirecting.reason.code = sip_reason_str_to_code(rest);
|
redirecting.reason.code = ast_redirecting_reason_parse(rest);
|
||||||
redirecting.reason.str = ast_strdup(rest);
|
if (redirecting.reason.code < 0) {
|
||||||
|
sprintf(quoted_rest, "\"%s\"", rest);/* Safe */
|
||||||
|
|
||||||
|
redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN;
|
||||||
|
redirecting.reason.str = quoted_rest;
|
||||||
|
} else {
|
||||||
|
redirecting.reason.str = "";
|
||||||
|
}
|
||||||
|
|
||||||
ast_channel_queue_redirecting_update(p->owner, &redirecting, &update_redirecting);
|
ast_channel_queue_redirecting_update(p->owner, &redirecting, &update_redirecting);
|
||||||
ast_party_redirecting_free(&redirecting);
|
|
||||||
|
|
||||||
ast_queue_control(p->owner, AST_CONTROL_BUSY);
|
ast_queue_control(p->owner, AST_CONTROL_BUSY);
|
||||||
}
|
}
|
||||||
|
@@ -1209,7 +1209,16 @@ static const struct ast_value_translation redirecting_reason_types[] = {
|
|||||||
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
|
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
|
||||||
{ AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
|
{ AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
|
||||||
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
|
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
|
||||||
{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", "Call is being redirected to user's voicemail"},
|
{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", "Call is being redirected to user's voicemail" },
|
||||||
|
|
||||||
|
/* Convenience SIP aliases. Alias descriptions are not used. */
|
||||||
|
{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
|
||||||
|
{ AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
|
||||||
|
{ AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
|
||||||
|
{ AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
|
||||||
|
{ AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
|
||||||
|
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
|
||||||
|
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1232,7 +1241,7 @@ const char *ast_redirecting_reason_describe(int data)
|
|||||||
|
|
||||||
for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
|
for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
|
||||||
if (redirecting_reason_types[index].value == data) {
|
if (redirecting_reason_types[index].value == data) {
|
||||||
return redirecting_reason_types[index].description;
|
return redirecting_reason_types[index].description ?: "Redirecting reason alias-bug";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,6 +37,39 @@
|
|||||||
|
|
||||||
static const pj_str_t diversion_name = { "Diversion", 9 };
|
static const pj_str_t diversion_name = { "Diversion", 9 };
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* \brief Determine if the given string is a SIP token.
|
||||||
|
* \since 13.8.0
|
||||||
|
*
|
||||||
|
* \param str String to determine if is a SIP token.
|
||||||
|
*
|
||||||
|
* \note A token is defined by RFC3261 Section 25.1
|
||||||
|
*
|
||||||
|
* \return Non-zero if the string is a SIP token.
|
||||||
|
*/
|
||||||
|
static int sip_is_token(const char *str)
|
||||||
|
{
|
||||||
|
int is_token;
|
||||||
|
|
||||||
|
if (ast_strlen_zero(str)) {
|
||||||
|
/* An empty string is not a token. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_token = 1;
|
||||||
|
do {
|
||||||
|
if (!isalnum(*str)
|
||||||
|
&& !strchr("-.!%*_+`'~", *str)) {
|
||||||
|
/* The character is not allowed in a token. */
|
||||||
|
is_token = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (*++str);
|
||||||
|
|
||||||
|
return is_token;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Diversion header reasons
|
/*! \brief Diversion header reasons
|
||||||
*
|
*
|
||||||
* The core defines a bunch of constants used to define
|
* The core defines a bunch of constants used to define
|
||||||
@@ -46,7 +79,7 @@ static const pj_str_t diversion_name = { "Diversion", 9 };
|
|||||||
*/
|
*/
|
||||||
static const struct reasons {
|
static const struct reasons {
|
||||||
enum AST_REDIRECTING_REASON code;
|
enum AST_REDIRECTING_REASON code;
|
||||||
char *const text;
|
const char *text;
|
||||||
} reason_table[] = {
|
} reason_table[] = {
|
||||||
{ AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
|
{ AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
|
||||||
{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
|
{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
|
||||||
@@ -59,39 +92,28 @@ static const struct reasons {
|
|||||||
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
|
{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
|
||||||
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
|
{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
|
||||||
{ AST_REDIRECTING_REASON_AWAY, "away" },
|
{ AST_REDIRECTING_REASON_AWAY, "away" },
|
||||||
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"},
|
{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte" }, /* Non-standard */
|
||||||
{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm"},
|
{ AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm" }, /* Non-standard */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
|
static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
|
||||||
{
|
{
|
||||||
int code = reason->code;
|
int idx;
|
||||||
|
int code;
|
||||||
|
|
||||||
/* use specific string if given */
|
/* use specific string if given */
|
||||||
if (!ast_strlen_zero(reason->str)) {
|
if (!ast_strlen_zero(reason->str)) {
|
||||||
return reason->str;
|
return reason->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code >= 0 && code < ARRAY_LEN(reason_table)) {
|
code = reason->code;
|
||||||
return reason_table[code].text;
|
for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
|
||||||
}
|
if (code == reason_table[idx].code) {
|
||||||
|
return reason_table[idx].text;
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum AST_REDIRECTING_REASON reason_str_to_code(const char *text)
|
|
||||||
{
|
|
||||||
enum AST_REDIRECTING_REASON code = AST_REDIRECTING_REASON_UNKNOWN;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LEN(reason_table); ++i) {
|
|
||||||
if (!strcasecmp(text, reason_table[i].text)) {
|
|
||||||
code = reason_table[i].code;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
|
static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
|
||||||
@@ -159,13 +181,31 @@ static void set_redirecting_reason(pjsip_fromto_hdr *hdr,
|
|||||||
{
|
{
|
||||||
static const pj_str_t reason_name = { "reason", 6 };
|
static const pj_str_t reason_name = { "reason", 6 };
|
||||||
pjsip_param *reason = pjsip_param_find(&hdr->other_param, &reason_name);
|
pjsip_param *reason = pjsip_param_find(&hdr->other_param, &reason_name);
|
||||||
|
char *reason_str;
|
||||||
|
|
||||||
if (!reason) {
|
if (!reason) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_redirecting_value(&data->str, &reason->value);
|
set_redirecting_value(&data->str, &reason->value);
|
||||||
data->code = reason_str_to_code(data->str);
|
if (!data->str) {
|
||||||
|
/* Oops, allocation failure */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reason_str = ast_strdupa(data->str);
|
||||||
|
|
||||||
|
/* Remove any enclosing double-quotes */
|
||||||
|
if (*reason_str == '"') {
|
||||||
|
reason_str = ast_strip_quoted(reason_str, "\"", "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
data->code = ast_redirecting_reason_parse(reason_str);
|
||||||
|
if (data->code < 0) {
|
||||||
|
data->code = AST_REDIRECTING_REASON_UNKNOWN;
|
||||||
|
} else {
|
||||||
|
ast_free(data->str);
|
||||||
|
data->str = ast_strdup("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_redirecting(struct ast_sip_session *session,
|
static void set_redirecting(struct ast_sip_session *session,
|
||||||
@@ -251,6 +291,9 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect
|
|||||||
pjsip_sip_uri *uri;
|
pjsip_sip_uri *uri;
|
||||||
pjsip_param *param;
|
pjsip_param *param;
|
||||||
pjsip_fromto_hdr *old_hdr;
|
pjsip_fromto_hdr *old_hdr;
|
||||||
|
const char *reason_str;
|
||||||
|
const char *quote_str;
|
||||||
|
char *reason_buf;
|
||||||
|
|
||||||
struct ast_party_id *id = &data->from;
|
struct ast_party_id *id = &data->from;
|
||||||
pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
|
pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
|
||||||
@@ -272,7 +315,17 @@ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirect
|
|||||||
|
|
||||||
param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
|
param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
|
||||||
param->name = pj_str("reason");
|
param->name = pj_str("reason");
|
||||||
param->value = pj_str((char*)reason_code_to_str(&data->reason));
|
|
||||||
|
reason_str = reason_code_to_str(&data->reason);
|
||||||
|
|
||||||
|
/* Reason is either already quoted or it is a token to not need quotes added. */
|
||||||
|
quote_str = *reason_str == '\"' || sip_is_token(reason_str) ? "" : "\"";
|
||||||
|
|
||||||
|
reason_buf = pj_pool_alloc(tdata->pool, strlen(reason_str) + 3);
|
||||||
|
sprintf(reason_buf, "%s%s%s", quote_str, reason_str, quote_str);/* Safe */
|
||||||
|
|
||||||
|
param->value = pj_str(reason_buf);
|
||||||
|
|
||||||
pj_list_insert_before(&hdr->other_param, param);
|
pj_list_insert_before(&hdr->other_param, param);
|
||||||
|
|
||||||
hdr->uri = (pjsip_uri *) name_addr;
|
hdr->uri = (pjsip_uri *) name_addr;
|
||||||
|
Reference in New Issue
Block a user