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