[asterisk-commits] file: trunk r403810 - in /trunk: ./ apps/ include/asterisk/ main/ res/ari/ re...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Dec 14 11:19:44 CST 2013


Author: file
Date: Sat Dec 14 11:19:41 2013
New Revision: 403810

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=403810
Log:
res_stasis: Expose event for call forwarding and follow forwarded channel.

This change adds an event for when an originated call is redirected to
another target. This event contains the original channel and the newly
created channel. If a stasis subscription exists on the original originated
channel for a stasis application then a new subscription will also be
created on the stasis application to the redirected channel. This allows
the application to follow the call path completely.

(closes issue ASTERISK-22719)
Reported by: Joshua Colp

Review: https://reviewboard.asterisk.org/r/3054/
........

Merged revisions 403808 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/apps/app_dial.c
    trunk/apps/app_queue.c
    trunk/include/asterisk/stasis_channels.h
    trunk/main/dial.c
    trunk/main/stasis_channels.c
    trunk/res/ari/ari_model_validators.c
    trunk/res/ari/ari_model_validators.h
    trunk/res/stasis/app.c
    trunk/rest-api/api-docs/events.json

Propchange: trunk/
------------------------------------------------------------------------------
--- branch-12-merged (original)
+++ branch-12-merged Sat Dec 14 11:19:41 2013
@@ -1,1 +1,1 @@
-/branches/12:1-398558,398560-398577,398579-399305,399307-401390,401392-403290,403292-403398,403435,403458,403510,403527,403541-403542,403545,403559,403587,403616,403618,403639,403680,403705,403713,403736,403749,403752,403767,403781-403782,403796
+/branches/12:1-398558,398560-398577,398579-399305,399307-401390,401392-403290,403292-403398,403435,403458,403510,403527,403541-403542,403545,403559,403587,403616,403618,403639,403680,403705,403713,403736,403749,403752,403767,403781-403782,403796,403808

Modified: trunk/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_dial.c?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/apps/app_dial.c (original)
+++ trunk/apps/app_dial.c Sat Dec 14 11:19:41 2013
@@ -1007,7 +1007,7 @@
 			ast_channel_unlock(c);
 
 			ast_channel_lock_both(original, in);
-			ast_channel_publish_dial_forward(in, original, NULL, "CANCEL",
+			ast_channel_publish_dial_forward(in, original, c, NULL, "CANCEL",
 				ast_channel_call_forward(c));
 			ast_channel_unlock(in);
 			ast_channel_unlock(original);

Modified: trunk/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_queue.c?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Sat Dec 14 11:19:41 2013
@@ -4666,7 +4666,7 @@
 					ast_channel_unlock(qe->chan);
 
 					ast_channel_lock_both(qe->chan, original);
-					ast_channel_publish_dial_forward(qe->chan, original, NULL, "CANCEL",
+					ast_channel_publish_dial_forward(qe->chan, original, o->chan, NULL, "CANCEL",
 						ast_channel_call_forward(original));
 					ast_channel_unlock(original);
 					ast_channel_unlock(qe->chan);

Modified: trunk/include/asterisk/stasis_channels.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/stasis_channels.h?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/include/asterisk/stasis_channels.h (original)
+++ trunk/include/asterisk/stasis_channels.h Sat Dec 14 11:19:41 2013
@@ -518,12 +518,14 @@
  *
  * \param caller The channel performing the dial operation
  * \param peer The channel being dialed
+ * \param forwarded The channel created as a result of the call forwarding
  * \param dialstring The information passed to the dialing application when beginning a dial
  * \param dialstatus The current status of the dial operation
  * \param forward The call forward string provided by the dialed channel
  */
 void ast_channel_publish_dial_forward(struct ast_channel *caller,
 		struct ast_channel *peer,
+		struct ast_channel *forwarded,
 		const char *dialstring,
 		const char *dialstatus,
 		const char *forward);

Modified: trunk/main/dial.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/dial.c?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/main/dial.c (original)
+++ trunk/main/dial.c Sat Dec 14 11:19:41 2013
@@ -465,13 +465,16 @@
 	channel->device = ast_strdup(device);
 	AST_LIST_UNLOCK(&dial->channels);
 
-
 	/* Drop the original channel */
-	ast_hangup(original);
 	channel->owner = NULL;
 
 	/* Finally give it a go... send it out into the world */
 	begin_dial_channel(channel, chan, chan ? 0 : 1, predial_string);
+
+	ast_channel_publish_dial_forward(chan, original, channel->owner, NULL, "CANCEL",
+		ast_channel_call_forward(original));
+
+	ast_hangup(original);
 
 	return 0;
 }

Modified: trunk/main/stasis_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/stasis_channels.c?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/main/stasis_channels.c (original)
+++ trunk/main/stasis_channels.c Sat Dec 14 11:19:41 2013
@@ -287,14 +287,21 @@
 	ast_json_unref(event->blob);
 }
 
