Refactor operations to access the stasis cache instead of objects directly when retri...
authorJoshua Colp <jcolp@digium.com>
Mon, 8 Jul 2013 19:19:55 +0000 (19:19 +0000)
committerJoshua Colp <jcolp@digium.com>
Mon, 8 Jul 2013 19:19:55 +0000 (19:19 +0000)
(closes issue ASTERISK-21883)

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

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393831 65c4cc65-6c06-0410-ace0-fbb531ad65f3

13 files changed:
build_tools/cflags-devmode.xml
include/asterisk/channel.h
include/asterisk/stasis_channels.h
main/bridging.c
main/channel.c
main/channel_internal_api.c
main/cli.c
main/manager.c
main/manager_bridging.c
main/manager_channels.c
main/pbx.c
main/stasis_channels.c
res/res_agi.c

index cfcc26c..0ed9f67 100644 (file)
@@ -24,9 +24,6 @@
                <member name="THREAD_CRASH" displayname="Crash on mutex errors">
                        <support_level>extended</support_level>
                </member>
-               <member name="CHANNEL_TRACE" displayname="Enable CHANNEL(trace) function">
-                       <support_level>extended</support_level>
-               </member>
                <member name="TEST_FRAMEWORK" displayname="Enable Test Framework API">
                        <support_level>extended</support_level>
                </member>
index a5f5210..bc8358d 100644 (file)
@@ -1420,39 +1420,6 @@ void ast_channel_unregister(const struct ast_channel_tech *tech);
  */
 const struct ast_channel_tech *ast_get_channel_tech(const char *name);
 
-#ifdef CHANNEL_TRACE
-/*!
- * \brief Update the context backtrace if tracing is enabled
- * \return Returns 0 on success, -1 on failure
- */
-int ast_channel_trace_update(struct ast_channel *chan);
-
-/*!
- * \brief Enable context tracing in the channel
- * \return Returns 0 on success, -1 on failure
- */
-int ast_channel_trace_enable(struct ast_channel *chan);
-
-/*!
- * \brief Disable context tracing in the channel.
- * \note Does not remove current trace entries
- * \return Returns 0 on success, -1 on failure
- */
-int ast_channel_trace_disable(struct ast_channel *chan);
-
-/*!
- * \brief Whether or not context tracing is enabled
- * \return Returns -1 when the trace is enabled. 0 if not.
- */
-int ast_channel_trace_is_enabled(struct ast_channel *chan);
-
-/*!
- * \brief Put the channel backtrace in a string
- * \return Returns the amount of lines in the backtrace. -1 on error.
- */
-int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out);
-#endif
-
 /*!
  * \brief Hang up a channel
  * \note Absolutely _NO_ channel locks should be held before calling this function.
@@ -4230,6 +4197,18 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan);
 
 /*!
  * \since 12
+ * \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper().
+ *
+ * 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_vars(struct ast_channel *chan);
+
+/*!
+ * \since 12
  * \brief A topic which publishes the events for a particular channel.
  *
  * If the given \a chan is \c NULL, ast_channel_topic_all() is returned.
index e8fc486..d5c3201 100644 (file)
@@ -39,6 +39,7 @@
 struct ast_channel_snapshot {
        AST_DECLARE_STRING_FIELDS(
                AST_STRING_FIELD(name);             /*!< ASCII unique channel name */
+               AST_STRING_FIELD(type);             /*!< Type of channel technology */
                AST_STRING_FIELD(accountcode);      /*!< Account code for billing */
                AST_STRING_FIELD(peeraccount);      /*!< Peer account code for billing */
                AST_STRING_FIELD(userfield);        /*!< Userfield for CEL billing */
@@ -58,18 +59,31 @@ struct ast_channel_snapshot {
                AST_STRING_FIELD(dialed_subaddr);   /*!< Dialed subaddress */
                AST_STRING_FIELD(connected_name);   /*!< Connected Line Name */
                AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
+               AST_STRING_FIELD(effective_name);   /*!< Effective Connected Line Name */
+               AST_STRING_FIELD(effective_number); /*!< Effective Connected Line Number */
                AST_STRING_FIELD(language);         /*!< The default spoken language for the channel */
+               AST_STRING_FIELD(bridgeid);         /*!< Unique Bridge Identifier */
+               AST_STRING_FIELD(nativeformats);    /*!< Native formats on the channel */
+               AST_STRING_FIELD(readformat);       /*!< The current read format */
+               AST_STRING_FIELD(writeformat);      /*!< The current write format */
+               AST_STRING_FIELD(writetrans);       /*!< The current write translation path */
+               AST_STRING_FIELD(readtrans);        /*!< The current read translation path */
        );
 
+       char callid[AST_CALLID_BUFFER_LENGTH];  /*!< Callid for the channel */
        struct timeval creationtime;            /*!< The time of channel creation */
+       struct timeval hanguptime;              /*!< When the channel should hang up */
        enum ast_channel_state state;           /*!< State of line */
        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 */
+       ast_group_t callgroup;                  /*!< Call group */
+       ast_group_t pickupgroup;                /*!< Pickup group */
        struct ast_flags softhangup_flags;      /*!< softhangup channel flags */
        struct varshead *manager_vars;          /*!< Variables to be appended to manager events */
+       struct varshead *channel_vars;          /*!< Variables set on the channel */
 };
 
 /*!
index e9f7091..38ec431 100644 (file)
@@ -6885,38 +6885,29 @@ static int bridge_sort_cmp(const void *obj_left, const void *obj_right, int flag
        return cmp;
 }
 
-struct bridge_complete {
-       /*! Nth match to return. */
-       int state;
-       /*! Which match currently on. */
-       int which;
-};
-
-static int complete_bridge_search(void *obj, void *arg, void *data, int flags)
+static char *complete_bridge(const char *word, int state)
 {
-       struct bridge_complete *search = data;
+       char *ret = NULL;
+       int wordlen = strlen(word), which = 0;
+       RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup);
+       struct ao2_iterator iter;
+       struct stasis_message *msg;
 
-       if (++search->which > search->state) {
-               return CMP_MATCH;
+       if (!(cached_bridges = stasis_cache_dump(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type()))) {
+               return NULL;
        }
-       return 0;
-}
 
-static char *complete_bridge(const char *word, int state)
-{
-       char *ret;
-       struct ast_bridge *bridge;
-       struct bridge_complete search = {
-               .state = state,
-               };
+       iter = ao2_iterator_init(cached_bridges, 0);
+       for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
+               struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
 
-       bridge = ao2_callback_data(bridges, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
-               complete_bridge_search, (char *) word, &search);
-       if (!bridge) {
-               return NULL;
+               if (!strncasecmp(word, snapshot->uniqueid, wordlen) && (++which > state)) {
+                       ret = ast_strdup(snapshot->uniqueid);
+                       break;
+               }
        }
-       ret = ast_strdup(bridge->uniqueid);
-       ao2_ref(bridge, -1);
+       ao2_iterator_destroy(&iter);
+
        return ret;
 }
 
@@ -6925,8 +6916,9 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast
 #define FORMAT_HDR "%-36s %5s %-15s %s\n"
 #define FORMAT_ROW "%-36s %5u %-15s %s\n"
 
+       RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup);
        struct ao2_iterator iter;
