Merge "Revert "AGI: Only defer frames when in an interception routine.""
[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 #include "asterisk/file.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/module.h"
45 #include "asterisk/app.h"
46 #include "asterisk/format_cache.h"
47
48 static const char app_originate[] = "Originate";
49
50 /*** DOCUMENTATION
51         <application name="Originate" language="en_US">
52                 <synopsis>
53                         Originate a call.
54                 </synopsis>
55                 <syntax>
56                         <parameter name="tech_data" required="true">
57                                 <para>Channel technology and data for creating the outbound channel.
58                       For example, SIP/1234.</para>
59                         </parameter>
60                         <parameter name="type" required="true">
61                                 <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>
62                         </parameter>
63                         <parameter name="arg1" required="true">
64                                 <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>
65                         </parameter>
66                         <parameter name="arg2" required="false">
67                                 <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>
68                         </parameter>
69                         <parameter name="arg3" required="false">
70                                 <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>
71                         </parameter>
72                         <parameter name="timeout" required="false">
73                                 <para>Timeout in seconds. Default is 30 seconds.</para>
74                         </parameter>
75                 </syntax>
76                 <description>
77                 <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>
78
79                 <para>This application sets the following channel variable before exiting:</para>
80                 <variablelist>
81                         <variable name="ORIGINATE_STATUS">
82                                 <para>This indicates the result of the call origination.</para>
83                                 <value name="FAILED"/>
84                                 <value name="SUCCESS"/>
85                                 <value name="BUSY"/>
86                                 <value name="CONGESTION"/>
87                                 <value name="HANGUP"/>
88                                 <value name="RINGING"/>
89                                 <value name="UNKNOWN">
90                                 In practice, you should never see this value.  Please report it to the issue tracker if you ever see it.
91                                 </value>
92                         </variable>
93                 </variablelist>
94                 </description>
95         </application>
96  ***/
97
98 static int originate_exec(struct ast_channel *chan, const char *data)
99 {
100         AST_DECLARE_APP_ARGS(args,
101                 AST_APP_ARG(tech_data);
102                 AST_APP_ARG(type);
103                 AST_APP_ARG(arg1);
104                 AST_APP_ARG(arg2);
105                 AST_APP_ARG(arg3);
106                 AST_APP_ARG(timeout);
107         );
108         char *parse;
109         char *chantech, *chandata;
110         int res = -1;
111         int outgoing_status = 0;
112         unsigned int timeout = 30;
113         static const char default_exten[] = "s";
114         struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
115
116         ast_autoservice_start(chan);
117         if (!cap_slin) {
118                 goto return_cleanup;
119         }
120
121         ast_format_cap_append(cap_slin, ast_format_slin, 0);
122         ast_format_cap_append(cap_slin, ast_format_slin12, 0);
123         ast_format_cap_append(cap_slin, ast_format_slin16, 0);
124         ast_format_cap_append(cap_slin, ast_format_slin24, 0);
125         ast_format_cap_append(cap_slin, ast_format_slin32, 0);
126         ast_format_cap_append(cap_slin, ast_format_slin44, 0);
127         ast_format_cap_append(cap_slin, ast_format_slin48, 0);
128         ast_format_cap_append(cap_slin, ast_format_slin96, 0);
129         ast_format_cap_append(cap_slin, ast_format_slin192, 0);
130
131         if (ast_strlen_zero(data)) {
132                 ast_log(LOG_ERROR, "Originate() requires arguments\n");
133                 goto return_cleanup;
134         }
135
136         parse = ast_strdupa(data);
137
138         AST_STANDARD_APP_ARGS(args, parse);
139
140         if (args.argc < 3) {
141                 ast_log(LOG_ERROR, "Incorrect number of arguments\n");
142                 goto return_cleanup;
143         }
144
145         if (!ast_strlen_zero(args.timeout)) {
146                 if(sscanf(args.timeout, "%u", &timeout) != 1) {
147                         ast_log(LOG_NOTICE, "Invalid timeout: '%s'. Setting timeout to 30 seconds\n", args.timeout);
148                         timeout = 30;
149                 }
150         }
151
152         chandata = ast_strdupa(args.tech_data);
153         chantech = strsep(&chandata, "/");
154
155         if (ast_strlen_zero(chandata) || ast_strlen_zero(chantech)) {
156                 ast_log(LOG_ERROR, "Channel Tech/Data invalid: '%s'\n", args.tech_data);
157                 goto return_cleanup;
158         }
159
160         if (!strcasecmp(args.type, "exten")) {
161                 int priority = 1; /* Initialized in case priority not specified */
162                 const char *exten = args.arg2;
163
164                 if (args.argc == 5) {
165                         /* Context/Exten/Priority all specified */
166                         if (sscanf(args.arg3, "%30d", &priority) != 1) {
167                                 ast_log(LOG_ERROR, "Invalid priority: '%s'\n", args.arg3);
168                                 goto return_cleanup;
169                         }
170                 } else if (args.argc == 3) {
171                         /* Exten not specified */
172                         exten = default_exten;
173                 }
174
175                 ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
176                                 chantech, chandata, args.arg1, exten, priority);
177
178                 ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
179                                 timeout * 1000, args.arg1, exten, priority, &outgoing_status, 1, NULL,
180                                 NULL, NULL, NULL, NULL, 0, NULL);
181         } else if (!strcasecmp(args.type, "app")) {
182                 ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
183                                 chantech, chandata, args.arg1, S_OR(args.arg2, ""));
184
185                 ast_pbx_outgoing_app(chantech, cap_slin, chandata,
186                                 timeout * 1000, args.arg1, args.arg2, &outgoing_status, 1, NULL,
187                                 NULL, NULL, NULL, NULL, NULL);
188         } else {
189                 ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
190                                 args.type);
191                 goto return_cleanup;
192         }
193
194         res = 0;
195
196 return_cleanup:
197         if (res) {
198                 pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "FAILED");
199         } else {
200                 switch (outgoing_status) {
201                 case 0:
202                 case AST_CONTROL_ANSWER:
203                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "SUCCESS");
204                         break;
205                 case AST_CONTROL_BUSY:
206                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "BUSY");
207                         break;
208                 case AST_CONTROL_CONGESTION:
209                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "CONGESTION");
210                         break;
211                 case AST_CONTROL_HANGUP:
212                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "HANGUP");
213                         break;
214                 case AST_CONTROL_RINGING:
215                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "RINGING");
216                         break;
217                 default:
218                         ast_log(LOG_WARNING, "Unknown originate status result of '%d'\n",
219                                         outgoing_status);
220                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "UNKNOWN");
221                         break;
222                 }
223         }
224         ao2_cleanup(cap_slin);
225         ast_autoservice_stop(chan);
226
227         return res;
228 }
229
230 static int unload_module(void)
231 {
232         return ast_unregister_application(app_originate);
233 }
234
235 static int load_module(void)
236 {
237         int res;
238
239         res = ast_register_application_xml(app_originate, originate_exec);
240
241         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
242 }
243
244 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Originate call");