Set ORIGINATE_STATUS instead of OUTGOING_STATUS to match the documentation
[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, void *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
109         ast_autoservice_start(chan);
110
111         if (ast_strlen_zero(data)) {
112                 ast_log(LOG_ERROR, "Originate() requires arguments\n");
113                 goto return_cleanup;
114         }
115
116         parse = ast_strdupa(data);
117
118         AST_STANDARD_APP_ARGS(args, parse);
119
120         if (args.argc < 3) {
121                 ast_log(LOG_ERROR, "Incorrect number of arguments\n");
122                 goto return_cleanup;
123         }
124
125         chandata = ast_strdupa(args.tech_data);
126         chantech = strsep(&chandata, "/");
127
128         if (ast_strlen_zero(chandata) || ast_strlen_zero(chantech)) {
129                 ast_log(LOG_ERROR, "Channel Tech/Data invalid: '%s'\n", args.tech_data);
130                 goto return_cleanup;
131         }
132
133         if (!strcasecmp(args.type, "exten")) {
134                 int priority = 1; /* Initialized in case priority not specified */
135                 const char *exten = args.arg2;
136
137                 if (args.argc == 5) {
138                         /* Context/Exten/Priority all specified */
139                         if (sscanf(args.arg3, "%d", &priority) != 1) {
140                                 ast_log(LOG_ERROR, "Invalid priority: '%s'\n", args.arg3);
141                                 goto return_cleanup;
142                         }
143                 } else if (args.argc == 3) {
144                         /* Exten not specified */
145                         exten = default_exten;
146                 }
147
148                 ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
149                                 chantech, chandata, args.arg1, exten, priority);
150
151                 outgoing_res = ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata,
152                                 timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
153                                 NULL, NULL, NULL, NULL);
154         } else if (!strcasecmp(args.type, "app")) {
155                 ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
156                                 chantech, chandata, args.arg1, S_OR(args.arg2, ""));
157
158                 outgoing_res = ast_pbx_outgoing_app(chantech, AST_FORMAT_SLINEAR, chandata,
159                                 timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
160                                 NULL, NULL, NULL, NULL);
161         } else {
162                 ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
163                                 args.type);
164                 goto return_cleanup;
165         }
166
167         res = 0;
168
169 return_cleanup:
170         if (res) {
171                 pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "FAILED");
172         } else {
173                 switch (outgoing_status) {
174                 case 0:
175                 case AST_CONTROL_ANSWER:
176                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "SUCCESS");
177                         break;
178                 case AST_CONTROL_BUSY:
179                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "BUSY");
180                         break;
181                 case AST_CONTROL_CONGESTION:
182                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "CONGESTION");
183                         break;
184                 case AST_CONTROL_HANGUP:
185                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "HANGUP");
186                         break;
187                 case AST_CONTROL_RINGING:
188                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "RINGING");
189                         break;
190                 default:
191                         ast_log(LOG_WARNING, "Unknown originate status result of '%d'\n",
192                                         outgoing_status);
193                         pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "UNKNOWN");
194                         break;
195                 }
196         }
197
198         ast_autoservice_stop(chan);
199
200         return res;
201 }
202
203 static int unload_module(void)
204 {
205         return ast_unregister_application(app_originate);
206 }
207
208 static int load_module(void)
209 {
210         int res;
211
212         res = ast_register_application_xml(app_originate, originate_exec);
213
214         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
215 }
216
217 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Originate call");