-       struct ast_bridge *bridge;
+       struct stasis_message *msg;
 
        switch (cmd) {
        case CLI_INIT:
@@ -6939,17 +6931,22 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast
                return NULL;
        }
 
-/* BUGBUG this command may need to be changed to look at the stasis cache. */
+       if (!(cached_bridges = stasis_cache_dump(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type()))) {
+               ast_cli(a->fd, "Failed to retrieve cached bridges\n");
+               return CLI_SUCCESS;
+       }
+
        ast_cli(a->fd, FORMAT_HDR, "Bridge-ID", "Chans", "Type", "Technology");
-       iter = ao2_iterator_init(bridges, 0);
-       for (; (bridge = ao2_iterator_next(&iter)); ao2_ref(bridge, -1)) {
-               ast_bridge_lock(bridge);
+
+       iter = ao2_iterator_init(cached_bridges, 0);
+       for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
+               struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
+
                ast_cli(a->fd, FORMAT_ROW,
-                       bridge->uniqueid,
-                       bridge->num_channels,
-                       bridge->v_table ? bridge->v_table->name : "<unknown>",
-                       bridge->technology ? bridge->technology->name : "<unknown>");
-               ast_bridge_unlock(bridge);
+                       snapshot->uniqueid,
+                       snapshot->num_channels,
+                       S_OR(snapshot->subclass, "<unknown>"),
+                       S_OR(snapshot->technology, "<unknown>"));
        }
        ao2_iterator_destroy(&iter);
        return CLI_SUCCESS;
@@ -6958,10 +6955,28 @@ static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast
 #undef FORMAT_ROW
 }
 
+/*! \brief Internal callback function for sending channels in a bridge to the CLI */
+static int bridge_show_specific_print_channel(void *obj, void *arg, int flags)
+{
+       const char *uniqueid = obj;
+       struct ast_cli_args *a = arg;
+       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+       struct ast_channel_snapshot *snapshot;
+
+       if (!(msg = stasis_cache_get(ast_channel_topic_all_cached(), ast_channel_snapshot_type(), uniqueid))) {
+               return 0;
+       }
+       snapshot = stasis_message_data(msg);
+
+       ast_cli(a->fd, "Channel: %s\n", snapshot->name);
+
+       return 0;
+}
+
 static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       struct ast_bridge *bridge;
-       struct ast_bridge_channel *bridge_channel;
+       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+       struct ast_bridge_snapshot *snapshot;
 
        switch (cmd) {
        case CLI_INIT:
@@ -6977,28 +6992,22 @@ static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struc
                return NULL;
        }
 
-/* BUGBUG this command may need to be changed to look at the stasis cache. */
        if (a->argc != 3) {
                return CLI_SHOWUSAGE;
        }
 
-       bridge = ao2_find(bridges, a->argv[2], OBJ_KEY);
-       if (!bridge) {
+       msg = stasis_cache_get(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type(), a->argv[2]);
+       if (!msg) {
                ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);
                return CLI_SUCCESS;
        }
 
-       ast_bridge_lock(bridge);
-       ast_cli(a->fd, "Id: %s\n", bridge->uniqueid);
-       ast_cli(a->fd, "Type: %s\n", bridge->v_table ? bridge->v_table->name : "<unknown>");
-       ast_cli(a->fd, "Technology: %s\n",
-               bridge->technology ? bridge->technology->name : "<unknown>");
-       ast_cli(a->fd, "Num-Channels: %u\n", bridge->num_channels);
-       AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-               ast_cli(a->fd, "Channel: %s\n", ast_channel_name(bridge_channel->chan));
-       }
-       ast_bridge_unlock(bridge);
-       ao2_ref(bridge, -1);
+       snapshot = stasis_message_data(msg);
+       ast_cli(a->fd, "Id: %s\n", snapshot->uniqueid);
+       ast_cli(a->fd, "Type: %s\n", S_OR(snapshot->subclass, "<unknown>"));
+       ast_cli(a->fd, "Technology: %s\n", S_OR(snapshot->technology, "<unknown>"));
+       ast_cli(a->fd, "Num-Channels: %u\n", snapshot->num_channels);
+       ao2_callback(snapshot->channels, OBJ_NODATA, bridge_show_specific_print_channel, a);
 
        return CLI_SUCCESS;
 }
index 8ff9bf2..2d73bf1 100644 (file)
@@ -127,22 +127,6 @@ struct chanlist {
        AST_LIST_ENTRY(chanlist) list;
 };
 
-#ifdef CHANNEL_TRACE
-/*! \brief Structure to hold channel context backtrace data */
-struct ast_chan_trace_data {
-       int enabled;
-       AST_LIST_HEAD_NOLOCK(, ast_chan_trace) trace;
-};
-
-/*! \brief Structure to save contexts where an ast_chan has been into */
-struct ast_chan_trace {
-       char context[AST_MAX_CONTEXT];
-       char exten[AST_MAX_EXTENSION];
-       int priority;
-       AST_LIST_ENTRY(ast_chan_trace) entry;
-};
-#endif
-
 /*! \brief the list of registered channel types */
 static AST_RWLIST_HEAD_STATIC(backends, chanlist);
 
@@ -472,132 +456,6 @@ const struct ast_channel_tech ast_kill_tech = {
        .hangup = kill_hangup,
 };
 
