[asterisk-commits] kmoore: branch kmoore/stasis-channel_events r383943 - in /team/kmoore/stasis-...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Mar 26 20:37:14 CDT 2013


Author: kmoore
Date: Tue Mar 26 20:37:10 2013
New Revision: 383943

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383943
Log:
Re-commit all work up to this point

Modified:
    team/kmoore/stasis-channel_events/apps/app_userevent.c
    team/kmoore/stasis-channel_events/include/asterisk/channel.h
    team/kmoore/stasis-channel_events/main/channel.c
    team/kmoore/stasis-channel_events/main/channel_internal_api.c
    team/kmoore/stasis-channel_events/main/manager_channels.c

Modified: team/kmoore/stasis-channel_events/apps/app_userevent.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/apps/app_userevent.c?view=diff&rev=383943&r1=383942&r2=383943
==============================================================================
--- team/kmoore/stasis-channel_events/apps/app_userevent.c (original)
+++ team/kmoore/stasis-channel_events/apps/app_userevent.c Tue Mar 26 20:37:10 2013
@@ -69,7 +69,6 @@
 		AST_APP_ARG(eventname);
 		AST_APP_ARG(extra)[100];
 	);
-	RAII_VAR(struct ast_str *, body, ast_str_create(16), ast_free);
 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 
@@ -78,26 +77,37 @@
 		return -1;
 	}
 
