diff options
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 138 |
1 files changed, 120 insertions, 18 deletions
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 */ |