-#ifdef CHANNEL_TRACE
-/*! \brief Destructor for the channel trace datastore */
-static void ast_chan_trace_destroy_cb(void *data)
-{
-       struct ast_chan_trace *trace;
-       struct ast_chan_trace_data *traced = data;
-       while ((trace = AST_LIST_REMOVE_HEAD(&traced->trace, entry))) {
-               ast_free(trace);
-       }
-       ast_free(traced);
-}
-
-/*! \brief Datastore to put the linked list of ast_chan_trace and trace status */
-static const struct ast_datastore_info ast_chan_trace_datastore_info = {
-       .type = "ChanTrace",
-       .destroy = ast_chan_trace_destroy_cb
-};
-
-/*! \brief Put the channel backtrace in a string */
-int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **buf)
-{
-       int total = 0;
-       struct ast_chan_trace *trace;
-       struct ast_chan_trace_data *traced;
-       struct ast_datastore *store;
-
-       ast_channel_lock(chan);
-       store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
-       if (!store) {
-               ast_channel_unlock(chan);
-               return total;
-       }
-       traced = store->data;
-       ast_str_reset(*buf);
-       AST_LIST_TRAVERSE(&traced->trace, trace, entry) {
-               if (ast_str_append(buf, 0, "[%d] => %s, %s, %d\n", total, trace->context, trace->exten, trace->priority) < 0) {
-                       ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
-                       total = -1;
-                       break;
-               }
-               total++;
-       }
-       ast_channel_unlock(chan);
-       return total;
-}
-
-/* !\brief Whether or not context tracing is enabled */
-int ast_channel_trace_is_enabled(struct ast_channel *chan)
-{
-       struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
-       if (!store)
-               return 0;
-       return ((struct ast_chan_trace_data *)store->data)->enabled;
-}
-
-/*! \brief Update the context backtrace data if tracing is enabled */
-static int ast_channel_trace_data_update(struct ast_channel *chan, struct ast_chan_trace_data *traced)
-{
-       struct ast_chan_trace *trace;
-       if (!traced->enabled)
-               return 0;
-       /* If the last saved context does not match the current one
-          OR we have not saved any context so far, then save the current context */
-       if ((!AST_LIST_EMPTY(&traced->trace) && strcasecmp(AST_LIST_FIRST(&traced->trace)->context, ast_channel_context(chan))) ||
-           (AST_LIST_EMPTY(&traced->trace))) {
-               /* Just do some debug logging */
-               if (AST_LIST_EMPTY(&traced->trace))
-                       ast_debug(1, "Setting initial trace context to %s\n", ast_channel_context(chan));
-               else
-                       ast_debug(1, "Changing trace context from %s to %s\n", AST_LIST_FIRST(&traced->trace)->context, ast_channel_context(chan));
-               /* alloc or bail out */
-               trace = ast_malloc(sizeof(*trace));
-               if (!trace)
-                       return -1;
-               /* save the current location and store it in the trace list */
-               ast_copy_string(trace->context, ast_channel_context(chan), sizeof(trace->context));
-               ast_copy_string(trace->exten, ast_channel_exten(chan), sizeof(trace->exten));
-               trace->priority = ast_channel_priority(chan);
-               AST_LIST_INSERT_HEAD(&traced->trace, trace, entry);
-       }
-       return 0;
-}
-
-/*! \brief Update the context backtrace if tracing is enabled */
-int ast_channel_trace_update(struct ast_channel *chan)
-{
-       struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
-       if (!store)
-               return 0;
-       return ast_channel_trace_data_update(chan, store->data);
-}
-
-/*! \brief Enable context tracing in the channel */
-int ast_channel_trace_enable(struct ast_channel *chan)
-{
-       struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
-       struct ast_chan_trace_data *traced;
-       if (!store) {
-               store = ast_datastore_alloc(&ast_chan_trace_datastore_info, "ChanTrace");
-               if (!store)
-                       return -1;
-               traced = ast_calloc(1, sizeof(*traced));
-               if (!traced) {
-                       ast_datastore_free(store);
-                       return -1;
-               }
-               store->data = traced;
-               AST_LIST_HEAD_INIT_NOLOCK(&traced->trace);
-               ast_channel_datastore_add(chan, store);
-       }
-       ((struct ast_chan_trace_data *)store->data)->enabled = 1;
-       ast_channel_trace_data_update(chan, store->data);
-       return 0;
-}
-
-/*! \brief Disable context tracing in the channel */
-int ast_channel_trace_disable(struct ast_channel *chan)
-{
-       struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
-       if (!store)
-               return 0;
-       ((struct ast_chan_trace_data *)store->data)->enabled = 0;
-       return 0;
-}
-#endif /* CHANNEL_TRACE */
-
 /*! \brief Checks to see if a channel is needing hang up */
 int ast_check_hangup(struct ast_channel *chan)
 {
@@ -5357,6 +5215,9 @@ static int set_format(struct ast_channel *chan,
                if (direction && ast_channel_generatordata(chan)) {
                        generator_write_format_change(chan);
                }
+
+               ast_channel_publish_snapshot(chan);
+
                return 0;
        }
 
@@ -5429,6 +5290,9 @@ static int set_format(struct ast_channel *chan,
        if (direction && ast_channel_generatordata(chan)) {
                generator_write_format_change(chan);
        }
+
+       ast_channel_publish_snapshot(chan);
+
        return res;
 }
 
@@ -7782,7 +7646,7 @@ void ast_channel_set_manager_vars(size_t varc, char **vars)
 }
 
 /*!
- * \brief Destructor for the return value from ast_channel_get_manager_vars().
+ * \brief Destructor for lists of variables.
  * \param obj AO2 object.
  */
 static void varshead_dtor(void *obj)
@@ -7795,6 +7659,31 @@ static void varshead_dtor(void *obj)
        }
 }
 
+struct varshead *ast_channel_get_vars(struct ast_channel *chan)
+{
+       RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
+       struct ast_var_t *cv;
+
+       ret = ao2_alloc(sizeof(*ret), varshead_dtor);
+
+       if (!ret) {
+               return NULL;
+       }
+
+       AST_LIST_TRAVERSE(ast_channel_varshead(chan), cv, entries) {
+               struct ast_var_t *var = ast_var_assign(ast_var_name(cv), ast_var_value(cv));
+
+               if (!var) {
+                       return NULL;
+               }
+
+               AST_LIST_INSERT_TAIL(ret, var, entries);
+       }
+
+       ao2_ref(ret, +1);
+       return ret;
+}
+
 struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
 {
        RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
index 085052a..bb63eeb 100644 (file)
@@ -868,6 +868,7 @@ const struct ast_channel_tech *ast_channel_tech(const struct ast_channel *chan)
 void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
 {
        chan->tech = value;
+       ast_channel_publish_snapshot(chan);
 }
 enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan)
 {
@@ -913,6 +914,7 @@ void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *callid)
                call_identifier_to,
                call_identifier_from);
 
+       ast_channel_publish_snapshot(chan);
 }
 void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state value)
 {
@@ -1037,6 +1039,7 @@ void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value)
 void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *value)
 {
        chan->whentohangup = *value;
+       ast_channel_publish_snapshot(chan);
 }
 void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value)
 {
@@ -1094,6 +1097,7 @@ ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
 void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value)
 {
        chan->callgroup = value;
+       ast_channel_publish_snapshot(chan);
 }
 ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
 {
@@ -1102,6 +1106,7 @@ ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
 void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
 {
        chan->pickupgroup = value;
+       ast_channel_publish_snapshot(chan);
 }
 struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan)
 {
@@ -1277,6 +1282,7 @@ struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan)
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value)
 {
        chan->bridge = value;
+       ast_channel_publish_snapshot(chan);
 }
 
 struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan)
index 3431d1d..3495171 100644 (file)
@@ -61,6 +61,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/threadstorage.h"
 #include "asterisk/translate.h"
 #include "asterisk/bridging.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/stasis_bridging.h"
 
 /*!
  * \brief List of restrictions per user.
@@ -877,9 +879,10 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 #define VERBOSE_FORMAT_STRING  "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
 #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
 
-       struct ast_channel *c = NULL;
+       RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
+       struct ao2_iterator it_chans;
+       struct stasis_message *msg;
        int numchans = 0, concise = 0, verbose = 0, count = 0;
-       struct ast_channel_iterator *iter = NULL;
 
        switch (cmd) {
        case CLI_INIT:
@@ -911,6 +914,12 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
        } else if (a->argc != e->args - 1)
                return CLI_SHOWUSAGE;
 
+
+       if (!(channels = stasis_cache_dump(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type()))) {
+               ast_cli(a->fd, "Failed to retrieve cached channels\n");
+               return CLI_SUCCESS;
+       }
+
        if (!count) {
                if (!concise && !verbose)
                        ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
@@ -919,21 +928,14 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                                "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgeID");
        }
 
-       if (!count && !(iter = ast_channel_iterator_all_new())) {
-               return CLI_FAILURE;
-       }
-
-       for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
-               struct ast_bridge *bridge;
+       it_chans = ao2_iterator_init(channels, 0);
+       for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {
+               struct ast_channel_snapshot *cs = stasis_message_data(msg);
                char durbuf[10] = "-";
 
-               ast_channel_lock(c);
-
-               bridge = ast_channel_get_bridge(c);
-
                if (!count) {
-                       if ((concise || verbose)  && !ast_tvzero(ast_channel_creationtime(c))) {
-                               int duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(c)) / 1000);
+                       if ((concise || verbose)  && !ast_tvzero(cs->creationtime)) {
+                               int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
                                if (verbose) {
                                        int durh = duration / 3600;
                                        int durm = (duration % 3600) / 60;
@@ -944,43 +946,38 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                                }
                        }
                        if (concise) {
-                               ast_cli(a->fd, CONCISE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)),
-                                       ast_channel_appl(c) ? ast_channel_appl(c) : "(None)",
-                                       S_OR(ast_channel_data(c), ""),  /* XXX different from verbose ? */
-                                       S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
-                                       S_OR(ast_channel_accountcode(c), ""),
-                                       S_OR(ast_channel_peeraccount(c), ""),
-                                       ast_channel_amaflags(c),
+                               ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
+                                       S_OR(cs->appl, "(None)"),
+                                       cs->data,
+                                       cs->caller_number,
+                                       cs->accountcode,
+                                       cs->peeraccount,
+                                       cs->amaflags,
                                        durbuf,