-	if (!body) {
-		ast_log(LOG_WARNING, "Unable to allocate buffer\n");
-		return -1;
-	}
-
 	parse = ast_strdupa(data);
 
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	for (x = 0; x < args.argc - 1; x++) {
-		ast_str_append(&body, 0, "%s\r\n", args.extra[x]);
+	blob = ast_json_pack("{s: s, s: s}",
+			     "type", "userevent",
+			     "eventname", args.eventname);
+
+	if (!blob) {
+		return -1;
 	}
 
-	blob = ast_json_pack("{s: s, s: s, s: s}",
-			     "type", "userevent",
-			     "eventname", args.eventname,
-			     "body", ast_str_buffer(body));
-	if (!blob) {
-		ast_log(LOG_WARNING, "Unable to create message buffer\n");
-		return -1;
+	for (x = 0; x < args.argc - 1; x++) {
+		char *key, *value = args.extra[x];
+		RAII_VAR(struct ast_json *, json_value, NULL, ast_json_unref);
+
+		key = strsep(&value, ":");
+		if (!value) {
+			/* no ':' in string? */
+			continue;
+		}
+
+		value = ast_strip(value);
+		json_value = ast_json_string_create(value);
+		if (!json_value) {
+			return -1;
+		}
+
+		if (ast_json_object_set(blob, key, json_value)) {
+			return -1;
+		}
 	}
 
 	msg = ast_channel_blob_create(chan, blob);

Modified: team/kmoore/stasis-channel_events/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/include/asterisk/channel.h?view=diff&rev=383943&r1=383942&r2=383943
==============================================================================
--- team/kmoore/stasis-channel_events/include/asterisk/channel.h (original)
+++ team/kmoore/stasis-channel_events/include/asterisk/channel.h Tue Mar 26 20:37:10 2013
@@ -4199,6 +4199,16 @@
 
 /*!
  * \since 12
+ * \brief Get the channel topic using the channel's uniqueid.
+ *
+ * \param uniqueid Unique ID of the channel for which to retreive the topic.
+ *
+ * \retval Topic for channel's events.
+ */
+struct stasis_topic *ast_channel_topic_by_uniqueid(const char *uniqueid);
+
+/*!
+ * \since 12
  * \brief A topic which publishes the events for all channels.
  * \retval Topic for all channel events.
  */
@@ -4247,6 +4257,22 @@
 
 /*!
  * \since 12
+ * \brief Creates a \ref ast_channel_blob message from an existing snapshot.
+ *
+ * The \a blob JSON object requires a \c "type" field describing the blob. It
+ * should also be treated as immutable and not modified after it is put into the
+ * message.
+ *
+ * \param snapshot Snapshot of channel blob is associated with.
+ * \param blob JSON object representing the data.
+ * \return \ref ast_channel_blob message.
+ * \return \c NULL on error
+ */
+struct stasis_message *ast_channel_blob_create_from_snapshot(struct ast_channel_snapshot *snapshot,
+					       struct ast_json *blob);
+
+/*!
+ * \since 12
  * \brief Creates a \ref ast_channel_blob message.
  *
  * The \a blob JSON object requires a \c "type" field describing the blob. It

Modified: team/kmoore/stasis-channel_events/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/main/channel.c?view=diff&rev=383943&r1=383942&r2=383943
==============================================================================
--- team/kmoore/stasis-channel_events/main/channel.c (original)
+++ team/kmoore/stasis-channel_events/main/channel.c Tue Mar 26 20:37:10 2013
@@ -160,6 +160,8 @@
 struct stasis_topic *__channel_topic_all;
 
 struct stasis_caching_topic *__channel_topic_all_cached;
+
+struct stasis_topic_pool *channel_topic_pool;
 
 /*! \brief map AST_CAUSE's to readable string representations
  *
@@ -262,17 +264,15 @@
 	ast_json_unref(event->blob);
 }
 
-struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
-					       struct ast_json *blob)
+struct stasis_message *ast_channel_blob_create_from_snapshot(struct ast_channel_snapshot *snapshot,
+	struct ast_json *blob)
 {
 	RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_json *type;
+	struct stasis_message *msg;
 
 	ast_assert(blob != NULL);
 
-	type = ast_json_object_get(blob, "type");
-	if (type == NULL) {
+	if (!ast_json_object_get(blob, "type")) {
 		ast_log(LOG_ERROR, "Invalid ast_channel_blob; missing type field");
 		return NULL;
 	}
@@ -282,11 +282,9 @@
 		return NULL;
 	}
 
-	if (chan) {
-		obj->snapshot = ast_channel_snapshot_create(chan);
-		if (obj->snapshot == NULL) {
-			return NULL;
-		}
+	if (snapshot) {
+		obj->snapshot = snapshot;
+		ao2_ref(snapshot, +1);
 	}
 
 	obj->blob = ast_json_ref(blob);
@@ -296,8 +294,22 @@
 		return NULL;
 	}
 
-	ao2_ref(msg, +1);
 	return msg;
+}
+
+struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
+					       struct ast_json *blob)
+{
+	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+
+	if (chan) {
+		snapshot = ast_channel_snapshot_create(chan);
+		if (!snapshot) {
+			return NULL;
+		}
+	}
+
+	return ast_channel_blob_create_from_snapshot(snapshot, blob);
 }
 
 const char *ast_channel_blob_type(struct ast_channel_blob *obj)
@@ -318,7 +330,7 @@
 	ast_assert(value != NULL);
 
 	blob = ast_json_pack("{s: s, s: s, s: s}",
-			     "type", "varset",
+			     "type", "VarSet",
 			     "variable", name,
 			     "value", value);
 	publish_channel_blob(chan, blob);
@@ -8707,6 +8719,8 @@
 	__channel_blob = NULL;
 	ao2_cleanup(__channel_topic_all);
 	__channel_topic_all = NULL;
+	ao2_cleanup(channel_topic_pool);
+	channel_topic_pool = NULL;
 	__channel_topic_all_cached = stasis_caching_unsubscribe(__channel_topic_all_cached);
 	ast_data_unregister(NULL);
 	ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
@@ -8740,6 +8754,8 @@
 
 	__channel_topic_all = stasis_topic_create("ast_channel_topic_all");
 	__channel_topic_all_cached = stasis_caching_topic_create(__channel_topic_all, channel_snapshot_get_id);
+
+	channel_topic_pool = stasis_topic_pool_create(__channel_topic_all);
 
 	ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel));
 
@@ -11399,6 +11415,16 @@
 	return __channel_topic_all_cached;
 }
 
+struct stasis_topic *ast_channel_topic_by_uniqueid(const char *uniqueid)
+{
+	return stasis_topic_pool_get_topic(channel_topic_pool, uniqueid);
+}
+
+struct stasis_topic *ast_channel_topic(struct ast_channel *chan)
+{
+	return chan ? ast_channel_topic_by_uniqueid(ast_channel_uniqueid(chan)) : ast_channel_topic_all();
+}
+
 /* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
  *
  * ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE

Modified: team/kmoore/stasis-channel_events/main/channel_internal_api.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/main/channel_internal_api.c?view=diff&rev=383943&r1=383942&r2=383943
==============================================================================
--- team/kmoore/stasis-channel_events/main/channel_internal_api.c (original)
+++ team/kmoore/stasis-channel_events/main/channel_internal_api.c Tue Mar 26 20:37:10 2013
@@ -195,8 +195,6 @@
 	char dtmf_digit_to_emulate;			/*!< Digit being emulated */
 	char sending_dtmf_digit;			/*!< Digit this channel is currently sending out. (zero if not sending) */
 	struct timeval sending_dtmf_tv;		/*!< The time this channel started sending the current digit. (Invalid if sending_dtmf_digit is zero.) */
-	struct stasis_topic *topic;			/*!< Topic for all channel's events */
-	struct stasis_subscription *forwarder;		/*!< Subscription for event forwarding to all topic */
 };
 
 /* AST_DATA definitions, which will probably have to be re-thought since the channel will be opaque */
@@ -1366,11 +1364,6 @@
 	}
 
 	ast_string_field_free_memory(chan);
