Fix stuck channel in ARI through the introduction of synchronous bridge actions.
[asterisk/asterisk.git] / res / res_clioriginate.c
index 3839eba..cd8b5dd 100644 (file)
  * at the top of the source tree.
  */
 
-/*! 
+/*!
  * \file
  * \author Russell Bryant <russell@digium.com>
  *
  * \brief Originate calls via the CLI
- * 
+ *
  */
 
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
@@ -52,19 +56,26 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app
        char *chantech;
        char *chandata;
        int reason = 0;
-       
+       struct ast_format_cap *cap;
+       struct ast_format tmpfmt;
+
        if (ast_strlen_zero(app))
                return CLI_SHOWUSAGE;
 
        chandata = ast_strdupa(chan);
-       
+
        chantech = strsep(&chandata, "/");
        if (!chandata) {
                ast_cli(fd, "*** No data provided after channel type! ***\n");
                return CLI_SHOWUSAGE;
        }
 
-       ast_pbx_outgoing_app(chantech, AST_FORMAT_SLINEAR, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL);
+       if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) {
+               return CLI_FAILURE;
+       }
+       ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+       ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL, NULL);
+       cap = ast_format_cap_destroy(cap);
 
        return CLI_SUCCESS;
 }
@@ -84,9 +95,11 @@ static char *orig_exten(int fd, const char *chan, const char *data)
        char *exten = NULL;
        char *context = NULL;
        int reason = 0;
+       struct ast_format_cap *cap;
+       struct ast_format tmpfmt;
 
        chandata = ast_strdupa(chan);
-       
+
        chantech = strsep(&chandata, "/");
        if (!chandata) {
                ast_cli(fd, "*** No data provided after channel type! ***\n");
@@ -102,8 +115,12 @@ static char *orig_exten(int fd, const char *chan, const char *data)
                exten = "s";
        if (ast_strlen_zero(context))
                context = "default";
-       
-       ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL);
+       if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) {
+               return CLI_FAILURE;
+       }
+       ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
+       ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL);
+       cap = ast_format_cap_destroy(cap);
 
        return CLI_SUCCESS;
 }
@@ -114,16 +131,15 @@ static char *orig_exten(int fd, const char *chan, const char *data)
  * \param cmd operation to execute
  * \param a structure that contains either application or extension arguments
  * \retval CLI_SUCCESS on success.
- * \retval CLI_SHOWUSAGE on failure.
-*/
+ * \retval CLI_SHOWUSAGE on failure.*/
 static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-       static char *choices[] = { "application", "extension", NULL };
-       char *res;
+       static const char * const choices[] = { "application", "extension", NULL };
+       char *res = NULL;
        switch (cmd) {
        case CLI_INIT:
                e->command = "channel originate";
-               e->usage = 
+               e->usage =
                        "  There are two ways to use this command. A call can be originated between a\n"
                        "channel and a specific application, or between a channel and an extension in\n"
                        "the dialplan. This is similar to call files or the manager originate action.\n"
@@ -141,14 +157,16 @@ static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
                        "used. If no extension is given, the 's' extension will be used.\n";
                return NULL;
        case CLI_GENERATE:
-               if (a->pos != 3)
-                       return NULL;
-
                /* ugly, can be removed when CLI entries have ast_module pointers */
                ast_module_ref(ast_module_info->self);
-               res = ast_cli_complete(a->word, choices, a->n);
+               if (a->pos == 3) {
+                       res = ast_cli_complete(a->word, choices, a->n);
+               } else if (a->pos == 4) {
+                       if (!strcasecmp("application", a->argv[3])) {
+                               res = ast_complete_applications(a->line, a->word, a->n);
+                       }
+               }
                ast_module_unref(ast_module_info->self);
-
                return res;
        }
 
@@ -159,11 +177,10 @@ static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
        ast_module_ref(ast_module_info->self);
 
        if (!strcasecmp("application", a->argv[3])) {
-               res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);      
+               res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);
        } else if (!strcasecmp("extension", a->argv[3])) {
                res = orig_exten(a->fd, a->argv[2], a->argv[4]);
        } else {
-               ast_log(LOG_WARNING, "else");
                res = CLI_SHOWUSAGE;
        }
 
@@ -184,6 +201,11 @@ static char *handle_redirect(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                e->usage = ""
                "Usage: channel redirect <channel> <[[context,]exten,]priority>\n"
                "    Redirect an active channel to a specified extension.\n";
+               /*! \todo It would be nice to be able to redirect 2 channels at the same
+                *  time like you can with AMI redirect.  However, it is not possible to acquire
+                *  two channels without the potential for a deadlock with how ast_channel structs
+                *  are managed today.  Once ast_channel is a refcounted object, this command
+                *  will be able to support that. */
                return NULL;
        case CLI_GENERATE:
                return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
@@ -196,15 +218,14 @@ static char *handle_redirect(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
        name = a->argv[2];
        dest = a->argv[3];
 
-       chan = ast_get_channel_by_name_locked(name);
-       if (!chan) {
+       if (!(chan = ast_channel_get_by_name(name))) {
                ast_cli(a->fd, "Channel '%s' not found\n", name);
                return CLI_FAILURE;
        }
 
        res = ast_async_parseable_goto(chan, dest);
 
-       ast_channel_unlock(chan);
+       chan = ast_channel_unref(chan);
 
        if (!res) {
                ast_cli(a->fd, "Channel '%s' successfully redirected to %s\n", name, dest);