diff options
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | channels/chan_misdn.c | 4 | ||||
-rw-r--r-- | channels/chan_sip.c | 138 | ||||
-rw-r--r-- | channels/sig_pri.c | 8 | ||||
-rw-r--r-- | funcs/func_callerid.c | 27 | ||||
-rw-r--r-- | include/asterisk/callerid.h | 6 | ||||
-rw-r--r-- | include/asterisk/channel.h | 89 | ||||
-rw-r--r-- | main/callerid.c | 9 | ||||
-rw-r--r-- | main/channel.c | 166 |
9 files changed, 383 insertions, 71 deletions
@@ -30,6 +30,13 @@ Queue Reports 'InUse' for no logged in agents or no free agents. Reports 'Idle' when an agent is free. +Core +------------------ + * Redirecting reasons can now be set to arbitrary strings. This means + that the REDIRECTING dialplan function can be used to set the redirecting + reason to any string. It also allows for custom strings to be read as the + redirecting reason from SIP Diversion headers. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 10 to Asterisk 11 -------------------- ------------------------------------------------------------------------------ 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); } /*! diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c index 789575399..30026af3d 100644 --- a/funcs/func_callerid.c +++ b/funcs/func_callerid.c @@ -1493,7 +1493,7 @@ static int redirecting_read(struct ast_channel *chan, const char *cmd, char *dat if (!strcasecmp("orig", member.argv[0])) { if (member.argc == 2 && !strcasecmp("reason", member.argv[1])) { ast_copy_string(buf, - ast_redirecting_reason_name(ast_redirecting->orig_reason), len); + ast_redirecting_reason_name(&ast_redirecting->orig_reason), len); } else { status = party_id_read(buf, len, member.argc - 1, member.argv + 1, &ast_redirecting->orig); @@ -1537,7 +1537,7 @@ static int redirecting_read(struct ast_channel *chan, const char *cmd, char *dat ast_named_caller_presentation( ast_party_id_presentation(&ast_redirecting->from)), len); } else if (member.argc == 1 && !strcasecmp("reason", member.argv[0])) { - ast_copy_string(buf, ast_redirecting_reason_name(ast_redirecting->reason), len); + ast_copy_string(buf, ast_redirecting_reason_name(&ast_redirecting->reason), len); } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) { snprintf(buf, len, "%d", ast_redirecting->count); } else if (1 < member.argc && !strcasecmp("priv", member.argv[0])) { @@ -1659,10 +1659,16 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da } if (reason < 0) { - ast_log(LOG_ERROR, - "Unknown redirecting orig reason '%s', value unchanged\n", val); + /* The argument passed into the function does not correspond to a pre-defined + * reason, so we can just set the reason string to what was given and set the + * code to be unknown + */ + redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN; + redirecting.orig_reason.str = val; + set_it(chan, &redirecting, NULL); } else { - redirecting.orig_reason = reason; + redirecting.orig_reason.code = reason; + redirecting.orig_reason.str = ""; set_it(chan, &redirecting, NULL); } } else { @@ -1742,9 +1748,16 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da } if (reason < 0) { - ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val); + /* The argument passed into the function does not correspond to a pre-defined + * reason, so we can just set the reason string to what was given and set the + * code to be unknown + */ + redirecting.reason.code = AST_REDIRECTING_REASON_UNKNOWN; + redirecting.reason.str = val; + set_it(chan, &redirecting, NULL); } else { - redirecting.reason = reason; + redirecting.reason.code = reason; + redirecting.reason.str = ""; set_it(chan, &redirecting, NULL); } } else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) { diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h index 7c4905e13..4f32dbf66 100644 --- a/include/asterisk/callerid.h +++ b/include/asterisk/callerid.h @@ -424,15 +424,17 @@ int ast_redirecting_reason_parse(const char *data); */ const char *ast_redirecting_reason_describe(int data); +struct ast_party_redirecting_reason; + /*! * \since 1.8 * \brief Convert redirecting reason value to text code * - * \param data Q931_REDIRECTING_REASON from callerid.h + * \param data ast_party_redirecting_reason structure from channel.h * * \return string for config file */ -const char *ast_redirecting_reason_name(int data); +const char *ast_redirecting_reason_name(const struct ast_party_redirecting_reason *data); /*! * \brief Connected line update source code diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index b60c8ad00..fed032a3d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -450,6 +450,21 @@ struct ast_set_party_connected_line { }; /*! + * \brief Redirecting reason information + */ +struct ast_party_redirecting_reason { + /*! \brief a string value for the redirecting reason + * + * Useful for cases where an endpoint has specified a redirecting reason + * that does not correspond to an enum AST_REDIRECTING_REASON + */ + char *str; + + /*! \brief enum AST_REDIRECTING_REASON value for redirection */ + int code; +}; + +/*! * \since 1.8 * \brief Redirecting Line information. * RDNIS (Redirecting Directory Number Information Service) @@ -477,14 +492,14 @@ struct ast_party_redirecting { /*! \brief Call is redirecting to a new party (Sent to the caller) - private representation */ struct ast_party_id priv_to; - /*! \brief Number of times the call was redirected */ - int count; + /*! \brief Reason for the redirection */ + struct ast_party_redirecting_reason reason; - /*! \brief enum AST_REDIRECTING_REASON value for redirection */ - int reason; + /*! \brief Reason for the redirection by the original party */ + struct ast_party_redirecting_reason orig_reason; - /*! \brief enum AST_REDIRECTING_REASON value for redirection by original party */ - int orig_reason; + /*! \brief Number of times the call was redirected */ + int count; }; /*! @@ -3229,6 +3244,68 @@ void ast_party_connected_line_collect_caller(struct ast_party_connected_line *co void ast_party_connected_line_free(struct ast_party_connected_line *doomed); /*! + * \brief Initialize the given redirecting reason structure + * + * \param init Redirecting reason structure to initialize + * + * \return Nothing + */ +void ast_party_redirecting_reason_init(struct ast_party_redirecting_reason *init); + +/*! + * \brief Copy the source redirecting reason information to the destination redirecting reason. + * + * \param dest Destination redirecting reason + * \param src Source redirecting reason + * + * \return Nothing + */ +void ast_party_redirecting_reason_copy(struct ast_party_redirecting_reason *dest, + const struct ast_party_redirecting_reason *src); + +/*! + * \brief Initialize the given redirecting reason structure using the given guide + * for a set update operation. + * + * \details + * The initialization is needed to allow a set operation to know if a + * value needs to be updated. Simple integers need the guide's original + * value in case the set operation is not trying to set a new value. + * String values are simply set to NULL pointers if they are not going + * to be updated. + * + * \param init Redirecting reason structure to initialize. + * \param guide Source redirecting reason to use as a guide in initializing. + * + * \return Nothing + */ +void ast_party_redirecting_reason_set_init(struct ast_party_redirecting_reason *init, + const struct ast_party_redirecting_reason *guide); + +/*! + * \brief Set the redirecting reason information based on another redirecting reason source + * + * This is similar to ast_party_redirecting_reason_copy, except that NULL values for + * strings in the src parameter indicate not to update the corresponding dest values. + * + * \param dest The redirecting reason one wishes to update + * \param src The new redirecting reason values to update the dest + * + * \return Nothing + */ +void ast_party_redirecting_reason_set(struct ast_party_redirecting_reason *dest, + const struct ast_party_redirecting_reason *src); + +/*! + * \brief Destroy the redirecting reason contents + * + * \param doomed The redirecting reason to destroy. + * + * \return Nothing + */ +void ast_party_redirecting_reason_free(struct ast_party_redirecting_reason *doomed); + +/*! * \brief Initialize the given redirecting structure. * \since 1.8 * diff --git a/main/callerid.c b/main/callerid.c index d9f74180a..db5e795ff 100644 --- a/main/callerid.c +++ b/main/callerid.c @@ -1237,12 +1237,17 @@ const char *ast_redirecting_reason_describe(int data) return "not-known"; } -const char *ast_redirecting_reason_name(int data) +const char *ast_redirecting_reason_name(const struct ast_party_redirecting_reason *data) { int index; + if (!ast_strlen_zero(data->str)) { + /* Use this string if it has been set. Otherwise, use the table. */ + return data->str; + } + for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) { - if (redirecting_reason_types[index].value == data) { + if (redirecting_reason_types[index].value == data->code) { return redirecting_reason_types[index].name; } } diff --git a/main/channel.c b/main/channel.c index dbc4703b5..751cbdd52 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2235,6 +2235,49 @@ void ast_party_connected_line_free(struct ast_party_connected_line *doomed) ast_party_id_free(&doomed->priv); } +void ast_party_redirecting_reason_init(struct ast_party_redirecting_reason *init) +{ + init->str = NULL; + init->code = AST_REDIRECTING_REASON_UNKNOWN; +} + +void ast_party_redirecting_reason_copy(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src) +{ + if (dest == src) { + return; + } + + ast_free(dest->str); + dest->str = ast_strdup(src->str); + dest->code = src->code; +} + +void ast_party_redirecting_reason_set_init(struct ast_party_redirecting_reason *init, const struct ast_party_redirecting_reason *guide) +{ + init->str = NULL; + init->code = guide->code; +} + +void ast_party_redirecting_reason_set(struct ast_party_redirecting_reason *dest, const struct ast_party_redirecting_reason *src) +{ + if (dest == src) { + return; + } + + if (src->str && src->str != dest->str) { + ast_free(dest->str); + dest->str = ast_strdup(src->str); + } + + dest->code = src->code; +} + +void ast_party_redirecting_reason_free(struct ast_party_redirecting_reason *doomed) +{ + ast_free(doomed->str); +} + + void ast_party_redirecting_init(struct ast_party_redirecting *init) { ast_party_id_init(&init->orig); @@ -2243,9 +2286,9 @@ void ast_party_redirecting_init(struct ast_party_redirecting *init) ast_party_id_init(&init->priv_orig); ast_party_id_init(&init->priv_from); ast_party_id_init(&init->priv_to); + ast_party_redirecting_reason_init(&init->reason); + ast_party_redirecting_reason_init(&init->orig_reason); init->count = 0; - init->reason = AST_REDIRECTING_REASON_UNKNOWN; - init->orig_reason = AST_REDIRECTING_REASON_UNKNOWN; } void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src) @@ -2261,9 +2304,9 @@ void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_id_copy(&dest->priv_orig, &src->priv_orig); ast_party_id_copy(&dest->priv_from, &src->priv_from); ast_party_id_copy(&dest->priv_to, &src->priv_to); + ast_party_redirecting_reason_copy(&dest->reason, &src->reason); + ast_party_redirecting_reason_copy(&dest->orig_reason, &src->orig_reason); dest->count = src->count; - dest->reason = src->reason; - dest->orig_reason = src->orig_reason; } void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide) @@ -2274,9 +2317,9 @@ void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const st ast_party_id_set_init(&init->priv_orig, &guide->priv_orig); ast_party_id_set_init(&init->priv_from, &guide->priv_from); ast_party_id_set_init(&init->priv_to, &guide->priv_to); + ast_party_redirecting_reason_set_init(&init->reason, &guide->reason); + ast_party_redirecting_reason_set_init(&init->orig_reason, &guide->orig_reason); init->count = guide->count; - init->reason = guide->reason; - init->orig_reason = guide->orig_reason; } void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src, const struct ast_set_party_redirecting *update) @@ -2287,9 +2330,9 @@ void ast_party_redirecting_set(struct ast_party_redirecting *dest, const struct ast_party_id_set(&dest->priv_orig, &src->priv_orig, update ? &update->priv_orig : NULL); ast_party_id_set(&dest->priv_from, &src->priv_from, update ? &update->priv_from : NULL); ast_party_id_set(&dest->priv_to, &src->priv_to, update ? &update->priv_to : NULL); + ast_party_redirecting_reason_set(&dest->reason, &src->reason); + ast_party_redirecting_reason_set(&dest->orig_reason, &src->orig_reason); dest->count = src->count; - dest->reason = src->reason; - dest->orig_reason = src->orig_reason; } void ast_party_redirecting_free(struct ast_party_redirecting *doomed) @@ -2300,6 +2343,8 @@ void ast_party_redirecting_free(struct ast_party_redirecting *doomed) ast_party_id_free(&doomed->priv_orig); ast_party_id_free(&doomed->priv_from); ast_party_id_free(&doomed->priv_to); + ast_party_redirecting_reason_free(&doomed->reason); + ast_party_redirecting_reason_free(&doomed->orig_reason); } /*! \brief Free a channel structure */ @@ -9616,7 +9661,7 @@ enum { AST_REDIRECTING_TO_NAME, AST_REDIRECTING_TO_NUMBER_PLAN, AST_REDIRECTING_TO_ID_PRESENTATION,/* Combined number and name presentation. */ - AST_REDIRECTING_REASON, + AST_REDIRECTING_REASON_CODE, AST_REDIRECTING_COUNT, AST_REDIRECTING_FROM_SUBADDRESS, AST_REDIRECTING_FROM_SUBADDRESS_TYPE, @@ -9656,7 +9701,7 @@ enum { AST_REDIRECTING_ORIG_SUBADDRESS_ODD_EVEN, AST_REDIRECTING_ORIG_SUBADDRESS_VALID, AST_REDIRECTING_ORIG_TAG, - AST_REDIRECTING_ORIG_REASON, + AST_REDIRECTING_ORIG_REASON_CODE, AST_REDIRECTING_PRIV_TO_NUMBER, AST_REDIRECTING_PRIV_TO_NUMBER_PLAN, AST_REDIRECTING_PRIV_TO_NUMBER_VALID, @@ -9696,8 +9741,48 @@ enum { AST_REDIRECTING_PRIV_ORIG_SUBADDRESS_ODD_EVEN, AST_REDIRECTING_PRIV_ORIG_SUBADDRESS_VALID, AST_REDIRECTING_PRIV_ORIG_TAG, + AST_REDIRECTING_REASON_STR, + AST_REDIRECTING_ORIG_REASON_STR, }; +struct ast_party_redirecting_reason_ies { + int code; + int str; +}; + +static int redirecting_reason_build_data(unsigned char *data, size_t datalen, + const struct ast_party_redirecting_reason *reason, const char *label, + const struct ast_party_redirecting_reason_ies *ies) +{ + size_t length; + size_t pos = 0; + int32_t value; + + if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { + ast_log(LOG_WARNING, "No space left for %s code\n", label); + return -1; + } + data[pos++] = ies->code; + data[pos++] = sizeof(value); + value = htonl(reason->code); + memcpy(data + pos, &value, sizeof(value)); + pos += sizeof(value); + + if (reason->str) { + length = strlen(reason->str); + if (datalen < pos + sizeof(data[0] * 2) + length) { + ast_log(LOG_WARNING, "No space left for %s string\n", label); + return -1; + } + data[pos++] = ies->str; + data[pos++] = length; + memcpy(data + pos, reason->str, length); + pos += length; + } + + return pos; +} + int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update) { int32_t value; @@ -9818,6 +9903,15 @@ int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct .tag = AST_REDIRECTING_PRIV_TO_TAG, .combined_presentation = 0,/* Not sent. */ }; + static const struct ast_party_redirecting_reason_ies reason_ies = { + .code = AST_REDIRECTING_REASON_CODE, + .str = AST_REDIRECTING_REASON_STR, + }; + + static const struct ast_party_redirecting_reason_ies orig_reason_ies = { + .code = AST_REDIRECTING_ORIG_REASON_CODE, + .str = AST_REDIRECTING_ORIG_REASON_STR, + }; /* Redirecting frame version */ if (datalen < pos + (sizeof(data[0]) * 2) + 1) { @@ -9871,26 +9965,20 @@ int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct pos += res; /* Redirecting reason */ - if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { - ast_log(LOG_WARNING, "No space left for redirecting reason\n"); + res = redirecting_reason_build_data(data + pos, datalen - pos, &redirecting->reason, + "redirecting-reason", &reason_ies); + if (res < 0) { return -1; } - data[pos++] = AST_REDIRECTING_REASON; - data[pos++] = sizeof(value); - value = htonl(redirecting->reason); - memcpy(data + pos, &value, sizeof(value)); - pos += sizeof(value); + pos += res; /* Redirecting original reason */ - if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { - ast_log(LOG_WARNING, "No space left for redirecting original reason\n"); + res = redirecting_reason_build_data(data + pos, datalen - pos, &redirecting->orig_reason, + "redirecting-orig-reason", &orig_reason_ies); + if (res < 0) { return -1; } - data[pos++] = AST_REDIRECTING_ORIG_REASON; - data[pos++] = sizeof(value); - value = htonl(redirecting->orig_reason); - memcpy(data + pos, &value, sizeof(value)); - pos += sizeof(value); + pos += res; /* Redirecting count */ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) { @@ -10614,25 +10702,43 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct redirecting->priv_to.tag[ie_len] = 0; } break; -/* Redirecting reason */ - case AST_REDIRECTING_REASON: +/* Redirecting reason code */ + case AST_REDIRECTING_REASON_CODE: if (ie_len != sizeof(value)) { ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", (unsigned) ie_len); break; } memcpy(&value, data + pos, sizeof(value)); - redirecting->reason = ntohl(value); + redirecting->reason.code = ntohl(value); break; -/* Redirecting orig-reason */ - case AST_REDIRECTING_ORIG_REASON: +/* Redirecting reason string */ + case AST_REDIRECTING_REASON_STR: + ast_free(redirecting->reason.str); + redirecting->reason.str = ast_malloc(ie_len + 1); + if (redirecting->reason.str) { + memcpy(redirecting->reason.str, data + pos, ie_len); + redirecting->reason.str[ie_len] = 0; + } + break; +/* Redirecting orig-reason code */ + case AST_REDIRECTING_ORIG_REASON_CODE: if (ie_len != sizeof(value)) { ast_log(LOG_WARNING, "Invalid redirecting original reason (%u)\n", (unsigned) ie_len); break; } memcpy(&value, data + pos, sizeof(value)); - redirecting->orig_reason = ntohl(value); + redirecting->orig_reason.code = ntohl(value); + break; +/* Redirecting orig-reason string */ + case AST_REDIRECTING_ORIG_REASON_STR: + ast_free(redirecting->orig_reason.str); + redirecting->orig_reason.str = ast_malloc(ie_len + 1); + if (redirecting->orig_reason.str) { + memcpy(redirecting->orig_reason.str, data + pos, ie_len); + redirecting->orig_reason.str[ie_len] = 0; + } break; /* Redirecting count */ case AST_REDIRECTING_COUNT: |