-
-	chan->forwarder = stasis_unsubscribe(chan->forwarder);
-
-	ao2_cleanup(chan->topic);
-	chan->topic = NULL;
 }
 
 void ast_channel_internal_finalize(struct ast_channel *chan)
@@ -1383,21 +1376,10 @@
 	return chan->finalized;
 }
 
-struct stasis_topic *ast_channel_topic(struct ast_channel *chan)
-{
-	return chan ? chan->topic : ast_channel_topic_all();
-}
-
 void ast_channel_internal_setup_topics(struct ast_channel *chan)
 {
-	const char *topic_name = chan->uniqueid;
-	ast_assert(chan->topic == NULL);
-	ast_assert(chan->forwarder == NULL);
-
-	if (ast_strlen_zero(topic_name)) {
-		topic_name = "<dummy-channel>";
-	}
-
-	chan->topic = stasis_topic_create(topic_name);
-	chan->forwarder = stasis_forward_all(chan->topic, ast_channel_topic_all());
-}
+	struct stasis_topic *topic;
+
+	topic = ast_channel_topic_by_uniqueid(chan->uniqueid);
+	ast_assert(topic != NULL);
+}

Modified: team/kmoore/stasis-channel_events/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/main/manager_channels.c?view=diff&rev=383943&r1=383942&r2=383943
==============================================================================
--- team/kmoore/stasis-channel_events/main/manager_channels.c (original)
+++ team/kmoore/stasis-channel_events/main/manager_channels.c Tue Mar 26 20:37:10 2013
@@ -37,6 +37,10 @@
 #include "asterisk/pbx.h"
 
 static struct stasis_message_router *channel_state_router;
