Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio...
[asterisk/asterisk.git] / res / res_clioriginate.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005 - 2006, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \author Russell Bryant <russell@digium.com>
22  *
23  * \brief Originate calls via the CLI
24  *
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
30
31 #include "asterisk/channel.h"
32 #include "asterisk/pbx.h"
33 #include "asterisk/module.h"
34 #include "asterisk/cli.h"
35 #include "asterisk/utils.h"
36 #include "asterisk/frame.h"
37
38 /*! The timeout for originated calls, in seconds */
39 #define TIMEOUT 30
40
41 /*!
42  * \brief orginate a call from the CLI
43  * \param fd file descriptor for cli
44  * \param chan channel to create type/data
45  * \param app application you want to run
46  * \param appdata data for application
47  * \retval CLI_SUCCESS on success.
48  * \retval CLI_SHOWUSAGE on failure.
49 */
50 static char *orig_app(int fd, const char *chan, const char *app, const char *appdata)
51 {
52         char *chantech;
53         char *chandata;
54         int reason = 0;
55         struct ast_format_cap *cap;
56         struct ast_format tmpfmt;
57
58         if (ast_strlen_zero(app))
59                 return CLI_SHOWUSAGE;
60
61         chandata = ast_strdupa(chan);
62
63         chantech = strsep(&chandata, "/");
64         if (!chandata) {
65                 ast_cli(fd, "*** No data provided after channel type! ***\n");
66                 return CLI_SHOWUSAGE;
67         }
68
69         if (!(cap = ast_format_cap_alloc_nolock())) {
70                 return CLI_FAILURE;
71         }
72         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
73         ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL);
74         cap = ast_format_cap_destroy(cap);
75
76         return CLI_SUCCESS;
77 }
78
79 /*!
80  * \brief orginate from extension
81  * \param fd file descriptor for cli
82  * \param chan channel to create type/data
83  * \param data contains exten\@context
84  * \retval CLI_SUCCESS on success.
85  * \retval CLI_SHOWUSAGE on failure.
86 */
87 static char *orig_exten(int fd, const char *chan, const char *data)
88 {
89         char *chantech;
90         char *chandata;
91         char *exten = NULL;
92         char *context = NULL;
93         int reason = 0;
94         struct ast_format_cap *cap;
95         struct ast_format tmpfmt;
96
97         chandata = ast_strdupa(chan);
98
99         chantech = strsep(&chandata, "/");
100         if (!chandata) {
101                 ast_cli(fd, "*** No data provided after channel type! ***\n");
102                 return CLI_SHOWUSAGE;
103         }
104
105         if (!ast_strlen_zero(data)) {
106                 context = ast_strdupa(data);
107                 exten = strsep(&context, "@");
108         }
109
110         if (ast_strlen_zero(exten))
111                 exten = "s";
112         if (ast_strlen_zero(context))
113                 context = "default";
114         if (!(cap = ast_format_cap_alloc_nolock())) {
115                 return CLI_FAILURE;
116         }
117         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
118         ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL);
119         cap = ast_format_cap_destroy(cap);
120
121         return CLI_SUCCESS;
122 }
123
124 /*!
125  * \brief handle for orgination app or exten.
126  * \param e pointer to the CLI structure to initialize
127  * \param cmd operation to execute
128  * \param a structure that contains either application or extension arguments
129  * \retval CLI_SUCCESS on success.
130  * \retval CLI_SHOWUSAGE on failure.*/
131 static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
132 {
133         static const char * const choices[] = { "application", "extension", NULL };
134         char *res = NULL;
135         switch (cmd) {
136         case CLI_INIT:
137                 e->command = "channel originate";
138                 e->usage =
139                         "  There are two ways to use this command. A call can be originated between a\n"
140                         "channel and a specific application, or between a channel and an extension in\n"
141                         "the dialplan. This is similar to call files or the manager originate action.\n"
142                         "Calls originated with this command are given a timeout of 30 seconds.\n\n"
143
144                         "Usage1: channel originate <tech/data> application <appname> [appdata]\n"
145                         "  This will originate a call between the specified channel tech/data and the\n"
146                         "given application. Arguments to the application are optional. If the given\n"
147                         "arguments to the application include spaces, all of the arguments to the\n"
148                         "application need to be placed in quotation marks.\n\n"
149
150                         "Usage2: channel originate <tech/data> extension [exten@][context]\n"
151                         "  This will originate a call between the specified channel tech/data and the\n"
152                         "given extension. If no context is specified, the 'default' context will be\n"
153                         "used. If no extension is given, the 's' extension will be used.\n";
154                 return NULL;
155         case CLI_GENERATE:
156                 /* ugly, can be removed when CLI entries have ast_module pointers */
157                 ast_module_ref(ast_module_info->self);
158                 if (a->pos == 3) {
159                         res = ast_cli_complete(a->word, choices, a->n);
160                 } else if (a->pos == 4) {
161                         if (!strcasecmp("application", a->argv[3])) {
162                                 res = ast_complete_applications(a->line, a->word, a->n);
163                         }
164                 }
165                 ast_module_unref(ast_module_info->self);
166                 return res;
167         }
168
169         if (ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3]))
170                 return CLI_SHOWUSAGE;
171
172         /* ugly, can be removed when CLI entries have ast_module pointers */
173         ast_module_ref(ast_module_info->self);
174
175         if (!strcasecmp("application", a->argv[3])) {
176                 res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);
177         } else if (!strcasecmp("extension", a->argv[3])) {
178                 res = orig_exten(a->fd, a->argv[2], a->argv[4]);
179         } else {
180                 ast_log(LOG_WARNING, "else");
181                 res = CLI_SHOWUSAGE;
182         }
183
184         ast_module_unref(ast_module_info->self);
185
186         return res;
187 }
188
189 static char *handle_redirect(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
190 {
191         const char *name, *dest;
192         struct ast_channel *chan;
193         int res;
194
195         switch (cmd) {
196         case CLI_INIT:
197                 e->command = "channel redirect";
198                 e->usage = ""
199                 "Usage: channel redirect <channel> <[[context,]exten,]priority>\n"
200                 "    Redirect an active channel to a specified extension.\n";
201                 /*! \todo It would be nice to be able to redirect 2 channels at the same
202                  *  time like you can with AMI redirect.  However, it is not possible to acquire
203                  *  two channels without the potential for a deadlock with how ast_channel structs
204                  *  are managed today.  Once ast_channel is a refcounted object, this command
205                  *  will be able to support that. */
206                 return NULL;
207         case CLI_GENERATE:
208                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
209         }
210
211         if (a->argc != e->args + 2) {
212                 return CLI_SHOWUSAGE;
213         }
214
215         name = a->argv[2];
216         dest = a->argv[3];
217
218         if (!(chan = ast_channel_get_by_name(name))) {
219                 ast_cli(a->fd, "Channel '%s' not found\n", name);
220                 return CLI_FAILURE;
221         }
222
223         res = ast_async_parseable_goto(chan, dest);
224
225         chan = ast_channel_unref(chan);
226
227         if (!res) {
228                 ast_cli(a->fd, "Channel '%s' successfully redirected to %s\n", name, dest);
229         } else {
230                 ast_cli(a->fd, "Channel '%s' failed to be redirected to %s\n", name, dest);
231         }
232
233         return res ? CLI_FAILURE : CLI_SUCCESS;
234 }
235
236 static struct ast_cli_entry cli_cliorig[] = {
237         AST_CLI_DEFINE(handle_orig, "Originate a call"),
238         AST_CLI_DEFINE(handle_redirect, "Redirect a call"),
239 };
240
241 static int unload_module(void)
242 {
243         return ast_cli_unregister_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig));
244 }
245
246 static int load_module(void)
247 {
248         int res;
249         res = ast_cli_register_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig));
250         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
251 }
252
253 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call origination and redirection from the CLI");