summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2012-09-25 19:29:14 +0000
committerMark Michelson <mmichelson@digium.com>2012-09-25 19:29:14 +0000
commitfdfb3ae5faac680bf939eea1312919bee14db76f (patch)
tree75907425ac9b850412fae5bc7b7e6d89e1aa19e1 /channels
parentb7233b18ebd9ce2f8f4bad1309fbe33edaf44e44 (diff)
Allow for redirecting reasons to be set to arbitrary strings.
This allows for the REDIRECTING dialplan function to be used to set the reason to any string. The SIP channel driver has been modified to set the redirecting reason string to the value received in a Diversion header. In addition, SIP 480 response reason text will set the redirecting reason as well. (closes issue AST-942) reported by Malcolm Davenport (closes issue AST-943) reported by Malcolm Davenport Review: https://reviewboard.asterisk.org/r/2101 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@373701 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_misdn.c4
-rw-r--r--channels/chan_sip.c138
-rw-r--r--channels/sig_pri.c8
3 files changed, 126 insertions, 24 deletions
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 3578bc54e..2f644a86e 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -6383,7 +6383,7 @@ static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct as
bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
}
- bc->redirecting.reason = ast_to_misdn_reason(ast_channel_redirecting(ast)->reason);
+ bc->redirecting.reason = ast_to_misdn_reason(ast_channel_redirecting(ast)->reason.code);
bc->redirecting.count = ast_channel_redirecting(ast)->count;
}
@@ -6427,7 +6427,7 @@ static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct
| misdn_to_ast_screen(redirect->to.screening);
redirecting.to.tag = tag;
- redirecting.reason = misdn_to_ast_reason(redirect->reason);
+ redirecting.reason.code = misdn_to_ast_reason(redirect->reason);
redirecting.count = redirect->count;
ast_channel_set_redirecting(ast, &redirecting, &update_redirecting);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index e41ccc125..615f576fe 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1576,7 +1576,7 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
static int set_address_from_contact(struct sip_pvt *pvt);
static void check_via(struct sip_pvt *p, struct sip_request *req);
static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason, char **reason_str);
static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, int full, int timeout);
static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
@@ -2379,8 +2379,35 @@ static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text)
return ast;
}
-static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code)
+static const char *sip_reason_code_to_str(struct ast_party_redirecting_reason *reason, int *table_lookup)
{
+ int code = reason->code;
+
+ /* If there's a specific string set, then we just
+ * use it.
+ */
+ 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;
+ }
+
+ if (table_lookup) {
+ *table_lookup = TRUE;
+ }
+
if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) {
return sip_reason_table[code].text;
}
@@ -13528,7 +13555,9 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
{
struct ast_party_id diverting_from;
const char *reason;
+ int found_in_table;
char header_text[256];
+ char encoded_number[SIPBUFSIZE/2];
/* We skip this entirely if the configuration doesn't allow diversion headers */
if (!sip_cfg.send_diversion) {
@@ -13545,17 +13574,37 @@ static void add_diversion(struct sip_request *req, struct sip_pvt *pvt)
return;
}
- reason = sip_reason_code_to_str(ast_channel_redirecting(pvt->owner)->reason);
+ if (sip_cfg.pedanticsipchecking) {
+ ast_uri_encode(diverting_from.number.str, encoded_number, sizeof(encoded_number), ast_uri_sip_user);
+ } else {
+ 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);
/* We at least have a number to place in the Diversion header, which is enough */
if (!diverting_from.name.valid
|| ast_strlen_zero(diverting_from.name.str)) {
- snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_from.number.str,
- ast_sockaddr_stringify_host_remote(&pvt->ourip), reason);
+ snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s%s%s",
+ encoded_number,
+ ast_sockaddr_stringify_host_remote(&pvt->ourip),
+ found_in_table ? "" : "\"",
+ reason,
+ found_in_table ? "" : "\"");
} else {
- snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s",
- diverting_from.name.str, diverting_from.number.str,
- ast_sockaddr_stringify_host_remote(&pvt->ourip), reason);
+ char escaped_name[SIPBUFSIZE/2];
+ if (sip_cfg.pedanticsipchecking) {
+ ast_escape_quoted(diverting_from.name.str, escaped_name, sizeof(escaped_name));
+ } else {
+ 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",
+ escaped_name,
+ encoded_number,
+ ast_sockaddr_stringify_host_remote(&pvt->ourip),
+ found_in_table ? "" : "\"",
+ reason,
+ found_in_table ? "" : "\"");
}
add_header(req, "Diversion", header_text);
@@ -16839,8 +16888,19 @@ static int get_rpid(struct sip_pvt *p, struct sip_request *oreq)
return 1;
}
-/*! \brief Get referring dnis */
-static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason)
+/*! \brief Get referring dnis
+ *
+ * \param p dialog information
+ * \param oreq The request to retrieve RDNIS from
+ * \param[out] name The name of the party redirecting the call.
+ * \param[out] number The number of the party redirecting the call.
+ * \param[out] reason_code The numerical code corresponding to the reason for the redirection.
+ * \param[out] reason_str A string describing the reason for redirection. Will never be zero-length
+ *
+ * \retval -1 Could not retrieve RDNIS information
+ * \retval 0 RDNIS successfully retrieved
+ */
+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason_code, char **reason_str)
{
char tmp[256], *exten, *rexten, *rdomain, *rname = NULL;
char *params, *reason_param = NULL;
@@ -16897,9 +16957,9 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
if (p->owner)
pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain);
- if (sip_debug_test_pvt(p))
+ if (sip_debug_test_pvt(p)) {
ast_verbose("RDNIS for this call is %s (reason %s)\n", exten, S_OR(reason_param, ""));
-
+ }
/*ast_string_field_set(p, rdnis, rexten);*/
if (*tmp == '\"') {
@@ -16919,8 +16979,14 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
*name = ast_strdup(rname);
}
- if (reason && !ast_strlen_zero(reason_param)) {
- *reason = sip_reason_str_to_code(reason_param);
+ if (!ast_strlen_zero(reason_param)) {
+ if (reason_code) {
+ *reason_code = sip_reason_str_to_code(reason_param);
+ }
+
+ if (reason_str) {
+ *reason_str = ast_strdup(reason_param);
+ }
}
return 0;
@@ -21622,11 +21688,12 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
char *redirecting_from_number = NULL;
char *redirecting_to_name = NULL;
char *redirecting_to_number = NULL;
+ char *reason_str = NULL;
int reason = AST_REDIRECTING_REASON_UNCONDITIONAL;
int is_response = req->method == SIP_RESPONSE;
int res = 0;
- res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason);
+ res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason, &reason_str);
if (res == -1) {
if (is_response) {
get_name_and_number(sip_get_header(req, "TO"), &redirecting_from_name, &redirecting_from_number);
@@ -21679,7 +21746,12 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
ast_free(redirecting->to.name.str);
redirecting->to.name.str = redirecting_to_name;
}
- redirecting->reason = reason;
+ redirecting->reason.code = reason;
+ if (reason_str) {
+ ast_debug(3, "Got redirecting reason %s\n", reason_str);
+ ast_free(redirecting->reason.str);
+ redirecting->reason.str = reason_str;
+ }
}
/*! \brief Parse 302 Moved temporalily response
@@ -22450,6 +22522,28 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
}
break;
+ case 480: /* Temporarily unavailable. */
+ /* RFC 3261 encourages setting the reason phrase to something indicative
+ * of why the endpoint is not available. We will make this readable via the
+ * redirecting reason.
+ */
+ xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
+ append_history(p, "TempUnavailable", "Endpoint is temporarily unavailable.");
+ if (p->owner && !req->ignore) {
+ struct ast_party_redirecting redirecting;
+ struct ast_set_party_redirecting update_redirecting;
+ ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(p->owner));
+ memset(&update_redirecting, 0, sizeof(update_redirecting));
+
+ redirecting.reason.code = sip_reason_str_to_code(rest);
+ redirecting.reason.str = ast_strdup(rest);
+
+ ast_channel_queue_redirecting_update(p->owner, &redirecting, &update_redirecting);
+ ast_party_redirecting_free(&redirecting);
+
+ ast_queue_control(p->owner, AST_CONTROL_BUSY);
+ }
+ break;
case 487: /* Cancelled transaction */
/* We have sent CANCEL on an outbound INVITE
This transaction is already scheduled to be killed by sip_hangup().
@@ -23320,7 +23414,16 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
handle_response_invite(p, resp, rest, req, seqno);
}
break;
-
+ case 480:
+ if (sipmethod == SIP_INVITE) {
+ handle_response_invite(p, resp, rest, req, seqno);
+ } else if (sipmethod == SIP_SUBSCRIBE) {
+ handle_response_subscribe(p, resp, rest, req, seqno);
+ } else if (owner) {
+ /* No specific handler. Default to congestion */
+ ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+ }
+ break;
case 481: /* Call leg does not exist */
if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, seqno);
@@ -23409,7 +23512,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
}
break;
case 482: /* Loop Detected */
- case 480: /* Temporarily Unavailable */
case 404: /* Not Found */
case 410: /* Gone */
case 400: /* Bad Request */
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index bf73ced37..93a77efd7 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -916,8 +916,8 @@ static void sig_pri_redirecting_update(struct sig_pri_chan *pvt, struct ast_chan
sig_pri_party_id_from_ast(&pri_redirecting.to, &redirecting_to);
sig_pri_party_id_from_ast(&pri_redirecting.orig_called, &redirecting_orig);
pri_redirecting.count = ast_redirecting->count;
- pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason);
- pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason);
+ pri_redirecting.orig_reason = ast_to_pri_reason(ast_redirecting->orig_reason.code);
+ pri_redirecting.reason = ast_to_pri_reason(ast_redirecting->reason.code);
pri_redirecting_update(pvt->pri->pri, pvt->call, &pri_redirecting);
}
@@ -2177,8 +2177,8 @@ static void sig_pri_redirecting_convert(struct ast_party_redirecting *ast_redire
sig_pri_party_id_convert(&ast_redirecting->from, &pri_redirecting->from, pri);
sig_pri_party_id_convert(&ast_redirecting->to, &pri_redirecting->to, pri);
ast_redirecting->count = pri_redirecting->count;
- ast_redirecting->reason = pri_to_ast_reason(pri_redirecting->reason);
- ast_redirecting->orig_reason = pri_to_ast_reason(pri_redirecting->orig_reason);
+ ast_redirecting->reason.code = pri_to_ast_reason(pri_redirecting->reason);
+ ast_redirecting->orig_reason.code = pri_to_ast_reason(pri_redirecting->orig_reason);
}
/*!