+
+static struct ao2_container *channel_blob_handlers;
+
+#define BLOB_HANDLER_BUCKETS 57
 
 /*** DOCUMENTATION
 	<managerEvent language="en_US" name="Newchannel">
@@ -150,6 +154,20 @@
 				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
 				<parameter name="CID-CallingPres">
 					<para>A description of the Caller ID presentation.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="VarSet">
+		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
+			<synopsis>Raised when a variable is set to a particular value.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+				<parameter name="Variable">
+					<para>The variable being set.</para>
+				</parameter>
+				<parameter name="Value">
+					<para>The new value of the variable.</para>
 				</parameter>
 			</syntax>
 		</managerEventInstance>
@@ -216,86 +234,32 @@
 	return out;
 }
 
-/*! \brief Struct containing info for an AMI channel event to send out. */
-struct snapshot_manager_event {
-	/*! event_flags manager_event() flags parameter. */
-	int event_flags;
-	/*!  manager_event manager_event() category. */
-	const char *manager_event;
-	AST_DECLARE_STRING_FIELDS(
-		/* extra fields to include in the event. */
-		AST_STRING_FIELD(extra_fields);
-		);
-};
-
-static void snapshot_manager_event_dtor(void *obj)
-{
-	struct snapshot_manager_event *ev = obj;
-	ast_string_field_free_memory(ev);
-}
-
-/*!
- * \brief Construct a \ref snapshot_manager_event.
- * \param event_flags manager_event() flags parameter.
- * \param manager_event manager_event() category.
- * \param extra_fields_fmt Format string for extra fields to include.
- *                         Or NO_EXTRA_FIELDS for no extra fields.
- * \return New \ref snapshot_manager_event object.
- * \return \c NULL on error.
- */
-static struct snapshot_manager_event *
-__attribute__((format(printf, 3, 4)))
-snapshot_manager_event_create(
-	int event_flags,
-	const char *manager_event,
-	const char *extra_fields_fmt,
-	...)
-{
-	RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
-	va_list argp;
-
-	ast_assert(extra_fields_fmt != NULL);
-	ast_assert(manager_event != NULL);
-
-	ev = ao2_alloc(sizeof(*ev), snapshot_manager_event_dtor);
-	if (!ev) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(ev, 20)) {
-		return NULL;
-	}
-
-	ev->manager_event = manager_event;
-	ev->event_flags = event_flags;
-
-	va_start(argp, extra_fields_fmt);
-	ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
-				      argp);
-	va_end(argp);
-
-	ao2_ref(ev, +1);
-	return ev;
-}
-
-/*! GCC warns about blank or NULL format strings. So, shenanigans! */
-#define NO_EXTRA_FIELDS "%s", ""
-
-/*! \brief Typedef for callbacks that get called on channel snapshot updates */
-typedef struct snapshot_manager_event *(*snapshot_monitor)(
-	struct ast_channel_snapshot *old_snapshot,
-	struct ast_channel_snapshot *new_snapshot);
+static void publish_channel_blob(struct ast_channel_snapshot *snapshot, struct ast_json *blob)
+{
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	if (!blob) {
+		return;
+	}
+
+	msg = ast_channel_blob_create_from_snapshot(snapshot, blob);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_channel_topic_by_uniqueid(snapshot->uniqueid), msg);
+}
 
 /*! \brief Handle channel state changes */
-static struct snapshot_manager_event *channel_state_change(
+static void channel_generate_state_change(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
-	int is_hungup, was_hungup;
+	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
 	if (!new_snapshot) {
 		/* Ignore cache clearing events; we'll see the hangup first */
-		return NULL;
+		return;
 	}
 
 	/* The Newchannel, Newstate and Hangup events are closely related, in
@@ -304,29 +268,19 @@
 	 */
 
 	if (!old_snapshot) {
-		return snapshot_manager_event_create(
-			EVENT_FLAG_CALL, "Newchannel", NO_EXTRA_FIELDS);
-	}
-
-	was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
-	is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
-
-	if (!was_hungup && is_hungup) {
-		return snapshot_manager_event_create(
-			EVENT_FLAG_CALL, "Hangup",
-			"Cause: %d\r\n"
-			"Cause-txt: %s\r\n",
-			new_snapshot->hangupcause,
-			ast_cause2str(new_snapshot->hangupcause));
-	}
-
-	if (old_snapshot->state != new_snapshot->state) {
-		return snapshot_manager_event_create(
-			EVENT_FLAG_CALL, "Newstate", NO_EXTRA_FIELDS);
-	}
-
-	/* No event */
-	return NULL;
+		blob = ast_json_pack("{s: s}",
+			"type", "Newchannel");
+	} else if (!ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) && ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE)) {
+		blob = ast_json_pack("{s: s, s: i, s: s}",
+			"type", "Hangup",
+			"Cause", new_snapshot->hangupcause,
+			"Cause-txt", ast_cause2str(new_snapshot->hangupcause));
+	} else if (old_snapshot->state != new_snapshot->state) {
+		blob = ast_json_pack("{s: s}",
+			"type", "Newstate");
+	}
+
+	publish_channel_blob(new_snapshot, blob);
 }
 
 /*!
@@ -357,33 +311,32 @@
 		strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
 }
 
-static struct snapshot_manager_event *channel_newexten(
+static void channel_generate_newexten(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
+	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
 	/* No Newexten event on cache clear */
 	if (!new_snapshot) {
-		return NULL;
+		return;
 	}
 
 	/* Empty application is not valid for a Newexten event */
 	if (ast_strlen_zero(new_snapshot->appl)) {
-		return NULL;
+		return;
 	}
 
 	if (old_snapshot && cep_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	/* DEPRECATED: Extension field deprecated in 12; remove in 14 */
-	return snapshot_manager_event_create(
-		EVENT_FLAG_CALL, "Newexten",
-		"Extension: %s\r\n"
-		"Application: %s\r\n"
-		"AppData: %s\r\n",
-		new_snapshot->exten,
-		new_snapshot->appl,
-		new_snapshot->data);
+		return;
+	}
+
+	blob = ast_json_pack("{s: s, s: s, s: s}",
+		"type", "Newexten",
+		"Application", new_snapshot->appl,
+		"AppData", new_snapshot->data);
+
+	publish_channel_blob(new_snapshot, blob);
 }
 
 /*!
@@ -403,37 +356,48 @@
 		strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
 }
 
-static struct snapshot_manager_event *channel_new_callerid(
+static void channel_generate_newcallerid(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
+	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+	RAII_VAR(struct ast_str *, calling_pres, ast_str_create(32), ast_free);
+
 	/* No NewCallerid event on cache clear or first event */
 	if (!old_snapshot || !new_snapshot) {
-		return NULL;
+		return;
 	}
 
 	if (caller_id_equal(old_snapshot, new_snapshot)) {
-		return NULL;
-	}
-
-	return snapshot_manager_event_create(
-		EVENT_FLAG_CALL, "NewCallerid",
-		"CID-CallingPres: %d (%s)\r\n",
+		return;
+	}
+
+	ast_str_set(&calling_pres, 0, "%d (%s)",
 		new_snapshot->caller_pres,
 		ast_describe_caller_presentation(new_snapshot->caller_pres));
