[asterisk-commits] kmoore: branch kmoore/stasis-channel_events r383706 - in /team/kmoore/stasis-...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Mar 25 08:47:39 CDT 2013
Author: kmoore
Date: Mon Mar 25 08:47:35 2013
New Revision: 383706
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383706
Log:
Pull in dlee's patch for NewCallerid, HangupRequest, and SoftHangupRequest over stasis
Modified:
team/kmoore/stasis-channel_events/CHANGES
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.c
team/kmoore/stasis-channel_events/main/manager_channels.c
Modified: team/kmoore/stasis-channel_events/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/CHANGES?view=diff&rev=383706&r1=383705&r2=383706
==============================================================================
--- team/kmoore/stasis-channel_events/CHANGES (original)
+++ team/kmoore/stasis-channel_events/CHANGES Mon Mar 25 08:47:35 2013
@@ -49,6 +49,9 @@
* The AMI event 'UserEvent' from app_userevent now contains the channel state
fields. The channel state fields will come before the body fields.
+
+ * The deprecated use of | (pipe) as a separator in the channelvars setting in
+ manager.conf has been removed.
Channel Drivers
------------------
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=383706&r1=383705&r2=383706
==============================================================================
--- team/kmoore/stasis-channel_events/include/asterisk/channel.h (original)
+++ team/kmoore/stasis-channel_events/include/asterisk/channel.h Mon Mar 25 08:47:35 2013
@@ -4136,7 +4136,11 @@
int priority; /*!< Dialplan: Current extension priority */
int amaflags; /*!< AMA flags for billing */
int hangupcause; /*!< Why is the channel hanged up. See causes.h */
+ int caller_pres; /*!< Caller ID presentation. */
+
struct ast_flags flags; /*!< channel flags of AST_FLAG_ type */
+
+ struct varshead *manager_vars; /*!< Variables to be appended to manager events */
};
/*!
@@ -4153,6 +4157,27 @@
/*!
* \since 12
+ * \brief Sets the variables to be stored in the \a manager_vars field of all
+ * snapshots.
+ * \param varc Number of variable names.
+ * \param vars Array of variable names.
+ */
+void ast_channel_set_manager_vars(size_t varc, char **vars);
+
+/*!
+ * \since 12
+ * \brief Gets the variables for a given channel, as specified by ast_channel_set_manager_vars().
+ *
+ * The returned variable list is an AO2 object, so ao2_cleanup() to free it.
+ *
+ * \param chan Channel to get variables for.
+ * \return List of channel variables.
+ * \return \c NULL on error
+ */
+struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan);
+
+/*!
+ * \since 12
* \brief Message type for \ref ast_channel_snapshot.
*
* \retval Message type for \ref ast_channel_snapshot.
@@ -4163,10 +4188,12 @@
* \since 12
* \brief A topic which publishes the events for a particular channel.
*
- * \param chan Channel.
+ * If the given \a chan is \c NULL, ast_channel_topic_all() is returned.
+ *
+ * \param chan Channel, or \c NULL.
*
* \retval Topic for channel's events.
- * \retval \c NULL if \a chan is \c NULL.
+ * \retval ast_channel_topic_all() if \a chan is \c NULL.
*/
struct stasis_topic *ast_channel_topic(struct ast_channel *chan);
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=383706&r1=383705&r2=383706
==============================================================================
--- team/kmoore/stasis-channel_events/main/channel.c (original)
+++ team/kmoore/stasis-channel_events/main/channel.c Mon Mar 25 08:47:35 2013
@@ -243,6 +243,18 @@
stasis_publish(ast_channel_topic(chan), message);
}
+static void publish_channel_blob(struct ast_channel *chan, struct ast_json *blob)
+{
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+ if (blob) {
+ message = ast_channel_blob_create(chan, blob);
+ }
+ if (message) {
+ stasis_publish(ast_channel_topic(chan), message);
+ }
+}
+
+
static void channel_blob_dtor(void *obj)
{
struct ast_channel_blob *event = obj;
@@ -309,22 +321,7 @@
"type", "varset",
"variable", name,
"value", value);
- if (!blob) {
- ast_log(LOG_ERROR, "Error creating message\n");
- return;
- }
-
- msg = ast_channel_blob_create(chan, ast_json_ref(blob));
-
- if (!msg) {
- return;
- }
-
- if (chan) {
- stasis_publish(ast_channel_topic(chan), msg);
- } else {
- stasis_publish(ast_channel_topic_all(), msg);
- }
+ publish_channel_blob(chan, blob);
}
@@ -1463,22 +1460,16 @@
/*! \brief Queue a hangup frame for channel */
int ast_queue_hangup(struct ast_channel *chan)
{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
int res;
/* Yeah, let's not change a lock-critical value without locking */
ast_channel_lock(chan);
ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_DEV);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a hangup is requested with no set cause.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_CALL, "HangupRequest",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan));
+ blob = ast_json_pack("{s: s}", "type", "hangup_request");
+ publish_channel_blob(chan, blob);
res = ast_queue_frame(chan, &f);
ast_channel_unlock(chan);
@@ -1488,6 +1479,8 @@
/*! \brief Queue a hangup frame for channel */
int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
int res;
@@ -1501,21 +1494,10 @@
if (cause < 0) {
f.data.uint32 = ast_channel_hangupcause(chan);
}
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a hangup is requested with a specific cause code.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_CALL, "HangupRequest",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "Cause: %d\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan),
- cause);
+ blob = ast_json_pack("{s: s, s: i}",
+ "type", "hangup_request",
+ "cause", cause);
+ publish_channel_blob(chan, blob);
res = ast_queue_frame(chan, &f);
ast_channel_unlock(chan);
@@ -2818,25 +2800,16 @@
/*! \brief Softly hangup a channel, lock */
int ast_softhangup(struct ast_channel *chan, int cause)
{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
int res;
ast_channel_lock(chan);
res = ast_softhangup_nolock(chan, cause);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a soft hangup is requested with a specific cause code.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_CALL, "SoftHangupRequest",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "Cause: %d\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan),
- cause);
+ blob = ast_json_pack("{s: s, s: i, s: b}",
+ "type", "hangup_request",
+ "cause", cause,
+ "soft", 1);
+ publish_channel_blob(chan, blob);
ast_channel_unlock(chan);
return res;
@@ -6837,39 +6810,6 @@
}
/*!
- * \pre chan is locked
- */
-static void report_new_callerid(struct ast_channel *chan)
-{
- int pres;
-
- pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a channel receives new Caller ID information.</synopsis>
- <syntax>
- <parameter name="CID-CallingPres">
- <para>A description of the Caller ID presentation.</para>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- ast_manager_event(chan, EVENT_FLAG_CALL, "NewCallerid",
- "Channel: %s\r\n"
- "CallerIDNum: %s\r\n"
- "CallerIDName: %s\r\n"
- "Uniqueid: %s\r\n"
- "CID-CallingPres: %d (%s)\r\n",
- ast_channel_name(chan),
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
- S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
- ast_channel_uniqueid(chan),
- pres,
- ast_describe_caller_presentation(pres)
- );
-}
-
-/*!
* \internal
* \brief Transfer COLP between target and transferee channels.
* \since 1.8
@@ -7273,7 +7213,7 @@
ast_channel_redirecting_set(original, ast_channel_redirecting(clonechan));
ast_channel_redirecting_set(clonechan, &exchange.redirecting);
- report_new_callerid(original);
+ publish_channel_state(original);
/* Restore original timing file descriptor */
ast_channel_set_fd(original, AST_TIMING_FD, ast_channel_timingfd(original));
@@ -7439,7 +7379,7 @@
ast_cdr_setcid(ast_channel_cdr(chan), chan);
}
- report_new_callerid(chan);
+ publish_channel_state(chan);
ast_channel_unlock(chan);
}
@@ -7471,13 +7411,7 @@
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL);
pre_set_name = S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL);
ast_party_caller_set(ast_channel_caller(chan), caller, update);
- if (S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)
- != pre_set_number
- || S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL)
- != pre_set_name) {
- /* The caller id name or number changed. */
- report_new_callerid(chan);
- }
+ publish_channel_state(chan);
if (ast_channel_cdr(chan)) {
ast_cdr_setcid(ast_channel_cdr(chan), chan);
}
@@ -8671,8 +8605,108 @@
prnt(where, "%s", ast_channel_name(chan));
}
+/*!
+ * \brief List of channel variables to append to all channel-related events.
+ */
+struct manager_channel_variable {
+ AST_LIST_ENTRY(manager_channel_variable) entry;
+ unsigned int isfunc:1;
+ char name[];
+};
+
+static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
+
+static void free_channelvars(void)
+{
+ struct manager_channel_variable *var;
+ AST_RWLIST_WRLOCK(&channelvars);
+ while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
+ ast_free(var);
+ }
+ AST_RWLIST_UNLOCK(&channelvars);
+}
+
+void ast_channel_set_manager_vars(size_t varc, char **vars)
+{
+ size_t i;
+
+ free_channelvars();
+ AST_RWLIST_WRLOCK(&channelvars);
+ for (i = 0; i < varc; ++i) {
+ const char *var = vars[i];
+ struct manager_channel_variable *mcv;
+ if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(var) + 1))) {
+ break;
+ }
+ strcpy(mcv->name, var); /* SAFE */
+ if (strchr(var, '(')) {
+ mcv->isfunc = 1;
+ }
+ AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
+ }
+ AST_RWLIST_UNLOCK(&channelvars);
+}
+
+/*!
+ * \brief Destructor for the return value from ast_channel_get_manager_vars().
+ * \param obj AO2 object.
+ */
+static void varshead_dtor(void *obj)
+{
+ struct varshead *head = obj;
+ struct ast_var_t *var;
+
+ while ((var = AST_RWLIST_REMOVE_HEAD(head, entries))) {
+ ast_var_delete(var);
+ }
+}
+
+struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
+{
+ RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_str *, tmp, NULL, ast_free);
+ struct manager_channel_variable *mcv;
+
+ ret = ao2_alloc(sizeof(*ret), varshead_dtor);
+ tmp = ast_str_create(16);
+
+ if (!ret || !tmp) {
+ return NULL;
+ }
+
+ AST_RWLIST_RDLOCK(&channelvars);
+ AST_LIST_TRAVERSE(&channelvars, mcv, entry) {
+ const char *val = NULL;
+ struct ast_var_t *var;
+
+ if (mcv->isfunc) {
+ if (ast_func_read2(chan, mcv->name, &tmp, 0) == 0) {
+ val = ast_str_buffer(tmp);
+ } else {
+ ast_log(LOG_ERROR,
+ "Error invoking function %s\n", mcv->name);
+ }
+ } else {
+ val = pbx_builtin_getvar_helper(chan, mcv->name);
+ }
+
+ var = ast_var_assign(mcv->name, val ? val : "");
+ if (!var) {
+ AST_RWLIST_UNLOCK(&channelvars);
+ return NULL;
+ }
+
+ AST_RWLIST_INSERT_TAIL(ret, var, entries);
+ }
+ AST_RWLIST_UNLOCK(&channelvars);
+
+ ao2_ref(ret, +1);
+ return ret;
+}
+
static void channels_shutdown(void)
{
+ free_channelvars();
ao2_cleanup(__channel_snapshot);
__channel_snapshot = NULL;
ao2_cleanup(__channel_blob);
@@ -11298,6 +11332,7 @@
{
struct ast_channel_snapshot *snapshot = obj;
ast_string_field_free_memory(snapshot);
+ ao2_cleanup(snapshot->manager_vars);
}
struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
@@ -11342,6 +11377,9 @@
snapshot->amaflags = ast_channel_amaflags(chan);
snapshot->hangupcause = ast_channel_hangupcause(chan);
snapshot->flags = *ast_channel_flags(chan);
+ snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
+
+ snapshot->manager_vars = ast_channel_get_manager_vars(chan);
ao2_ref(snapshot, +1);
return snapshot;
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=383706&r1=383705&r2=383706
==============================================================================
--- team/kmoore/stasis-channel_events/main/channel_internal_api.c (original)
+++ team/kmoore/stasis-channel_events/main/channel_internal_api.c Mon Mar 25 08:47:35 2013
@@ -1385,7 +1385,7 @@
struct stasis_topic *ast_channel_topic(struct ast_channel *chan)
{
- return chan->topic;
+ return chan ? chan->topic : ast_channel_topic_all();
}
void ast_channel_internal_setup_topics(struct ast_channel *chan)
Modified: team/kmoore/stasis-channel_events/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-channel_events/main/manager.c?view=diff&rev=383706&r1=383705&r2=383706
==============================================================================
--- team/kmoore/stasis-channel_events/main/manager.c (original)
+++ team/kmoore/stasis-channel_events/main/manager.c Mon Mar 25 08:47:35 2013
@@ -1041,6 +1041,8 @@
static struct ast_event_sub *acl_change_event_subscription;
#define MGR_SHOW_TERMINAL_WIDTH 80
+
+#define MAX_VARS 128
/*! \brief
* Descriptor for a manager session, either on the AMI socket or over HTTP.
@@ -1167,14 +1169,6 @@
static struct ao2_container *sessions = NULL;
-struct manager_channel_variable {
- AST_LIST_ENTRY(manager_channel_variable) entry;
- unsigned int isfunc:1;
- char name[0]; /* allocate off the end the real size. */
-};
-
-static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
-
/*! \brief user descriptor, as read from the config file.
*
* \note It is still missing some fields -- e.g. we can have multiple permit and deny
@@ -1208,8 +1202,6 @@
/*! \brief A container of event documentation nodes */
AO2_GLOBAL_OBJ_STATIC(event_docs);
-
-static void free_channelvars(void);
static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
@@ -5650,30 +5642,16 @@
return 0;
}
-AST_THREADSTORAGE(manager_event_funcbuf);
-
static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan)
{
- struct manager_channel_variable *var;
-
- AST_RWLIST_RDLOCK(&channelvars);
- AST_LIST_TRAVERSE(&channelvars, var, entry) {
- const char *val;
- struct ast_str *res;
-
- if (var->isfunc) {
- res = ast_str_thread_get(&manager_event_funcbuf, 16);
- if (res && ast_func_read2(chan, var->name, &res, 0) == 0) {
- val = ast_str_buffer(res);
- } else {
- val = NULL;
- }
- } else {
- val = pbx_builtin_getvar_helper(chan, var->name);
- }
- ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, val ? val : "");
- }
- AST_RWLIST_UNLOCK(&channelvars);
+ RAII_VAR(struct varshead *, vars, NULL, ao2_cleanup);
+ struct ast_var_t *var;
+
+ vars = ast_channel_get_manager_vars(chan);
+
+ AST_LIST_TRAVERSE(vars, var, entries) {
+ ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", ast_channel_name(chan), var->name, var->value);
+ }
}
/* XXX see if can be moved inside the function */
@@ -5700,7 +5678,7 @@
return -1;
}
- cat_str = authority_to_str(category, &auth);
+ cat_str = authority_to_str (category, &auth);
ast_str_set(&buf, 0,
"Event: %s\r\nPrivilege: %s\r\n",
event, cat_str);
@@ -7350,31 +7328,19 @@
*/
static void load_channelvars(struct ast_variable *var)
{
- struct manager_channel_variable *mcv;
- char *remaining = ast_strdupa(var->value);
- char *next;
+ char *parse = NULL;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(vars)[MAX_VARS];
+ );
ast_free(manager_channelvars);
manager_channelvars = ast_strdup(var->value);
- /*
- * XXX TODO: To allow dialplan functions to have more than one
- * parameter requires eliminating the '|' as a separator so we
- * could use AST_STANDARD_APP_ARGS() to separate items.
- */
- free_channelvars();
- AST_RWLIST_WRLOCK(&channelvars);
- while ((next = strsep(&remaining, ",|"))) {
- if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) {
- break;
- }
- strcpy(mcv->name, next); /* SAFE */
- if (strchr(next, '(')) {
- mcv->isfunc = 1;
- }
- AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
- }
- AST_RWLIST_UNLOCK(&channelvars);
+ /* parse the setting */
+ parse = ast_strdupa(manager_channelvars);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ ast_channel_set_manager_vars(args.argc, args.vars);
}
/*! \internal \brief Free a user record. Should already be removed from the list */
@@ -7595,8 +7561,6 @@
}
ami_tls_cfg.cipher = ast_strdup("");
- free_channelvars();
-
for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
val = var->value;
@@ -7955,17 +7919,6 @@
__init_manager(1, 1);
}
-/* clear out every entry in the channelvar list */
-static void free_channelvars(void)
-{
- struct manager_channel_variable *var;
- AST_RWLIST_WRLOCK(&channelvars);
- while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
- ast_free(var);
- }
- AST_RWLIST_UNLOCK(&channelvars);
-}
-
int init_manager(void)
{
return __init_manager(0, 0);
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=383706&r1=383705&r2=383706
==============================================================================
--- team/kmoore/stasis-channel_events/main/manager_channels.c (original)
+++ team/kmoore/stasis-channel_events/main/manager_channels.c Mon Mar 25 08:47:35 2013
@@ -30,6 +30,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include "asterisk/callerid.h"
#include "asterisk/channel.h"
#include "asterisk/manager.h"
#include "asterisk/stasis_message_router.h"
@@ -80,12 +81,6 @@
</parameter>
<parameter name="Uniqueid">
</parameter>
- <parameter name="Cause">
- <para>A numeric cause code for why the channel was hung up.</para>
- </parameter>
- <parameter name="Cause-txt">
- <para>A description of why the channel was hung up.</para>
- </parameter>
</syntax>
</managerEventInstance>
</managerEvent>
@@ -102,6 +97,60 @@
<synopsis>Raised when a channel is hung up.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Cause">
+ <para>A numeric cause code for why the channel was hung up.</para>
+ </parameter>
+ <parameter name="Cause-txt">
+ <para>A description of why the channel was hung up.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="HangupRequest">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a hangup is requested.</synopsis>
+ <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="SoftHangupRequest">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a soft hangup is requested with a specific cause code.</synopsis>
+ <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>
@@ -137,9 +186,7 @@
"Context: %s\r\n"
"Exten: %s\r\n"
"Priority: %d\r\n"
- "Uniqueid: %s\r\n"
- "Cause: %d\r\n"
- "Cause-txt: %s\r\n",
+ "Uniqueid: %s\r\n",
snapshot->name,
snapshot->state,
ast_state2str(snapshot->state),
@@ -151,39 +198,248 @@
snapshot->context,
snapshot->exten,
snapshot->priority,
- snapshot->uniqueid,
- snapshot->hangupcause,
- ast_cause2str(snapshot->hangupcause));
+ snapshot->uniqueid);
if (!res) {
return NULL;
}
+ if (snapshot->manager_vars) {
+ struct ast_var_t *var;
+ AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
+ ast_str_append(&out, 0, "ChanVariable(%s): %s=%s\r\n",
+ snapshot->name,
+ var->name, var->value);
+ }
+ }
+
return out;
}
-static inline int cep_has_changed(
+/*! \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);
+
+/*! \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)
+{
+ int is_hungup, was_hungup;
+
+ if (!new_snapshot) {
+ /* Ignore cache clearing events; we'll see the hangup first */
+ return NULL;
+ }
+
+ /* 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) {
+ 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;
+}
+
+/*!
+ * \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;
-}
+
+ /* 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 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
+};
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 = 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;
+ size_t i;
+
+ update = stasis_message_data(message);
if (ast_channel_snapshot() != update->type) {
return;
@@ -192,82 +448,26 @@
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";
- }
-
- /* 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));
-
- if (manager_event || new_exten) {
- 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",
- ast_str_buffer(channel_event_string));
- }
-
- 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);
+ 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) {
+ 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);
}
}
@@ -347,6 +547,43 @@
ast_str_buffer(channel_event_string), eventname, body);
}
+static void channel_hangup_request(struct ast_channel_blob *obj)
+{
+ RAII_VAR(struct ast_str *, extra, NULL, ast_free);
+ RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+ struct ast_json *cause;
+ int is_soft;
+ char *manager_event = "HangupRequest";
+
+ extra = ast_str_create(20);
+ if (!extra) {
+ return;
+ }
+
+ channel_event_string = manager_build_channel_state_string(obj->snapshot);
+
+ if (!channel_event_string) {
+ return;
+ }
+
+ cause = ast_json_object_get(obj->blob, "cause");
+ if (cause) {
+ ast_str_append(&extra, 0,
+ "Cause: %jd\r\n",
+ ast_json_integer_get(cause));
+ }
+
+ is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft"));
+ if (is_soft) {
+ manager_event = "SoftHangupRequest";
+ }
+
+ manager_event(EVENT_FLAG_CALL, manager_event,
+ "%s%s",
+ ast_str_buffer(channel_event_string),
+ ast_str_buffer(extra));
+}
+
/*!
* \brief Callback processing messages on the channel topic.
*/
@@ -360,6 +597,8 @@
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);
}
}
More information about the asterisk-commits
mailing list