media formats: re-architect handling of media for performance improvements
[asterisk/asterisk.git] / apps / app_originate.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2008, Roberto Casas.
5  * Copyright (C) 2008, Digium, Inc.
6  *
7  * Roberto Casas <roberto.casas@diaple.com>
8  * Russell Bryant <russell@digium.com>
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*!
22  * \file
23  * \brief Originate application
24  *
25  * \author Roberto Casas <roberto.casas@diaple.com>
26  * \author Russell Bryant <russell@digium.com>
27  *
28  * \ingroup applications
29  *
30  * \todo Make a way to be able to set variables (and functions) on the outbound
31  *       channel, similar to the Variable headers for the AMI Originate, and the
32  *       Set options for call files.
33  */
34
35 /*** MODULEINFO
36         <support_level>core</support_level>
37  ***/
38
39 #include "asterisk.h"
40
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
42
43 #include "asterisk/file.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/module.h"
47 #include "asterisk/app.h"
48 #include "asterisk/format_cache.h"
49
50 static const char app_originate[] = "Originate";
51
52 /*** DOCUMENTATION
53         <application name="Originate" language="en_US">
54                 <synopsis>
55                         Originate a call.
56                 </synopsis>
57                 <syntax>
58                         <parameter name="tech_data" required="true">
59                                 <para>Channel technology and data for creating the outbound channel.
60                       For example, SIP/1234.</para>
61                         </parameter>
62                         <parameter name="type" required="true">
63                                 <para>This should be <literal>app</literal> or <literal>exten</literal>, depending on whether the outbound channel should be connected to an application or extension.</para>
64                         </parameter>
65                         <parameter name="arg1" required="true">
66                                 <para>If the type is <literal>app</literal>, then this is the application name.  If the type is <literal>exten</literal>, then this is the context that the channel will be sent to.</para>
67                         </parameter>
68                         <parameter name="arg2" required="false">
69                                 <para>If the type is <literal>app</literal>, then this is the data passed as arguments to the application.  If the type is <literal>exten</literal>, then this is the extension that the channel will be sent to.</para>
70                         </parameter>
71                         <parameter name="arg3" required="false">
72                                 <para>If the type is <literal>exten</literal>, then this is the priority that the channel is sent to.  If the type is <literal>app</literal>, then this parameter is ignored.</para>
73                         </parameter>
74                         <parameter name="timeout" required="false">
75                                 <para>Timeout in seconds. Default is 30 seconds.</para>
76                         </parameter>
77                 </syntax>
78                 <description>
79                 <para>This application originates an outbound call and connects it to a specified extension or application.  This application will block until the outgoing call fails or gets answered.  At that point, this application will exit with the status variable set and dialplan processing will continue.</para>
80
81                 <para>This application sets the following channel variable before exiting:</para>
82                 <variablelist>
83                         <variable name="ORIGINATE_STATUS">
84                                 <para>This indicates the result of the call origination.</para>
85                                 <value name="FAILED"/>
86                                 <value name="SUCCESS"/>
87                                 <value name="BUSY"/>
88                                 <value name="CONGESTION"/>
89                                 <value name="HANGUP"/>
90                                 <value name="RINGING"/>
91                                 <value name="UNKNOWN">
92                                 In practice, you should never see this value.  Please report it to the issue tracker if you ever see it.
93                                 </value>
94                         </variable>
95                 </variablelist>
96                 </description>
97         </application>
98  ***/
99
100 static int originate_exec(struct ast_channel *chan, const char *data)
101 {
102         AST_DECLARE_APP_ARGS(args,
103                 AST_APP_ARG(tech_data);
104                 AST_APP_ARG(type);
105                 AST_APP_ARG(arg1);
106                 AST_APP_ARG(arg2);
107                 AST_APP_ARG(arg3);
108                 AST_APP_ARG(timeout);
109         );
110         char *parse;
111         char *chantech, *chandata;
112         int res = -1;
113         int outgoing_status = 0;
114         unsigned int timeout = 30;
115         static const char default_exten[] = "s";
116         struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
117
118         ast_autoservice_start(chan);
119         if (!cap_slin) {
120                 goto return_cleanup;
121         }
122
123         ast_format_cap_append(cap_slin, ast_format_slin, 0);
124         ast_format_cap_append(cap_slin, ast_format_slin12, 0);
125         ast_format_cap_append(cap_slin, ast_format_slin16, 0);
126         ast_format_cap_append(cap_slin, ast_format_slin24, 0);
127         ast_format_cap_append(cap_slin, ast_format_slin32, 0);
128         ast_format_cap_append(cap_slin, ast_format_slin44, 0);
129         ast_format_cap_append(cap_slin, ast_format_slin48, 0);
130         ast_format_cap_append(cap_slin, ast_format_slin96, 0);
131         ast_format_cap_append(cap_slin, ast_format_slin192, 0);
132
133         if (ast_strlen_zero(data)) {
134                 ast_log(LOG_ERROR, "Originate() requires arguments\n");
135                 goto return_cleanup;
136         }
137
138         parse = ast_strdupa(data);
139
140         AST_STANDARD_APP_ARGS(args, parse);
141
142         if (args.argc < 3) {
143                 ast_log(LOG_ERROR, "Incorrect number of arguments\n");
144                 goto return_cleanup;
145         }
146
147         if (!ast_strlen_zero(args.timeout)) {
148                 if(sscanf(args.timeout, "%u", &timeout) != 1) {
149                         ast_log(LOG_NOTICE, "Invalid timeout: '%s'. Setting timeout to 30 seconds\n", args.timeout);
150                         timeout = 30;
151                 }
152         }
153
154         chandata = ast_strdupa(args.tech_data);
155         chantech = strsep(&chandata, "/");
156
157         if (ast_strlen_zero(chandata) || ast_strlen_zero(chantech)) {
158                 ast_log(LOG_ERROR, "Channel Tech/Data invalid: '%s'\n", args.tech_data);
159                 goto return_cleanup;
160         }
161
162         if (!strcasecmp(args.type, "exten")) {
163                 int priority = 1; /* Initialized in case priority not specified */
164                 const char *exten = args.arg2;
165
166                 if (args.argc == 5) {
167                         /* Context/Exten/Priority all specified */
168                         if (sscanf(args.arg3, "%30d", &priority) != 1) {
169                                 ast_log(LOG_ERROR, "Invalid priority: '%s'\n", args.arg3);
170                                 goto return_cleanup;
171                         }
172                 } else if (args.argc == 3) {
173                         /* Exten not specified */
174                         exten = default_exten;
175                 }
176
177                 ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
178                                 chantech, chandata, args.arg1, exten, priority);
179
180                 ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
181                                 timeout * 1000, args.arg1, exten, priority, &outgoing_status, 1, NULL,
182                                 NULL, NULL, NULL, NULL, 0, NULL);
183         } else if (!strcasecmp(args.type, "app")) {
184                 ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
185                                 chantech, chandata, args.arg1, S_OR(args.arg2, ""));
186
187                 ast_pbx_outgoing_app(chantech, cap_slin, chandata,
188                                 timeout * 1000, args.arg1, args.arg2, &outgoing_status, 1, NULL,
189                                 NULL, NULL, NULL, NULL, NULL);
190         } else {
191                 ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
192                                 args.type);
193                 goto return_cleanup;
194         }
195
196         res = 0;
197
198 return_cleanup:
199         if (res) {
200                 pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "FAILED");
201         } else {
202                 switch (outgoing_status) {
203                 case 0:
204                 case AST_CONTROL_ANSWER:
205                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "SUCCESS");
206                         break;
207                 case AST_CONTROL_BUSY:
208                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "BUSY");
209                         break;
210                 case AST_CONTROL_CONGESTION:
211                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "CONGESTION");
212                         break;
213                 case AST_CONTROL_HANGUP:
214                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "HANGUP");
215                         break;
216                 case AST_CONTROL_RINGING:
217                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "RINGING");
218                         break;
219                 default:
220                         ast_log(LOG_WARNING, "Unknown originate status result of '%d'\n",
221                                         outgoing_status);
222                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "UNKNOWN");
223                         break;
224                 }
225         }
226         ao2_cleanup(cap_slin);
227         ast_autoservice_stop(chan);
228
229         return res;
230 }
231
232 static int unload_module(void)
233 {
234         return ast_unregister_application(app_originate);
235 }
236
237 static int load_module(void)
238 {
239         int res;
240
241         res = ast_register_application_xml(app_originate, originate_exec);
242
243         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
244 }
245
246 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Originate call");