-}
+
+	blob = ast_json_pack("{s: s, s: s}",
+		"type", "NewCallerid",
+		"CID-CallingPres", ast_str_buffer(calling_pres));
+
+	publish_channel_blob(new_snapshot, blob);
+}
+
+/*! \brief Typedef for callbacks that get called on channel snapshot updates */
+typedef void (*snapshot_monitor)(
+	struct ast_channel_snapshot *old_snapshot,
+	struct ast_channel_snapshot *new_snapshot);
 
 snapshot_monitor monitors[] = {
-	channel_state_change,
-	channel_newexten,
-	channel_new_callerid
+	channel_generate_state_change,
+	channel_generate_newexten,
+	channel_generate_newcallerid
 };
 
 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
 				    struct stasis_topic *topic,
 				    struct stasis_message *message)
 {
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
 	struct stasis_cache_update *update;
 	struct ast_channel_snapshot *old_snapshot;
 	struct ast_channel_snapshot *new_snapshot;
@@ -449,33 +413,57 @@
 	new_snapshot = stasis_message_data(update->new_snapshot);
 
 	for (i = 0; i < ARRAY_LEN(monitors); ++i) {
-		RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
-		ev = monitors[i](old_snapshot, new_snapshot);
-
-		if (!ev) {
+		monitors[i](old_snapshot, new_snapshot);
+	}
+}
+
+/*!
+ * \brief Callback used to determine whether a key should be skipped when converting a JSON object to a manager blob
+ * \param key Key from JSON blob to be evaluated
+ * \retval non-zero if the key should be excluded
+ * \retval zero if the key should not be excluded
+ */
+typedef int (*key_exclusion_cb)(const char *key);
+
+static int default_exclusion_cb(const char *key)
+{
+	if (!strcmp("type", key)) {
+		return 1;
+	}
+	return 0;
+}
+
+#define manager_str_from_blob(blob) \
+	manager_str_from_blob_exclusion(blob, default_exclusion_cb)
+
+static struct ast_str *manager_str_from_blob_exclusion(struct ast_json *blob, key_exclusion_cb exclusion_cb)
+{
+	struct ast_str *output_str = ast_str_create(32);
+	struct ast_json_iter *blob_iter = ast_json_object_iter(blob);
+	if (!output_str || !blob_iter) {
+		return NULL;
+	}
+
+	do {
+		const char *key = ast_json_object_iter_key(blob_iter);
+		const char *value = ast_json_string_get(ast_json_object_iter_value(blob_iter));
+		if (exclusion_cb && exclusion_cb(key)) {
 			continue;
 		}
 
-		/* If we haven't already, build the channel event string */
-		if (!channel_event_string) {
-			channel_event_string =
-				manager_build_channel_state_string(new_snapshot);
-			if (!channel_event_string) {
-				return;
-			}
+		ast_str_append(&output_str, 0, "%s: %s\r\n", key, value);
+		if (!output_str) {
+			return NULL;
 		}
-
-		manager_event(ev->event_flags, ev->manager_event, "%s%s",
-			ast_str_buffer(channel_event_string),
-			ev->extra_fields);
-	}
-}
-
-static void channel_varset(struct ast_channel_blob *obj)
+	} while ((blob_iter = ast_json_object_iter_next(blob, blob_iter)));
+
+	return output_str;
+}
+
+static void channel_manager_generic(struct ast_channel_blob *obj, int manager_flag)
 {
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
-	const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value"));
+	RAII_VAR(struct ast_str *, blob_str, manager_str_from_blob(obj->blob), ast_free);
 
 	if (obj->snapshot) {
 		channel_event_string = manager_build_channel_state_string(obj->snapshot);
@@ -486,43 +474,38 @@
 			    "Uniqueid: none\r\n");
 	}
 