-                                       bridge ? bridge->uniqueid : "(Not bridged)",
-                                       ast_channel_uniqueid(c));
+                                       cs->bridgeid,
+                                       cs->uniqueid);
                        } else if (verbose) {
-                               ast_cli(a->fd, VERBOSE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)),
-                                       ast_channel_appl(c) ? ast_channel_appl(c) : "(None)",
-                                       ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)" ): "(None)",
-                                       S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
+                               ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
+                                       S_OR(cs->appl, "(None)"),
+                                       S_OR(cs->data, "(Empty)"),
+                                       cs->caller_number,
                                        durbuf,
-                                       S_OR(ast_channel_accountcode(c), ""),
-                                       S_OR(ast_channel_peeraccount(c), ""),
-                                       bridge ? bridge->uniqueid : "(Not bridged)");
+                                       cs->accountcode,
+                                       cs->peeraccount,
+                                       cs->bridgeid);
                        } else {
                                char locbuf[40] = "(None)";
                                char appdata[40] = "(None)";
 
-                               if (!ast_strlen_zero(ast_channel_context(c)) && !ast_strlen_zero(ast_channel_exten(c)))
-                                       snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", ast_channel_exten(c), ast_channel_context(c), ast_channel_priority(c));
-                               if (ast_channel_appl(c))
-                                       snprintf(appdata, sizeof(appdata), "%s(%s)", ast_channel_appl(c), S_OR(ast_channel_data(c), ""));
-                               ast_cli(a->fd, FORMAT_STRING, ast_channel_name(c), locbuf, ast_state2str(ast_channel_state(c)), appdata);
+                               if (!cs->context && !cs->exten)
+                                       snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority);
+                               if (cs->appl)
+                                       snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, ""));
+                               ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata);
                        }
                }
-               ast_channel_unlock(c);
-               ao2_cleanup(bridge);
-       }
-
-       if (iter) {
-               ast_channel_iterator_destroy(iter);
        }
