Remove ASTERISK_REGISTER_FILE.
[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 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 #include "asterisk/channel.h"
34 #include "asterisk/pbx.h"
35 #include "asterisk/module.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/frame.h"
39 #include "asterisk/format_cache.h"
40
41 /*! The timeout for originated calls, in seconds */
42 #define TIMEOUT 30
43
44 /*!
45  * \brief orginate a call from the CLI
46  * \param fd file descriptor for cli
47  * \param chan channel to create type/data
48  * \param app application you want to run
49  * \param appdata data for application
50  * \retval CLI_SUCCESS on success.
51  * \retval CLI_SHOWUSAGE on failure.
52 */
53 static char *orig_app(int fd, const char *chan, const char *app, const char *appdata)
54 {
55         char *chantech;
56         char *chandata;
57         int reason = 0;
58         struct ast_format_cap *cap;
59
60         if (ast_strlen_zero(app))
61                 return CLI_SHOWUSAGE;
62
63         chandata = ast_strdupa(chan);
64
65         chantech = strsep(&chandata, "/");
66         if (!chandata) {
67                 ast_cli(fd, "*** No data provided after channel type! ***\n");
68                 return CLI_SHOWUSAGE;
69         }
70
71         if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
72                 return CLI_FAILURE;
73         }
74         ast_format_cap_append(cap, ast_format_slin, 0);
75         ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL, NULL);
76         ao2_ref(cap, -1);
77
78         return CLI_SUCCESS;
79 }
80
81 /*!
82  * \brief orginate from extension
83  * \param fd file descriptor for cli
84  * \param chan channel to create type/data
85  * \param data contains exten\@context
86  * \retval CLI_SUCCESS on success.
87  * \retval CLI_SHOWUSAGE on failure.
88 */
89 static char *orig_exten(int fd, const char *chan, const char *data)
90 {
91         char *chantech;
92         char *chandata;
93         char *exten = NULL;
94         char *context = NULL;
95         int reason = 0;
96         struct ast_format_cap *cap;
97
98         chandata = ast_strdupa(chan);
99
100         chantech = strsep(&chandata, "/");
101         if (!chandata) {
102                 ast_cli(fd, "*** No data provided after channel type! ***\n");
103                 return CLI_SHOWUSAGE;
104         }
105
106         if (!ast_strlen_zero(data)) {
107                 context = ast_strdupa(data);
108                 exten = strsep(&context, "@");
109         }
110
111         if (ast_strlen_zero(exten))
112                 exten = "s";
113         if (ast_strlen_zero(context))
114                 context = "default";
115         if (!(cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
116                 return CLI_FAILURE;
117         }
118         ast_format_cap_append(cap, ast_format_slin, 0);
119         ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL);
120         ao2_ref(cap, -1);
121
122         return CLI_SUCCESS;
123 }
124
125 /*!
126  * \brief handle for orgination app or exten.
127  * \param e pointer to the CLI structure to initialize
128  * \param cmd operation to execute
129  * \param a structure that contains either application or extension arguments
130  * \retval CLI_SUCCESS on success.
131  * \retval CLI_SHOWUSAGE on failure.*/
132 static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
133 {
134         static const char * const choices[] = { "application", "extension", NULL };
135         char *res = NULL;
136         switch (cmd) {
137         case CLI_INIT:
138                 e->command = "channel originate";
139                 e->usage =
140                         "  There are two ways to use this command. A call can be originated between a\n"
141                         "channel and a specific application, or between a channel and an extension in\n"
142                         "the dialplan. This is similar to call files or the manager originate action.\n"
143                         "Calls originated with this command are given a timeout of 30 seconds.\n\n"
144
145                         "Usage1: channel originate <tech/data> application <appname> [appdata]\n"
146                         "  This will originate a call between the specified channel tech/data and the\n"
147                         "given application. Arguments to the application are optional. If the given\n"
148                         "arguments to the application include spaces, all of the arguments to the\n"
149                         "application need to be placed in quotation marks.\n\n"
150
151                         "Usage2: channel originate <tech/data> extension [exten@][context]\n"
152                         "  This will originate a call between the specified channel tech/data and the\n"
153                         "given extension. If no context is specified, the 'default' context will be\n"
154                         "used. If no extension is given, the 's' extension will be used.\n";
155                 return NULL;
156         case CLI_GENERATE:
157                 if (a->pos == 3) {
158                         res = ast_cli_complete(a->word, choices, a->n);
159                 } else if (a->pos == 4) {
160                         if (!strcasecmp("application", a->argv[3])) {
161                                 res = ast_complete_applications(a->line, a->word, a->n);
162                         }
163                 }
164                 return res;
165         }
166
167         if (ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3]))
168                 return CLI_SHOWUSAGE;
169
170         if (!strcasecmp("application", a->argv[3])) {
171                 res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);
172         } else if (!strcasecmp("extension", a->argv[3])) {
173                 res = orig_exten(a->fd, a->argv[2], a->argv[4]);
174         } else {
175                 res = CLI_SHOWUSAGE;
176         }
177
178         return res;
179 }
180
181 static char *handle_redirect(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
182 {
183         const char *name, *dest;
184         struct ast_channel *chan;
185         int res;
186
187         switch (cmd) {
188         case CLI_INIT:
189                 e->command = "channel redirect";
190                 e->usage = ""
191                 "Usage: channel redirect <channel> <[[context,]exten,]priority>\n"
192                 "    Redirect an active channel to a specified extension.\n";
193                 /*! \todo It would be nice to be able to redirect 2 channels at the same
194                  *  time like you can with AMI redirect.  However, it is not possible to acquire
195                  *  two channels without the potential for a deadlock with how ast_channel structs
196                  *  are managed today.  Once ast_channel is a refcounted object, this command
197                  *  will be able to support that. */
198                 return NULL;
199         case CLI_GENERATE:
200                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
201         }
202
203         if (a->argc != e->args + 2) {
204                 return CLI_SHOWUSAGE;
205         }
206
207         name = a->argv[2];
208         dest = a->argv[3];
209
210         if (!(chan = ast_channel_get_by_name(name))) {
211                 ast_cli(a->fd, "Channel '%s' not found\n", name);
212                 return CLI_FAILURE;
213         }
214
215         res = ast_async_parseable_goto(chan, dest);
216
217         chan = ast_channel_unref(chan);
218
219         if (!res) {
220                 ast_cli(a->fd, "Channel '%s' successfully redirected to %s\n", name, dest);
221         } else {
222                 ast_cli(a->fd, "Channel '%s' failed to be redirected to %s\n", name, dest);
223         }
224
225         return res ? CLI_FAILURE : CLI_SUCCESS;
226 }
227
228 static struct ast_cli_entry cli_cliorig[] = {
229         AST_CLI_DEFINE(handle_orig, "Originate a call"),
230         AST_CLI_DEFINE(handle_redirect, "Redirect a call"),
231 };
232
233 static int unload_module(void)
234 {
235         return ast_cli_unregister_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig));
236 }
237
238 static int load_module(void)
239 {
240         int res;
241         res = ast_cli_register_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig));
242         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
243 }
244
245 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call origination and redirection from the CLI");