[svn-commits] mmichelson: trunk r373701 - in /trunk: ./ channels/ funcs/ include/asterisk/ ...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Sep 25 14:29:21 CDT 2012


Author: mmichelson
Date: Tue Sep 25 14:29:14 2012
New Revision: 373701

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=373701
Log:
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


Modified:
    trunk/CHANGES
    trunk/channels/chan_misdn.c
    trunk/channels/chan_sip.c
    trunk/channels/sig_pri.c
    trunk/funcs/func_callerid.c
    trunk/include/asterisk/callerid.h
    trunk/include/asterisk/channel.h
    trunk/main/callerid.c
    trunk/main/channel.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Sep 25 14:29:14 2012
@@ -29,6 +29,13 @@
    Note: the suffix '_avail' after the queuename.
    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 --------------------

Modified: trunk/channels/chan_misdn.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_misdn.c?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/channels/chan_misdn.c (original)
+++ trunk/channels/chan_misdn.c Tue Sep 25 14:29:14 2012
@@ -6383,7 +6383,7 @@
 		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 @@
 		| 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);

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Tue Sep 25 14:29:14 2012
@@ -1576,7 +1576,7 @@
 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 @@
 	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 @@
 {
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 		*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 @@
 	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 @@
 		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 @@
 		}
 		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 @@
 				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 @@
 					}
 					break;
 				case 482: /* Loop Detected */
-				case 480: /* Temporarily Unavailable */
 				case 404: /* Not Found */
 				case 410: /* Gone */
 				case 400: /* Bad Request */

Modified: trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.c?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/channels/sig_pri.c (original)
+++ trunk/channels/sig_pri.c Tue Sep 25 14:29:14 2012
@@ -916,8 +916,8 @@
 	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 @@
 	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);
 }
 
 /*!

Modified: trunk/funcs/func_callerid.c
URL: http://svnview.digium.com/svn/asterisk/trunk/funcs/func_callerid.c?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/funcs/func_callerid.c (original)
+++ trunk/funcs/func_callerid.c Tue Sep 25 14:29:14 2012
@@ -1493,7 +1493,7 @@
 	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 @@
 			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 @@
 			}
 
 			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 @@
 		}
 
 		if (reason < 0) {
-			ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val);
-		} else {
-			redirecting.reason = reason;
+			/* 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.code = reason;
+			redirecting.reason.str = "";
 			set_it(chan, &redirecting, NULL);
 		}
 	} else if (member.argc == 1 && !strcasecmp("count", member.argv[0])) {

Modified: trunk/include/asterisk/callerid.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/callerid.h?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/include/asterisk/callerid.h (original)
+++ trunk/include/asterisk/callerid.h Tue Sep 25 14:29:14 2012
@@ -424,15 +424,17 @@
  */
 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

Modified: trunk/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/channel.h?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Tue Sep 25 14:29:14 2012
@@ -450,6 +450,21 @@
 };
 
 /*!
+ * \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 @@
 	/*! \brief Call is redirecting to a new party (Sent to the caller)  - private representation */
 	struct ast_party_id priv_to;
 
+	/*! \brief Reason for the redirection */
+	struct ast_party_redirecting_reason reason;
+
+	/*! \brief Reason for the redirection by the original party */
+	struct ast_party_redirecting_reason orig_reason;
+
 	/*! \brief Number of times the call was redirected */
 	int count;
-
-	/*! \brief enum AST_REDIRECTING_REASON value for redirection */
-	int reason;
-
-	/*! \brief enum AST_REDIRECTING_REASON value for redirection by original party */
-	int orig_reason;
 };
 
 /*!
@@ -3227,6 +3242,68 @@
  * \return Nothing
  */
 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.

Modified: trunk/main/callerid.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/callerid.c?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/main/callerid.c (original)
+++ trunk/main/callerid.c Tue Sep 25 14:29:14 2012
@@ -1237,12 +1237,17 @@
 	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;
 		}
 	}

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=373701&r1=373700&r2=373701
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Tue Sep 25 14:29:14 2012
@@ -2235,6 +2235,49 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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,7 +9741,47 @@
 	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)
 {
@@ -9818,6 +9903,15 @@
 		.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 @@
 	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 @@
 				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);
-			break;
-/* Redirecting orig-reason */
-		case AST_REDIRECTING_ORIG_REASON:
+			redirecting->reason.code = ntohl(value);
+			break;
+/* 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:




More information about the svn-commits mailing list