+/*! \brief Dummy callback for receiving events */
+static void dummy_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+{
+}
+
 void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer,
-	const char *dialstring, const char *dialstatus, const char *forward)
+	struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
+	const char *forward)
 {
 	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_channel_snapshot *, peer_snapshot, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel_snapshot *, forwarded_snapshot, NULL, ao2_cleanup);
 
 	ast_assert(peer != NULL);
 	blob = ast_json_pack("{s: s, s: s, s: s}",
@@ -323,18 +330,33 @@
 	}
 	ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
 
+	if (forwarded) {
+		forwarded_snapshot = ast_channel_snapshot_create(forwarded);
+		if (!forwarded_snapshot) {
+			return;
+		}
+		ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
+	}
+
 	msg = stasis_message_create(ast_channel_dial_type(), payload);
 	if (!msg) {
 		return;
 	}
 
-	publish_message_for_channel_topics(msg, caller);
+	if (forwarded) {
+		struct stasis_subscription *subscription = stasis_subscribe(ast_channel_topic(peer), dummy_event_cb, NULL);
+
+		stasis_publish(ast_channel_topic(peer), msg);
+		stasis_unsubscribe_and_join(subscription);
+	} else {
+		publish_message_for_channel_topics(msg, caller);
+	}
 }
 
 void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer,
 	const char *dialstring, const char *dialstatus)
 {
-	ast_channel_publish_dial_forward(caller, peer, dialstring, dialstatus, NULL);
+	ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
 }
 
 static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
@@ -931,11 +953,54 @@
 	return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
 }
 
+static struct ast_json *dial_to_json(
+	struct stasis_message *message,
+	const struct stasis_message_sanitizer *sanitize)
+{
+	struct ast_multi_channel_blob *payload = stasis_message_data(message);
+	struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
+	struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
+	struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
+	struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
+	struct ast_json *json;
+	const struct timeval *tv = stasis_message_timestamp(message);
+	int res = 0;
+
+	json = ast_json_pack("{s: s, s: o, s: O, s: O, s: O}",
+		"type", "Dial",
+		"timestamp", ast_json_timeval(*tv, NULL),
+		"dialstatus", ast_json_object_get(blob, "dialstatus"),
+		"forward", ast_json_object_get(blob, "forward"),
+		"dialstring", ast_json_object_get(blob, "dialstring"));
+	if (!json) {
+		return NULL;
+	}
+
+	if (caller_json) {
+		res |= ast_json_object_set(json, "caller", caller_json);
+	}
+	if (peer_json) {
+		res |= ast_json_object_set(json, "peer", peer_json);
+	}
+	if (forwarded_json) {
+		res |= ast_json_object_set(json, "forwarded", forwarded_json);
+	}
+
+	if (res) {
+		ast_json_unref(json);
+		return NULL;
+	}
+
+	return json;
+}
+
 /*!
  * @{ \brief Define channel message types.
  */
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type,
+	.to_json = dial_to_json,
+	);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type,
 	.to_ami = varset_to_ami,
 	.to_json = varset_to_json,

Modified: trunk/res/ari/ari_model_validators.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/ari_model_validators.c?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/res/ari/ari_model_validators.c (original)
+++ trunk/res/ari/ari_model_validators.c Sat Dec 14 11:19:41 2013
@@ -2879,6 +2879,137 @@
 	return ast_ari_validate_device_state_changed;
 }
 