-	if (!channel_event_string) {
-		return;
-	}
-
-	/*** DOCUMENTATION
-		<managerEventInstance>
-			<synopsis>Raised when a variable is set to a particular value.</synopsis>
-			<syntax>
-				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
-				<parameter name="Variable">
-					<para>The variable being set.</para>
-				</parameter>
-				<parameter name="Value">
-					<para>The new value of the variable.</para>
-				</parameter>
-			</syntax>
-		</managerEventInstance>
-	***/
-	manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
+	if (!channel_event_string || !blob_str) {
+		return;
+	}
+
+	manager_event(manager_flag, ast_channel_blob_type(obj),
 		      "%s"
-		      "Variable: %s\r\n"
-		      "Value: %s\r\n",
+		      "%s",
 		      ast_str_buffer(channel_event_string),
-		      variable, value);
-}
-
-static void channel_userevent(struct ast_channel_blob *obj)
+		      ast_str_buffer(blob_str));
+}
+
+static int userevent_exclusion_cb(const char *key)
+{
+	if (!strcmp("type", key)) {
+		return 1;
+	}
+	if (!strcmp("eventname", key)) {
+		return 1;
+	}
+	return 0;
+}
+
+static void channel_userevent(struct ast_channel_blob *obj, int manager_flag)
 {
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+	RAII_VAR(struct ast_str *, body, manager_str_from_blob_exclusion(obj->blob, userevent_exclusion_cb), ast_free);
 	const char *eventname;
-	const char *body;
 
 	eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
-	body = ast_json_string_get(ast_json_object_get(obj->blob, "body"));
 	channel_event_string = manager_build_channel_state_string(obj->snapshot);
 
-	if (!channel_event_string) {
+	if (!channel_event_string || !body) {
 		return;
 	}
 
@@ -544,10 +527,10 @@
 		      "%s"
 		      "UserEvent: %s\r\n"
 		      "%s",
-		      ast_str_buffer(channel_event_string), eventname, body);
-}
-
-static void channel_hangup_request(struct ast_channel_blob *obj)
+		      ast_str_buffer(channel_event_string), eventname, ast_str_buffer(body));
+}
+
+static void channel_hangup_request(struct ast_channel_blob *obj, int manager_flag)
 {
 	RAII_VAR(struct ast_str *, extra, NULL, ast_free);
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
@@ -582,6 +565,60 @@
 		      "%s%s",
 		      ast_str_buffer(channel_event_string),
 		      ast_str_buffer(extra));
