[asterisk-commits] dlee: branch dlee/ASTERISK-21096 r383540 - /team/dlee/ASTERISK-21096/main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Mar 21 15:03:23 CDT 2013


Author: dlee
Date: Thu Mar 21 15:03:22 2013
New Revision: 383540

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383540
Log:
Handle snapshot monitors independently, avoiding a single BBOM function.

Modified:
    team/dlee/ASTERISK-21096/main/manager_channels.c

Modified: team/dlee/ASTERISK-21096/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-21096/main/manager_channels.c?view=diff&rev=383540&r1=383539&r2=383540
==============================================================================
--- team/dlee/ASTERISK-21096/main/manager_channels.c (original)
+++ team/dlee/ASTERISK-21096/main/manager_channels.c Thu Mar 21 15:03:22 2013
@@ -121,6 +121,36 @@
 			<syntax>
 				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
 				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="NewExten">
+		<managerEventInstance class="EVENT_FLAG_DIALPLAN">
+			<synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+				<parameter name="Extension">
+					<para>Deprecated in 12, but kept for
+					backward compatability. Please use
+					'Exten' instead.</para>
+				</parameter>
+				<parameter name="Application">
+					<para>The application about to be executed.</para>
+				</parameter>
+				<parameter name="AppData">
+					<para>The data to be passed to the application.</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="NewCallerid">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a channel receives new Caller ID information.</synopsis>
+			<syntax>
+				<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>
@@ -186,158 +216,256 @@
 	return out;
 }
 