+int ast_ari_validate_dial(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_type = 0;
+	int has_application = 0;
+	int has_dialstatus = 0;
+	int has_peer = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_type = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field type failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_application = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field application failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_date(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field timestamp failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("caller", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field caller failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("dialstatus", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_dialstatus = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field dialstatus failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("dialstring", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field dialstring failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("forward", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field forward failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("forwarded", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field forwarded failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("peer", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_peer = 1;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI Dial field peer failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI Dial has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_type) {
+		ast_log(LOG_ERROR, "ARI Dial missing required field type\n");
+		res = 0;
+	}
+
+	if (!has_application) {
+		ast_log(LOG_ERROR, "ARI Dial missing required field application\n");
+		res = 0;
+	}
+
+	if (!has_dialstatus) {
+		ast_log(LOG_ERROR, "ARI Dial missing required field dialstatus\n");
+		res = 0;
+	}
+
+	if (!has_peer) {
+		ast_log(LOG_ERROR, "ARI Dial missing required field peer\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_dial_fn(void)
+{
+	return ast_ari_validate_dial;
+}
+
 int ast_ari_validate_endpoint_state_change(struct ast_json *json)
 {
 	int res = 1;
@@ -3023,6 +3154,9 @@
 	if (strcmp("DeviceStateChanged", discriminator) == 0) {
 		return ast_ari_validate_device_state_changed(json);
 	} else
+	if (strcmp("Dial", discriminator) == 0) {
+		return ast_ari_validate_dial(json);
+	} else
 	if (strcmp("EndpointStateChange", discriminator) == 0) {
 		return ast_ari_validate_endpoint_state_change(json);
 	} else
@@ -3172,6 +3306,9 @@
 	} else
 	if (strcmp("DeviceStateChanged", discriminator) == 0) {
 		return ast_ari_validate_device_state_changed(json);
+	} else
+	if (strcmp("Dial", discriminator) == 0) {
+		return ast_ari_validate_dial(json);
 	} else
 	if (strcmp("EndpointStateChange", discriminator) == 0) {
 		return ast_ari_validate_endpoint_state_change(json);

Modified: trunk/res/ari/ari_model_validators.h
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/ari_model_validators.h?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/res/ari/ari_model_validators.h (original)
+++ trunk/res/ari/ari_model_validators.h Sat Dec 14 11:19:41 2013
@@ -789,6 +789,24 @@
  * See \ref ast_ari_model_validators.h for more details.
  */
 ari_validator ast_ari_validate_device_state_changed_fn(void);
+
+/*!
+ * \brief Validator for Dial.
+ *
+ * Dialing state has changed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_dial(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_dial().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_dial_fn(void);
 
 /*!
  * \brief Validator for EndpointStateChange.
@@ -1187,6 +1205,16 @@
  * - application: string (required)
  * - timestamp: Date
  * - device_state: DeviceState (required)
+ * Dial
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - caller: Channel
+ * - dialstatus: string (required)
+ * - dialstring: string
+ * - forward: string
+ * - forwarded: Channel
+ * - peer: Channel (required)
  * EndpointStateChange
  * - type: string (required)
  * - application: string (required)

Modified: trunk/res/stasis/app.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/stasis/app.c?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/res/stasis/app.c (original)
+++ trunk/res/stasis/app.c Sat Dec 14 11:19:41 2013
@@ -265,6 +265,25 @@
 	app->data = NULL;
 }
 
+static void call_forwarded_handler(struct stasis_app *app, struct stasis_message *message)
+{
+	struct ast_multi_channel_blob *payload = stasis_message_data(message);
+	struct ast_channel_snapshot *snapshot = ast_multi_channel_blob_get_channel(payload, "forwarded");
+	struct ast_channel *chan;
+
+	if (!snapshot) {
+		return;
+	}
+
+	chan = ast_channel_get_by_name(snapshot->uniqueid);
+	if (!chan) {
+		return;
+	}
+
+	app_subscribe_channel(app, chan);
+	ast_channel_unref(chan);
+}
+
 static void sub_default_handler(void *data, struct stasis_subscription *sub,
 	struct stasis_message *message)
 {
@@ -273,6 +292,10 @@
 
 	if (stasis_subscription_final_message(sub, message)) {
 		ao2_cleanup(app);
+	}
+
+	if (stasis_message_type(message) == ast_channel_dial_type()) {
+		call_forwarded_handler(app, message);
 	}
 
 	/* By default, send any message that has a JSON representation */

Modified: trunk/rest-api/api-docs/events.json
URL: http://svnview.digium.com/svn/asterisk/trunk/rest-api/api-docs/events.json?view=diff&rev=403810&r1=403809&r2=403810
==============================================================================
--- trunk/rest-api/api-docs/events.json (original)
+++ trunk/rest-api/api-docs/events.json Sat Dec 14 11:19:41 2013
@@ -98,6 +98,7 @@
 				"ChannelHangupRequest",
 				"ChannelVarset",
 				"EndpointStateChange",
+				"Dial",
 				"StasisEnd",
 				"StasisStart"
 			]
@@ -411,6 +412,42 @@
 				}
 			}
 		},
+		"Dial": {
+			"id": "Dial",
+			"description": "Dialing state has changed.",
+			"properties": {
+				"caller": {
+					"required": false,
+					"type": "Channel",
+					"description": "The calling channel."
+				},
+				"peer": {
+					"required": true,
+					"type": "Channel",
+					"description": "The dialed channel."
+				},
+				"forward": {
+					"required": false,
+					"type": "string",
+					"description": "Forwarding target requested by the original dialed channel."
+				},
+				"forwarded": {
+					"required": false,
+					"type": "Channel",
+					"description": "Channel that the caller has been forwarded to."
+				},
+				"dialstring": {
+					"required": false,
+					"type": "string",
+					"description": "The dial string for calling the peer channel."
+				},
+				"dialstatus": {
+					"required": true,
+					"type": "string",
+					"description": "Current status of the dialing attempt to the peer."
+				}
+			}
+		},
 		"StasisEnd": {
 			"id": "StasisEnd",
 			"description": "Notification that a channel has left a Stasis application.",




More information about the asterisk-commits mailing list