+       ao2_iterator_destroy(&it_chans);
 
        if (!concise) {
                numchans = ast_active_channels();
@@ -1414,23 +1411,15 @@ static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, str
 
 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       struct ast_channel *c=NULL;
+       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+       struct ast_channel_snapshot *snapshot;
        struct timeval now;
        char cdrtime[256];
-       char nf[256];
-       struct ast_str *write_transpath = ast_str_alloca(256);
-       struct ast_str *read_transpath = ast_str_alloca(256);
-       struct ast_str *obuf;/*!< Buffer for variable, CDR variable, and trace output. */
+       struct ast_str *obuf;/*!< Buffer for CDR variables. */
        struct ast_str *output;/*!< Accumulation buffer for all output. */
        long elapsed_seconds=0;
        int hour=0, min=0, sec=0;
-       struct ast_callid *callid;
-       char call_identifier_str[AST_CALLID_BUFFER_LENGTH] = "";
-       struct ast_party_id effective_connected_id;
-#ifdef CHANNEL_TRACE
-       int trace_enabled;
-#endif
-       struct ast_bridge *bridge;
+       struct ast_var_t *var;
 
        switch (cmd) {
        case CLI_INIT:
@@ -1449,10 +1438,11 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 
        now = ast_tvnow();
 
-       if (!(c = ast_channel_get_by_name(a->argv[3]))) {
+       if (!(msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), a->argv[3]))) {
                ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
                return CLI_SUCCESS;
        }
+       snapshot = stasis_message_data(msg);
 
        obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
        if (!obuf) {
@@ -1463,10 +1453,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                return CLI_FAILURE;
        }
 
-       ast_channel_lock(c);
-
-       if (!ast_tvzero(ast_channel_creationtime(c))) {
-               elapsed_seconds = now.tv_sec - ast_channel_creationtime(c).tv_sec;
+       if (!ast_tvzero(snapshot->creationtime)) {
+               elapsed_seconds = now.tv_sec - snapshot->creationtime.tv_sec;
                hour = elapsed_seconds / 3600;
                min = (elapsed_seconds % 3600) / 60;
                sec = elapsed_seconds % 60;
@@ -1475,15 +1463,6 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                strcpy(cdrtime, "N/A");
        }
 
-       /* Construct the call identifier string based on the status of the channel's call identifier */
-       if ((callid = ast_channel_callid(c))) {
-               ast_callid_strnprint(call_identifier_str, sizeof(call_identifier_str), callid);
-               ast_callid_unref(callid);
-       }
-
-       effective_connected_id = ast_channel_connected_effective_id(c);
-       bridge = ast_channel_get_bridge(c);
-
        ast_str_append(&output, 0,
                " -- General --\n"
                "           Name: %s\n"
@@ -1499,15 +1478,11 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                "    DNID Digits: %s\n"
                "       Language: %s\n"
                "          State: %s (%d)\n"
-               "          Rings: %d\n"
                "  NativeFormats: %s\n"
                "    WriteFormat: %s\n"
                "     ReadFormat: %s\n"
                " WriteTranscode: %s %s\n"
                "  ReadTranscode: %s %s\n"
-               "1st File Descriptor: %d\n"
-               "      Frames in: %d%s\n"
-               "     Frames out: %d%s\n"
                " Time to Hangup: %ld\n"
                "   Elapsed Time: %s\n"
                "      Bridge ID: %s\n"
@@ -1519,68 +1494,49 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                "   Pickup Group: %llu\n"
                "    Application: %s\n"
                "           Data: %s\n"
-               "    Blocking in: %s\n"
                " Call Identifer: %s\n",
-               ast_channel_name(c),
-               ast_channel_tech(c)->type,
-               ast_channel_uniqueid(c),
-               ast_channel_linkedid(c),
-               S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"),
-               S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"),
-               S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"),
-               S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"),
-               S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "(N/A)"),
-               S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "(N/A)"),
-               S_OR(ast_channel_dialed(c)->number.str, "(N/A)"),
-               ast_channel_language(c),
-               ast_state2str(ast_channel_state(c)),
-               ast_channel_state(c),
-               ast_channel_rings(c),
-               ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)),
-               ast_getformatname(ast_channel_writeformat(c)),
-               ast_getformatname(ast_channel_readformat(c)),
-               ast_channel_writetrans(c) ? "Yes" : "No",
-               ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath),
-               ast_channel_readtrans(c) ? "Yes" : "No",
-               ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath),
-               ast_channel_fd(c, 0),
-               ast_channel_fin(c) & ~DEBUGCHAN_FLAG,
-               (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
-               ast_channel_fout(c) & ~DEBUGCHAN_FLAG,
-               (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
-               (long) ast_channel_whentohangup(c)->tv_sec,
+               snapshot->name,
+               snapshot->type,
+               snapshot->uniqueid,
+               snapshot->linkedid,
+               S_OR(snapshot->caller_number, "(N/A)"),
+               S_OR(snapshot->caller_name, "(N/A)"),
+               S_OR(snapshot->connected_number, "(N/A)"),
+               S_OR(snapshot->connected_name, "(N/A)"),
+               S_OR(snapshot->effective_number, "(N/A)"),
+               S_OR(snapshot->effective_name, "(N/A)"),
+               S_OR(snapshot->caller_dnid, "(N/A)"),
+               snapshot->language,
+               ast_state2str(snapshot->state),
+               snapshot->state,
+               snapshot->nativeformats,
+               snapshot->writeformat,
+               snapshot->readformat,
+               !ast_strlen_zero(snapshot->writetrans) ? "Yes" : "No",
+               snapshot->writetrans,
+               !ast_strlen_zero(snapshot->readtrans) ? "Yes" : "No",
+               snapshot->readtrans,
+               (long) snapshot->hanguptime.tv_sec,
                cdrtime,
-               bridge ? bridge->uniqueid : "(Not bridged)",
-               ast_channel_context(c),
-               ast_channel_exten(c),
-               ast_channel_priority(c),
-               ast_channel_callgroup(c),
-               ast_channel_pickupgroup(c),
-               (ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)" ),
-               (ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)"),
-               (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"),
-               S_OR(call_identifier_str, "(None)"));
-
-       if (pbx_builtin_serialize_variables(c, &obuf)) {
-               ast_str_append(&output, 0, "      Variables:\n%s\n", ast_str_buffer(obuf));
-       }
-
-       if (ast_cdr_serialize_variables(ast_channel_name(c), &obuf, '=', '\n')) {
-               ast_str_append(&output, 0, "  CDR Variables:\n%s\n", ast_str_buffer(obuf));
-       }
+               S_OR(snapshot->bridgeid, "(Not bridged)"),
+               snapshot->context,
+               snapshot->exten,
+               snapshot->priority,
+               snapshot->callgroup,
+               snapshot->pickupgroup,
+               S_OR(snapshot->appl, "(N/A)"),
+               S_OR(snapshot->data, "(Empty)"),
+               S_OR(snapshot->callid, "(None)"));
+
+       ast_str_append(&output, 0, "      Variables:\n");
 
-#ifdef CHANNEL_TRACE
-       trace_enabled = ast_channel_trace_is_enabled(c);
-       ast_str_append(&output, 0, "  Context Trace: %s\n",
-               trace_enabled ? "Enabled" : "Disabled");
-       if (trace_enabled && ast_channel_trace_serialize(c, &obuf)) {
-               ast_str_append(&output, 0, "          Trace:\n%s\n", ast_str_buffer(obuf));
+       AST_LIST_TRAVERSE(snapshot->channel_vars, var, entries) {
+               ast_str_append(&output, 0, "%s=%s\n", ast_var_name(var), ast_var_value(var));
        }
-#endif
 
-       ast_channel_unlock(c);
-       c = ast_channel_unref(c);
-       ao2_cleanup(bridge);
+       if (ast_cdr_serialize_variables(snapshot->name, &obuf, '=', '\n')) {
+               ast_str_append(&output, 0, "  CDR Variables:\n%s\n", ast_str_buffer(obuf));
+       }
 
        ast_cli(a->fd, "%s", ast_str_buffer(output));
        ast_free(output);
@@ -1605,38 +1561,32 @@ char *ast_cli_complete(const char *word, const char * const choices[], int state
 
 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
 {
-       struct ast_channel *c = NULL;
-       int which = 0;
-       char notfound = '\0';
-       char *ret = &notfound; /* so NULL can break the loop */
-       struct ast_channel_iterator *iter;
+       int wordlen = strlen(word), which = 0;
+       RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup);
+       char *ret = NULL;
+       struct ao2_iterator iter;
+       struct stasis_message *msg;
 
        if (pos != rpos) {
                return NULL;
        }
 
-       if (ast_strlen_zero(word)) {
-               iter = ast_channel_iterator_all_new();
-       } else {
-               iter = ast_channel_iterator_by_name_new(word, strlen(word));
-       }
-
-       if (!iter) {
+       if (!(cached_channels = stasis_cache_dump(ast_channel_topic_all_cached(), ast_channel_snapshot_type()))) {
                return NULL;
        }
 
-       while (ret == &notfound && (c = ast_channel_iterator_next(iter))) {
-               if (++which > state) {
-                       ast_channel_lock(c);
-                       ret = ast_strdup(ast_channel_name(c));
-                       ast_channel_unlock(c);
+       iter = ao2_iterator_init(cached_channels, 0);
+       for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
+               struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+
+               if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) {
+                       ret = ast_strdup(snapshot->name);
+                       break;
                }
-               ast_channel_unref(c);
        }
+       ao2_iterator_destroy(&iter);
 
-       ast_channel_iterator_destroy(iter);
-
-       return ret == &notfound ? NULL : ret;
+       return ret;
 }
 
 static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -2037,7 +1987,7 @@ static char *is_prefix(const char *word, const char *token,
  * \param cmds
  * \param match_type has 3 possible values:
  *      0       returns if the search key is equal or longer than the entry.
- *                         note that trailing optional arguments are skipped.
+ *                         note that trailing optional arguments are skipped.
  *      -1      true if the mismatch is on the last word XXX not true!
  *      1       true only on complete, exact match.
  *
index b8b067d..d5efc47 100644 (file)
@@ -92,8 +92,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/strings.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/presencestate.h"
-#include "asterisk/stasis.h"
 #include "asterisk/stasis_message_router.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/stasis_bridging.h"
 #include "asterisk/test.h"
 #include "asterisk/json.h"
 #include "asterisk/bridging.h"
@@ -221,6 +222,106 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        value for the specified channel variables.</para>
                </description>
        </manager>
+       <managerEvent language="en_US" name="Status">
+               <managerEventInstance class="EVENT_FLAG_CALL">
+                       <synopsis>Raised in response to a Status command.</synopsis>
+                       <syntax>
+                               <parameter name="ActionID" required="false"/>
+                               <parameter name="Channel">
+                                       <para>Name of the channel</para>
+                               </parameter>
+                               <parameter name="Type">
+                                       <para>Type of channel</para>
+                               </parameter>
+                               <parameter name="DNID">
+                                       <para>Dialed number identifier</para>
+                               </parameter>
+                               <parameter name="ChannelState">
+                                       <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
+                               </parameter>
+                               <parameter name="ChannelStateDesc">
+                                       <para>Name for the channel's current state</para>
+                                       <enumlist>
+                                               <enum name="Down"/>
+                                               <enum name="Rsrvd"/>
+                                               <enum name="OffHook"/>
+                                               <enum name="Dialing"/>
+                                               <enum name="Ring"/>
+                                               <enum name="Ringing"/>
+                                               <enum name="Up"/>
+                                               <enum name="Busy"/>
+                                               <enum name="Dialing Offhook"/>
+                                               <enum name="Pre-ring"/>
+                                               <enum name="Unknown"/>
+                                       </enumlist>
+                               </parameter>
+                               <parameter name="CallerIDNum">
+                               </parameter>
+                               <parameter name="CallerIDName">
+                               </parameter>
+                               <parameter name="ConnectedLineNum">
+                               </parameter>
+                               <parameter name="ConnectedLineName">
+                               </parameter>
+                               <parameter name="EffectiveConnectedLineNum">
+                               </parameter>
+                               <parameter name="EffectiveConnectedLineName">
+                               </parameter>
+                               <parameter name="AccountCode">
+                               </parameter>
+                               <parameter name="Context">
+                               </parameter>
+                               <parameter name="Exten">
+                               </parameter>
+                               <parameter name="Priority">
+                               </parameter>
+                               <parameter name="Uniqueid">
+                                       <para>Unique identifier for the channel</para>
+                               </parameter>
+                               <parameter name="TimeToHangup">
+                                       <para>Absolute lifetime of the channel</para>
+                               </parameter>
+                               <parameter name="BridgeID">
+                                       <para>Identifier of the bridge the channel is in, may be empty if not in one</para>
+                               </parameter>
+                               <parameter name="Linkedid">
+                               </parameter>
+                               <parameter name="Application">
+                                       <para>Application currently executing on the channel</para>
+                               </parameter>
+                               <parameter name="Data">
+                                       <para>Data given to the currently executing channel</para>
+                               </parameter>
+                               <parameter name="Nativeformats">
+                                       <para>Media formats the connected party is willing to send or receive</para>
+                               </parameter>
+                               <parameter name="Readformat">
+                                       <para>Media formats that frames from the channel are received in</para>
+                               </parameter>
+                               <parameter name="Readtrans">
+                                       <para>Translation path for media received in native formats</para>
+                               </parameter>
+                               <parameter name="Writeformat">
+                                       <para>Media formats that frames to the channel are accepted in</para>
+                               </parameter>
+                               <parameter name="Writetrans">
+                                       <para>Translation path for media sent to the connected party</para>
+                               </parameter>
+                               <parameter name="Callgroup">
+                                       <para>Configured call group on the channel</para>
+                               </parameter>
+                               <parameter name="Pickupgroup">
+                                       <para>Configured pickup group on the channel</para>
+                               </parameter>
+                               <parameter name="Seconds">
+                                       <para>Number of seconds the channel has been active</para>
+                               </parameter>
+                       </syntax>
+                       <see-also>
+                               <ref type="manager">Status</ref>
+                       </see-also>
+               </managerEventInstance>
+       </managerEvent>
        <manager name="Setvar" language="en_US">
                <synopsis>
                        Set a channel variable.
@@ -3745,11 +3846,8 @@ static int action_status(struct mansession *s, const struct message *m)
        const char *name = astman_get_header(m, "Channel");
        const char *cvariables = astman_get_header(m, "Variables");
        char *variables = ast_strdupa(S_OR(cvariables, ""));
-       struct ast_channel *c;
-       struct ast_bridge *bridge;
-       char bridge_text[256];
-       struct timeval now = ast_tvnow();
-       long elapsed_seconds = 0;
+       RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup);
+       struct stasis_message *msg;
        int channels = 0;
        int all = ast_strlen_zero(name); /* set if we want all channels */
        const char *id = astman_get_header(m, "ActionID");
@@ -3758,7 +3856,8 @@ static int action_status(struct mansession *s, const struct message *m)
                AST_APP_ARG(name)[100];
        );
        struct ast_str *str = ast_str_create(1000);
-       struct ast_channel_iterator *iter = NULL;
+       struct ao2_iterator it_chans;
+       struct timeval now = ast_tvnow();
 
        if (!ast_strlen_zero(id)) {
                snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
@@ -3772,14 +3871,15 @@ static int action_status(struct mansession *s, const struct message *m)
        }
 
        if (all) {
-               if (!(iter = ast_channel_iterator_all_new())) {
+               if (!(cached_channels = stasis_cache_dump(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type()))) {
                        ast_free(str);
                        astman_send_error(s, m, "Memory Allocation Failure");
                        return 1;
                }
-               c = ast_channel_iterator_next(iter);
+               it_chans = ao2_iterator_init(cached_channels, 0);
+               msg = ao2_iterator_next(&it_chans);
        } else {
-               if (!(c = ast_channel_get_by_name(name))) {
+               if (!(msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), name))) {
                        astman_send_error(s, m, "No such channel");
                        ast_free(str);
                        return 0;
@@ -3793,10 +3893,17 @@ static int action_status(struct mansession *s, const struct message *m)
        }
 
        /* if we look by name, we break after the first iteration */
-       for (; c; c = ast_channel_iterator_next(iter)) {
-               ast_channel_lock(c);
+       for (; msg; ao2_ref(msg, -1), msg = ao2_iterator_next(&it_chans)) {
+               struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+               struct ast_channel *c;
+               struct ast_str *built = ast_manager_build_channel_state_string_prefix(snapshot, "");
+               long elapsed_seconds = 0;
+
+               if (!built) {
+                       continue;
+               }
 
-               if (!ast_strlen_zero(cvariables)) {
+               if (!ast_strlen_zero(cvariables) && (c = ast_channel_get_by_name(snapshot->name))) {
                        int i;
                        ast_str_reset(str);
                        for (i = 0; i < vars.argc; i++) {
@@ -3813,94 +3920,70 @@ static int action_status(struct mansession *s, const struct message *m)
 
                                ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
                        }
+                       ast_channel_unref(c);
                }
 
                channels++;
-               bridge = ast_channel_get_bridge(c);
-               if (bridge) {
-                       snprintf(bridge_text, sizeof(bridge_text), "BridgeID: %s\r\n",
-                               bridge->uniqueid);
-                       ao2_ref(bridge, -1);
-               } else {
-                       bridge_text[0] = '\0';
+
+
+               if (!ast_tvzero(snapshot->creationtime)) {
+                       elapsed_seconds = now.tv_sec - snapshot->creationtime.tv_sec;
                }
-               if (ast_channel_pbx(c)) {
-                       if (!ast_tvzero(ast_channel_creationtime(c))) {
-                               elapsed_seconds = now.tv_sec - ast_channel_creationtime(c).tv_sec;
-                       }
-                       astman_append(s,
-                               "Event: Status\r\n"
-                               "Privilege: Call\r\n"
-                               "Channel: %s\r\n"
-                               "CallerIDNum: %s\r\n"
-                               "CallerIDName: %s\r\n"
-                               "ConnectedLineNum: %s\r\n"
-                               "ConnectedLineName: %s\r\n"
-                               "Accountcode: %s\r\n"
-                               "ChannelState: %d\r\n"
-                               "ChannelStateDesc: %s\r\n"
-                               "Context: %s\r\n"
-                               "Extension: %s\r\n"
-                               "Priority: %d\r\n"
-                               "Seconds: %ld\r\n"
-                               "%s"
-                               "Uniqueid: %s\r\n"
-                               "%s"
-                               "%s"
-                               "\r\n",
-                               ast_channel_name(c),
-                               S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"),
-                               S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"),
-                               S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"),
-                               S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"),
-                               ast_channel_accountcode(c),
-                               ast_channel_state(c),
-                               ast_state2str(ast_channel_state(c)),
-                               ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
-                               (long) elapsed_seconds,
-                               bridge_text,
-                               ast_channel_uniqueid(c),
-                               ast_str_buffer(str),
-                               idText);
-               } else {
-                       astman_append(s,
-                               "Event: Status\r\n"
-                               "Privilege: Call\r\n"
-                               "Channel: %s\r\n"
-                               "CallerIDNum: %s\r\n"
-                               "CallerIDName: %s\r\n"
-                               "ConnectedLineNum: %s\r\n"
-                               "ConnectedLineName: %s\r\n"
-                               "Account: %s\r\n"
-                               "State: %s\r\n"
-                               "%s"
-                               "Uniqueid: %s\r\n"
-                               "%s"
-                               "%s"
-                               "\r\n",
-                               ast_channel_name(c),
-                               S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"),
-                               S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"),
-                               S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"),
-                               S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"),
-                               ast_channel_accountcode(c),
-                               ast_state2str(ast_channel_state(c)),
-                               bridge_text,
-                               ast_channel_uniqueid(c),
-                               ast_str_buffer(str),
-                               idText);
-               }
-
-               ast_channel_unlock(c);
-               c = ast_channel_unref(c);
+
+               astman_append(s,
+                       "Event: Status\r\n"
+                       "Privilege: Call\r\n"
+                       "Type: %s\r\n"
+                       "DNID: %s\r\n"
+                       "EffectiveConnectedLineNum: %s\r\n"
+                       "EffectiveConnectedLineName: %s\r\n"
+                       "TimeToHangup: %ld\r\n"
+                       "BridgeID: %s\r\n"
+                       "Linkedid: %s\r\n"
+                       "Application: %s\r\n"
+                       "Data: %s\r\n"
+                       "Nativeformats: %s\r\n"
+                       "Readformat: %s\r\n"
+                       "Readtrans: %s\r\n"
+                       "Writeformat: %s\r\n"
+                       "Writetrans: %s\r\n"
+                       "Callgroup: %llu\r\n"
+                       "Pickupgroup: %llu\r\n"
+                       "Seconds: %ld\r\n"
+                       "%s"
+                       "%s"
+                       "%s"
+                       "\r\n",
+                       snapshot->type,
+                       snapshot->caller_dnid,
+                       S_OR(snapshot->effective_number, "<unknown>"),
+                       S_OR(snapshot->effective_name, "<unknown>"),
+                       snapshot->hanguptime.tv_sec,
+                       snapshot->bridgeid,
+                       snapshot->linkedid,
+                       snapshot->appl,
+                       snapshot->data,
+                       snapshot->nativeformats,
+                       snapshot->readformat,
+                       snapshot->readtrans,
+                       snapshot->writeformat,
+                       snapshot->writetrans,
+                       snapshot->callgroup,
+                       snapshot->pickupgroup,
+                       (long) elapsed_seconds,
+                       ast_str_buffer(built),
+                       ast_str_buffer(str),
+                       idText);
+
+               ast_free(built);
 
                if (!all) {
                        break;
                }
        }
 
-       if (iter) {
-               ast_channel_iterator_destroy(iter);
+       if (all) {
+               ao2_iterator_destroy(&it_chans);
        }
 
        astman_append(s,
@@ -5259,10 +5342,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 {
        const char *actionid = astman_get_header(m, "ActionID");
        char idText[256];
-       struct ast_channel *c = NULL;
        int numchans = 0;
-       int duration, durh, durm, durs;
-       struct ast_channel_iterator *iter;
+       RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
+       struct ao2_iterator it_chans;
+       struct stasis_message *msg;
 
        if (!ast_strlen_zero(actionid)) {
                snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
@@ -5270,60 +5353,35 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                idText[0] = '\0';
        }
 
-       if (!(iter = ast_channel_iterator_all_new())) {
-               astman_send_error(s, m, "Memory Allocation Failure");
-               return 1;
+       if (!(channels = stasis_cache_dump(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type()))) {
+               astman_send_error(s, m, "Could not get cached channels");
+               return 0;
        }
 
        astman_send_listack(s, m, "Channels will follow", "start");
 
-       for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
-               struct ast_channel *bc;
-               char durbuf[10] = "";
-
-               ast_channel_lock(c);
+       it_chans = ao2_iterator_init(channels, 0);
+       for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {
+               struct ast_channel_snapshot *cs = stasis_message_data(msg);
+               struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, "");
 
-               bc = ast_bridged_channel(c);
-               if (!ast_tvzero(ast_channel_creationtime(c))) {
-                       duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_creationtime(c)) / 1000);
-                       durh = duration / 3600;
-                       durm = (duration % 3600) / 60;
-                       durs = duration % 60;
-                       snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
+               if (!built) {
+                       continue;
                }
 
                astman_append(s,
                        "Event: CoreShowChannel\r\n"
                        "%s"
-                       "Channel: %s\r\n"
-                       "UniqueID: %s\r\n"
-                       "Context: %s\r\n"
-                       "Extension: %s\r\n"
-                       "Priority: %d\r\n"
-                       "ChannelState: %d\r\n"
-                       "ChannelStateDesc: %s\r\n"
-                       "Application: %s\r\n"
-                       "ApplicationData: %s\r\n"
-                       "CallerIDnum: %s\r\n"
-                       "CallerIDname: %s\r\n"
-                       "ConnectedLineNum: %s\r\n"
-                       "ConnectedLineName: %s\r\n"
-                       "Duration: %s\r\n"
-                       "AccountCode: %s\r\n"
-                       "BridgedChannel: %s\r\n"
-                       "BridgedUniqueID: %s\r\n"
-                       "\r\n", idText, ast_channel_name(c), ast_channel_uniqueid(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_state(c),
-                       ast_state2str(ast_channel_state(c)), ast_channel_appl(c) ? ast_channel_appl(c) : "", ast_channel_data(c) ? S_OR(ast_channel_data(c), "") : "",
-                       S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
-                       S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
-                       S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, ""),
-                       S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, ""),
-                       durbuf, S_OR(ast_channel_accountcode(c), ""), bc ? ast_channel_name(bc) : "", bc ? ast_channel_uniqueid(bc) : "");
-
-               ast_channel_unlock(c);
+                       "%s"
+                       "\r\n",
+                       idText,
+                       ast_str_buffer(built));
 
                numchans++;
+
+               ast_free(built);
        }
+       ao2_iterator_destroy(&it_chans);
 
        astman_append(s,
                "Event: CoreShowChannelsComplete\r\n"
@@ -5332,8 +5390,6 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                "%s"
                "\r\n", numchans, idText);
 
-       ast_channel_iterator_destroy(iter);
-
        return 0;
 }
 
index 5e5f409..7fbbbea 100644 (file)
@@ -41,10 +41,17 @@ static struct stasis_message_router *bridge_state_router;
                        <synopsis>Raised when a bridge is created.</synopsis>
                        <syntax>
                                <parameter name="BridgeUniqueid">
+                                       <para>The unique identifier of the bridge</para>
                                </parameter>
                                <parameter name="BridgeType">
                                        <para>The type of bridge</para>
                                </parameter>
+                               <parameter name="BridgeTechnology">
+                                       <para>Technology in use by the bridge</para>
+                               </parameter>
+                               <parameter name="BridgeNumChannels">
+                                       <para>Number of channels in the bridge</para>
+                               </parameter>
                        </syntax>
                </managerEventInstance>
        </managerEvent>
@@ -124,9 +131,13 @@ struct ast_str *ast_manager_build_bridge_state_string(
        }
        res = ast_str_set(&out, 0,
                "BridgeUniqueid%s: %s\r\n"
-               "BridgeType%s: %s\r\n",
+               "BridgeType%s: %s\r\n"
+               "BridgeTechnology%s: %s\r\n"
+               "BridgeNumChannels%s: %d\r\n",
                suffix, snapshot->uniqueid,
-               suffix, snapshot->technology);
+               suffix, snapshot->subclass,
+               suffix, snapshot->technology,
+               suffix, snapshot->num_channels);
 
        if (!res) {
                return NULL;
index 7dd91a6..bc9e83d 100644 (file)
@@ -43,11 +43,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <synopsis>Raised when a new channel is created.</synopsis>
                        <syntax>
                                <parameter name="Channel">
+                                       <para>Name of the channel</para>
                                </parameter>
                                <parameter name="ChannelState">
                                        <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
                                </parameter>
                                <parameter name="ChannelStateDesc">
+                                       <para>Name for the channel's current state</para>
                                        <enumlist>
                                                <enum name="Down"/>
                                                <enum name="Rsrvd"/>
@@ -79,6 +81,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                <parameter name="Priority">
                                </parameter>
                                <parameter name="Uniqueid">
+                                       <para>Unique identifier for the channel</para>
                                </parameter>
                        </syntax>
                </managerEventInstance>
@@ -525,9 +528,11 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
 {
        struct ast_str *out = ast_str_create(1024);
        int res = 0;
+
        if (!out) {
                return NULL;
        }
+
        res = ast_str_set(&out, 0,
                "%sChannel: %s\r\n"
                "%sChannelState: %d\r\n"
index f3d9184..21a1a14 100644 (file)
@@ -4643,9 +4643,6 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                                ast_channel_exten_set(c, exten);
                        ast_channel_priority_set(c, priority);
                        pbx_substitute_variables(passdata, sizeof(passdata), c, e);
-#ifdef CHANNEL_TRACE
-                       ast_channel_trace_update(c);
-#endif
                        ast_debug(1, "Launching '%s'\n", app->name);
                        {
                                ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
@@ -8028,8 +8025,9 @@ static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, str
 /*! \brief CLI support for listing chanvar's variables in a parseable way */
 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       struct ast_channel *chan = NULL;
-       struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
+       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+       struct ast_channel_snapshot *snapshot;
+       struct ast_var_t *var;
 
        switch (cmd) {
        case CLI_INIT:
@@ -8045,19 +8043,16 @@ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cl
        if (a->argc != e->args + 1)
                return CLI_SHOWUSAGE;
 
-       if (!(chan = ast_channel_get_by_name(a->argv[e->args]))) {
+       if (!(msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), a->argv[3]))) {
                ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
                return CLI_FAILURE;
        }
+       snapshot = stasis_message_data(msg);
 
-       pbx_builtin_serialize_variables(chan, &vars);
-
-       if (ast_str_strlen(vars)) {
-               ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
+       AST_LIST_TRAVERSE(snapshot->channel_vars, var, entries) {
+               ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
        }
 
-       chan = ast_channel_unref(chan);
-
        return CLI_SUCCESS;
 }
 
@@ -10985,6 +10980,10 @@ int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
                newvariable = ast_var_assign(name, value);
                AST_LIST_INSERT_HEAD(headp, newvariable, entries);
                ast_channel_publish_varset(chan, name, value);
+
+               if (headp != &globals) {
+                       ast_channel_publish_snapshot(chan);
+               }
        }
 
        if (chan)
index 9179878..eb71531 100644 (file)
@@ -35,6 +35,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/astobj2.h"
 #include "asterisk/json.h"
 #include "asterisk/pbx.h"
+#include "asterisk/bridging.h"
+#include "asterisk/translate.h"
 #include "asterisk/stasis.h"
 #include "asterisk/stasis_channels.h"
 
@@ -121,13 +123,21 @@ static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
 static void channel_snapshot_dtor(void *obj)
 {
        struct ast_channel_snapshot *snapshot = obj;
+
        ast_string_field_free_memory(snapshot);
        ao2_cleanup(snapshot->manager_vars);
+       ao2_cleanup(snapshot->channel_vars);
 }
 
 struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
 {
        RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+       char nativeformats[256];
+       struct ast_str *write_transpath = ast_str_alloca(256);
+       struct ast_str *read_transpath = ast_str_alloca(256);
+       struct ast_party_id effective_connected_id;
+       struct ast_callid *callid;
 
        /* no snapshots for dummy channels */
        if (!ast_channel_tech(chan)) {
@@ -140,6 +150,7 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
        }
 
        ast_string_field_set(snapshot, name, ast_channel_name(chan));
+       ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
        ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
        ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
        ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
@@ -180,16 +191,42 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
                S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
        ast_string_field_set(snapshot, language, ast_channel_language(chan));
 
+       if ((bridge = ast_channel_get_bridge(chan))) {
+               ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
+       }
+
+       ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats),
+               ast_channel_nativeformats(chan)));
+       ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan)));
+       ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan)));
+       ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath));
+       ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath));
+
+       effective_connected_id = ast_channel_connected_effective_id(chan);
+       ast_string_field_set(snapshot, effective_name,
+               S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, ""));
+       ast_string_field_set(snapshot, effective_number,
+               S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, ""));
+
+       if ((callid = ast_channel_callid(chan))) {
+               ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid);
+               ast_callid_unref(callid);
+       }
+
        snapshot->creationtime = ast_channel_creationtime(chan);