+}
+
+static void channel_newexten(struct ast_channel_blob *obj, int manager_flag)
+{
+	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+	RAII_VAR(struct ast_str *, blob_str, manager_str_from_blob(obj->blob), ast_free);
+
+	channel_event_string = manager_build_channel_state_string(obj->snapshot);
+
+	if (!channel_event_string || !blob_str) {
+		return;
+	}
+
+	/* DEPRECATED: Extension field deprecated in 12; remove in 14 */
+	manager_event(manager_flag, ast_channel_blob_type(obj),
+		"%s"
+		"%s"
+		"Extension: %s\r\n",
+		ast_str_buffer(channel_event_string),
+		ast_str_buffer(blob_str),
+		obj->snapshot->exten);
+}
+
+typedef void (*blob_handler_cb)(struct ast_channel_blob *obj, int manager_flag);
+
+struct blob_handler {
+	char *type;
+	int flag;
+	blob_handler_cb handler_cb;
+};
+
+static void blob_handler_destroy(void *obj)
+{
+	struct blob_handler *handler = obj;
+	ast_free(handler->type);
+}
+
+static void register_blob_handler(char *type, int flag, blob_handler_cb handler_cb)
+{
+	RAII_VAR(struct blob_handler *, handler, ao2_alloc(sizeof(*handler), blob_handler_destroy), ao2_cleanup);
+
+	if (!handler) {
+		return;
+	}
+
+	handler->type = ast_strdup(type);
+
+	if (!type) {
+		return;
+	}
+
+	handler->handler_cb = handler_cb;
+	handler->flag = flag;
+	ao2_link(channel_blob_handlers, handler);
 }
 
 /*!
@@ -592,20 +629,32 @@
 			    struct stasis_message *message)
 {
 	struct ast_channel_blob *obj = stasis_message_data(message);
-
-	if (strcmp("varset", ast_channel_blob_type(obj)) == 0) {
-		channel_varset(obj);
-	} else if (strcmp("userevent", ast_channel_blob_type(obj)) == 0) {
-		channel_userevent(obj);
-	} else if (strcmp("hangup_request", ast_channel_blob_type(obj)) == 0) {
-		channel_hangup_request(obj);
-	}
+	RAII_VAR(struct blob_handler *, handler, ao2_find(channel_blob_handlers, ast_channel_blob_type(obj), OBJ_KEY), ao2_cleanup);
+
+	if (handler) {
+		handler->handler_cb(obj, handler->flag);
+	}
+}
+
+static int blob_handler_hash(const void *obj, const int flags)
+{
+	const char *handler_type = (flags & OBJ_KEY) ? obj : ((struct blob_handler*) obj)->type;
+	return ast_str_case_hash(handler_type);
+}
+
+static int blob_handler_cmp(void *obj, void *arg, int flags)
+{
+	struct blob_handler *opt1 = obj, *opt2 = arg;
+	const char *handler_type = (flags & OBJ_KEY) ? arg : opt2->type;
+	return strcasecmp(opt1->type, handler_type) ? 0 : CMP_MATCH | CMP_STOP;
 }
 
 static void manager_channels_shutdown(void)
 {
 	stasis_message_router_unsubscribe(channel_state_router);
 	channel_state_router = NULL;
+	ao2_cleanup(channel_blob_handlers);
+	channel_blob_handlers = NULL;
 }
 
 int manager_channels_init(void)
@@ -644,5 +693,21 @@
 		return -1;
 	}
 
+	channel_blob_handlers = ao2_container_alloc(BLOB_HANDLER_BUCKETS, blob_handler_hash, blob_handler_cmp);
+
+	if (!channel_blob_handlers) {
+		manager_channels_shutdown();
+		return -1;
+	}
+
+	register_blob_handler("userevent", EVENT_FLAG_USER, channel_userevent);
+	register_blob_handler("hangup_request", EVENT_FLAG_CALL, channel_hangup_request);
+	register_blob_handler("Newexten", EVENT_FLAG_CALL, channel_newexten);
+	register_blob_handler("VarSet", EVENT_FLAG_DIALPLAN, channel_manager_generic);
+	register_blob_handler("NewCallerid", EVENT_FLAG_CALL, channel_manager_generic);
+	register_blob_handler("Newchannel", EVENT_FLAG_CALL, channel_manager_generic);
+	register_blob_handler("Newstate", EVENT_FLAG_CALL, channel_manager_generic);
+	register_blob_handler("Hangup", EVENT_FLAG_CALL, channel_manager_generic);
+
 	return 0;
 }




More information about the asterisk-commits mailing list