-static inline int cep_has_changed(
+/*! \brief Struct containing info for an AMI channel event to send out. */
+struct snapshot_manager_event {
+	AST_LIST_ENTRY(snapshot_manager_event) list;
+	const char *manager_event;
+	int event_flags;
+	char extra_fields[];
+};
+
+/*!
+ * \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.
+ * \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);
+	RAII_VAR(char *, extra_fields, NULL, ast_free);
+	va_list argp;
+
+	ast_assert(extra_fields_fmt != NULL);
+	ast_assert(manager_event != NULL);
+
+	va_start(argp, extra_fields_fmt);
+	ast_vasprintf(&extra_fields, extra_fields_fmt, argp);
+	if (!extra_fields) {
+		return NULL;
+	}
+
+	ev = ao2_alloc(sizeof(*ev) + strlen(extra_fields) + 1, NULL);
+	if (!ev) {
+		return NULL;
+	}
+
+	ev->manager_event = manager_event;
+	ev->event_flags = event_flags;
+	strcpy(ev->extra_fields, extra_fields);
+
+	ao2_ref(ev, +1);
+	return ev;
+}
+
+/*! \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);
+
+/*! \brief Handle channel state changes */
+static struct snapshot_manager_event *channel_state_change(
+	struct ast_channel_snapshot *old_snapshot,
+	struct ast_channel_snapshot *new_snapshot)
+{
+	RAII_VAR(char *, extra_fields, NULL, ast_free);
+	char *manager_event = NULL;
+	int is_hungup, was_hungup;
+
+	if (!new_snapshot) {
+		/* Ignore cache clearing events; we'll see the hangup first */
+		return NULL;
+	}
+
+	extra_fields = ast_strdup("");
+
+	was_hungup = (old_snapshot && ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE)) ? 1 : 0;
+	is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
+
+	/* The Newchannel, Newstate and Hangup events are closely related, in
+	 * in that they are mutually exclusive, basically different flavors
+	 * of a new channel state event.
+	 */
+
+	if (!old_snapshot) {
+		manager_event = "Newchannel";
+	}
+
+	if (old_snapshot && old_snapshot->state != new_snapshot->state) {
+		manager_event = "Newstate";
+	}
+
+	if (!was_hungup && is_hungup) {
+		manager_event = "Hangup";
+		ast_asprintf(&extra_fields,
+			     "Cause: %d\r\n"
+			     "Cause-txt: %s\r\n",
+			     new_snapshot->hangupcause,
+			     ast_cause2str(new_snapshot->hangupcause));
+		if (!extra_fields) {
+			return NULL;
+		}
+	}
+
+	/* No event */
+	if (!manager_event) {
+		return NULL;
+	}
+
+	return snapshot_manager_event_create(
+		EVENT_FLAG_CALL, manager_event, "%s", extra_fields);
+}
+
+/*!
+ * \brief Compares the context, exten and priority of two snapshots.
+ * \param old_snapshot Old snapshot
+ * \param new_snapshot New snapshot
+ * \return True (non-zero) if context, exten or priority are identical.
+ * \return False (zero) if context, exten and priority changed.
+ */
+static inline int cep_equal(
 	const struct ast_channel_snapshot *old_snapshot,
 	const struct ast_channel_snapshot *new_snapshot)
 {
 	ast_assert(old_snapshot != NULL);
 	ast_assert(new_snapshot != NULL);
-	return old_snapshot->priority != new_snapshot->priority ||
-		strcmp(old_snapshot->context, new_snapshot->context) != 0 ||
-		strcmp(old_snapshot->exten, new_snapshot->exten) != 0;
-}
-
-static inline int caller_id_changed(
+
+	/* We actually get some snapshots with CEP set, but before the
+	 * application is set. Since empty application is invalid, we treat
+	 * setting the application from nothing as a CEP change.
+	 */
+	if (ast_strlen_zero(old_snapshot->appl) &&
+	    !ast_strlen_zero(new_snapshot->appl)) {
+		return 0;
+	}
+
+	return old_snapshot->priority == new_snapshot->priority &&
+		strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
+		strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
+}
+
+static struct snapshot_manager_event *channel_newexten(
+	struct ast_channel_snapshot *old_snapshot,
+	struct ast_channel_snapshot *new_snapshot)
+{
+	/* No Newexten event on cache clear */
+	if (!new_snapshot) {
+		return NULL;
+	}
+
+	/* Empty application is not valid for a Newexten event */
+	if (ast_strlen_zero(new_snapshot->appl)) {
+		return NULL;
+	}
+
+	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);
+}
+
+/*!
+ * \brief Compares the callerid info of two snapshots.
+ * \param old_snapshot Old snapshot
+ * \param new_snapshot New snapshot
+ * \return True (non-zero) if callerid are identical.
+ * \return False (zero) if callerid changed.
+ */
+static inline int caller_id_equal(
 	const struct ast_channel_snapshot *old_snapshot,
 	const struct ast_channel_snapshot *new_snapshot)
 {
+	ast_assert(old_snapshot != NULL);
 	ast_assert(new_snapshot != NULL);
-	return old_snapshot && (
-		strcmp(old_snapshot->caller_number, new_snapshot->caller_number) != 0 ||
-		strcmp(old_snapshot->caller_name, new_snapshot->caller_name) != 0);
-}
+	return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
+		strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0);
+}
+
+static struct snapshot_manager_event *channel_new_callerid(
+	struct ast_channel_snapshot *old_snapshot,
+	struct ast_channel_snapshot *new_snapshot)
+{
+	/* No NewCallerid event on cache clear or first event */
+	if (!old_snapshot || !new_snapshot) {
+		return NULL;
+	}
+
+	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",
+		new_snapshot->caller_pres,
+		ast_describe_caller_presentation(new_snapshot->caller_pres));
+}
+
+snapshot_monitor monitors[] = {
+	channel_state_change,
+	channel_newexten,
+	channel_new_callerid
+};
+
+size_t monitors_size = sizeof(monitors) / sizeof(monitors[0]);
 
 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
 				    struct stasis_topic *topic,
 				    struct stasis_message *message)
 {
-	RAII_VAR(struct ast_str *, extra_fields, NULL, ast_free);
 	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-	struct stasis_cache_update *update = stasis_message_data(message);
+	struct stasis_cache_update *update;
 	struct ast_channel_snapshot *old_snapshot;
 	struct ast_channel_snapshot *new_snapshot;
-	int is_hungup, was_hungup;
-	char *manager_event = NULL;
-	int new_exten, new_callerid;
+	size_t i;
+
+	update = stasis_message_data(message);
 
 	if (ast_channel_snapshot() != update->type) {
 		return;
 	}
 
-	extra_fields = ast_str_create(20);
-	if (!extra_fields) {
-		return;
-	}
-
 	old_snapshot = stasis_message_data(update->old_snapshot);
 	new_snapshot = stasis_message_data(update->new_snapshot);
 
-	if (!new_snapshot) {
-		/* Ignore cache clearing events; we'll see the hangup first */
-		return;
-	}
-
-	was_hungup = (old_snapshot && 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 (!old_snapshot) {
-		manager_event = "Newchannel";
-	}
-
-	if (old_snapshot && old_snapshot->state != new_snapshot->state) {
-		manager_event = "Newstate";
-	}
-
-	if (!was_hungup && is_hungup) {
-		manager_event = "Hangup";
-		ast_str_append(&extra_fields, 0,
-			       "Cause: %d\r\n"
-			       "Cause-txt: %s\r\n",
-			       new_snapshot->hangupcause,
-			       ast_cause2str(new_snapshot->hangupcause));
-	}
-
-	/* Detect Newexten transitions
-	 *  - if new snapshot has an application set AND
-	 *    - first snapshot OR
-	 *    - if the old snapshot has no application (first Newexten) OR
-	 *    - if the context/priority/exten changes
-	 */
-	new_exten = !ast_strlen_zero(new_snapshot->appl) && (
-		!old_snapshot ||
-		ast_strlen_zero(old_snapshot->appl) ||
-		cep_has_changed(old_snapshot, new_snapshot));
-
-	new_callerid = caller_id_changed(old_snapshot, new_snapshot);
-
-	if (manager_event || new_exten || new_callerid) {
-		channel_event_string =
-			manager_build_channel_state_string(new_snapshot);
-	}
-
-	if (!channel_event_string) {
-		return;
-	}
-
-	/* Channel state change events */
-	if (manager_event) {
-		manager_event(EVENT_FLAG_CALL, manager_event, "%s%s",
-			      ast_str_buffer(channel_event_string),
-			      ast_str_buffer(extra_fields));
-	}
-
-	if (new_exten) {
-		/* DEPRECATED: Extension field deprecated in 12; remove in 14 */
-		/*** DOCUMENTATION
-			<managerEventInstance>
-				<synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
-				<syntax>
-					<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
-					<parameter name="Extension">
-						<para>Deprecated in 12, but kept for
-						backward compatability. Please use
-						'Exten' instead.</para>
-					</parameter>
-					<parameter name="Application">
-						<para>The application about to be executed.</para>
-					</parameter>
-					<parameter name="AppData">
-						<para>The data to be passed to the application.</para>
-					</parameter>
-				</syntax>
-			</managerEventInstance>
-		***/
-		manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
-			      "%s"
-			      "Extension: %s\r\n"
-			      "Application: %s\r\n"
-			      "AppData: %s\r\n",
-			      ast_str_buffer(channel_event_string),
-			      new_snapshot->exten,
-			      new_snapshot->appl,
-			      new_snapshot->data);
-	}
-
-	if (new_callerid) {
-		const char *pres_str = ast_describe_caller_presentation(
-			new_snapshot->caller_pres);
-		/*** DOCUMENTATION
-			<managerEventInstance>
-				<synopsis>Raised when a channel receives new Caller ID information.</synopsis>
-				<syntax>
-					<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>
-		***/
-		manager_event(EVENT_FLAG_CALL, "NewCallerid",
-			      "%s"
-			      "CID-CallingPres: %d (%s)\r\n",
-			      ast_str_buffer(channel_event_string),
-			      new_snapshot->caller_pres,
-			      pres_str);
+	for (i = 0; i < monitors_size; ++i) {
+		RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
+		ev = monitors[i](old_snapshot, new_snapshot);
+
+		if (!ev) {
+			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;
+			}
+		}
+
+		manager_event(ev->event_flags, ev->manager_event, "%s%s",
+			ast_str_buffer(channel_event_string),
+			ev->extra_fields);
 	}
 }
 




More information about the asterisk-commits mailing list