+       snapshot->hanguptime = *(ast_channel_whentohangup(chan));
        snapshot->state = ast_channel_state(chan);
        snapshot->priority = ast_channel_priority(chan);
        snapshot->amaflags = ast_channel_amaflags(chan);
        snapshot->hangupcause = ast_channel_hangupcause(chan);
        ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
        snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
+       snapshot->callgroup = ast_channel_callgroup(chan);
+       snapshot->pickupgroup = ast_channel_pickupgroup(chan);
        ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
 
        snapshot->manager_vars = ast_channel_get_manager_vars(chan);
+       snapshot->channel_vars = ast_channel_get_vars(chan);
 
        ao2_ref(snapshot, +1);
        return snapshot;
index eff753e..1e22ff9 100644 (file)
@@ -2753,16 +2753,18 @@ static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, cons
 
 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
 {
-       struct ast_channel *c;
        if (argc == 2) {
                /* no argument: supply info on the current channel */
                ast_agi_send(agi->fd, chan, "200 result=%d\n", ast_channel_state(chan));
                return RESULT_SUCCESS;
        } else if (argc == 3) {
+               RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
                /* one argument: look for info on the specified channel */
-               if ((c = ast_channel_get_by_name(argv[2]))) {
-                       ast_agi_send(agi->fd, chan, "200 result=%d\n", ast_channel_state(c));
-                       c = ast_channel_unref(c);
+               if ((msg = stasis_cache_get(ast_channel_topic_all_cached_by_name(), ast_channel_snapshot_type(), argv[2]))) {
+                       struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+
+                       ast_agi_send(agi->fd, chan, "200 result=%d\n", snapshot->state);
                        return RESULT_SUCCESS;
                }
                /* if we get this far no channel name matched the argument given */