Clear the autoloop flag when parsing and setting the context/extension/priority to...
[asterisk/asterisk.git] / apps / app_parkandannounce.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * Author: Ben Miller <bgmiller@dccinc.com>
9  *    With TONS of help from Mark!
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief ParkAndAnnounce application for Asterisk
25  *
26  * \author Ben Miller <bgmiller@dccinc.com>
27  * \arg With TONS of help from Mark!
28  *
29  * \ingroup applications
30  */
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/file.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/features.h"
41 #include "asterisk/say.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/app.h"
45
46 /*** DOCUMENTATION
47         <application name="ParkAndAnnounce" language="en_US">
48                 <synopsis>
49                         Park and Announce.
50                 </synopsis>
51                 <syntax>
52                         <parameter name="announce_template" required="true" argsep=":">
53                                 <argument name="announce" required="true">
54                                         <para>Colon-separated list of files to announce. The word
55                                         <literal>PARKED</literal> will be replaced by a say_digits of the extension in which
56                                         the call is parked.</para>
57                                 </argument>
58                                 <argument name="announce1" multiple="true" />
59                         </parameter>
60                         <parameter name="timeout" required="true">
61                                 <para>Time in seconds before the call returns into the return
62                                 context.</para>
63                         </parameter>
64                         <parameter name="dial" required="true">
65                                 <para>The app_dial style resource to call to make the
66                                 announcement. Console/dsp calls the console.</para>
67                         </parameter>
68                         <parameter name="return_context">
69                                 <para>The goto-style label to jump the call back into after
70                                 timeout. Default <literal>priority+1</literal>.</para>
71                         </parameter>
72                 </syntax>
73                 <description>
74                         <para>Park a call into the parkinglot and announce the call to another channel.</para>
75                         <para>The variable <variable>PARKEDAT</variable> will contain the parking extension
76                         into which the call was placed.  Use with the Local channel to allow the dialplan to make
77                         use of this information.</para>
78                 </description>
79                 <see-also>
80                         <ref type="application">Park</ref>
81                         <ref type="application">ParkedCall</ref>
82                 </see-also>
83         </application>
84  ***/
85
86 static char *app = "ParkAndAnnounce";
87
88 static int parkandannounce_exec(struct ast_channel *chan, void *data)
89 {
90         int res = -1;
91         int lot, timeout = 0, dres;
92         char *dialtech, *tmp[100], buf[13];
93         int looptemp, i;
94         char *s;
95
96         struct ast_channel *dchan;
97         struct outgoing_helper oh = { 0, };
98         int outstate;
99         AST_DECLARE_APP_ARGS(args,
100                 AST_APP_ARG(template);
101                 AST_APP_ARG(timeout);
102                 AST_APP_ARG(dial);
103                 AST_APP_ARG(return_context);
104         );
105         if (ast_strlen_zero(data)) {
106                 ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
107                 return -1;
108         }
109   
110         s = ast_strdupa(data);
111         AST_STANDARD_APP_ARGS(args, s);
112
113         if (args.timeout)
114                 timeout = atoi(args.timeout) * 1000;
115
116         if (ast_strlen_zero(args.dial)) {
117                 ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or DAHDI/g1/5551212\n");
118                 return -1;
119         }
120
121         dialtech = strsep(&args.dial, "/");
122         ast_verb(3, "Dial Tech,String: (%s,%s)\n", dialtech, args.dial);
123
124         if (!ast_strlen_zero(args.return_context)) {
125                 ast_clear_flag(chan, AST_FLAG_IN_AUTOLOOP);
126                 ast_parseable_goto(chan, args.return_context);
127         }
128
129         ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n", chan->context, chan->exten, chan->priority, chan->cid.cid_num);
130                 if (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
131                 ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
132                 }
133
134         /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
135         before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
136
137         res = ast_masq_park_call(chan, NULL, timeout, &lot);
138         if (res == -1)
139                 return res;
140
141         ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, args.return_context);
142
143         /* Now place the call to the extension */
144
145         snprintf(buf, sizeof(buf), "%d", lot);
146         oh.parent_channel = chan;
147         oh.vars = ast_variable_new("_PARKEDAT", buf, "");
148         dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, args.dial, 30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
149
150         if (dchan) {
151                 if (dchan->_state == AST_STATE_UP) {
152                         ast_verb(4, "Channel %s was answered.\n", dchan->name);
153                 } else {
154                         ast_verb(4, "Channel %s was never answered.\n", dchan->name);
155                         ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
156                         ast_hangup(dchan);
157                         return -1;
158                 }
159         } else {
160                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
161                 return -1; 
162         }
163
164         ast_stopstream(dchan);
165
166         /* now we have the call placed and are ready to play stuff to it */
167
168         ast_verb(4, "Announce Template:%s\n", args.template);
169
170         for (looptemp = 0; looptemp < ARRAY_LEN(tmp); looptemp++) {
171                 if ((tmp[looptemp] = strsep(&args.template, ":")) != NULL)
172                         continue;
173                 else
174                         break;
175         }
176
177         for (i = 0; i < looptemp; i++) {
178                 ast_verb(4, "Announce:%s\n", tmp[i]);
179                 if (!strcmp(tmp[i], "PARKED")) {
180                         ast_say_digits(dchan, lot, "", dchan->language);
181                 } else {
182                         dres = ast_streamfile(dchan, tmp[i], dchan->language);
183                         if (!dres) {
184                                 dres = ast_waitstream(dchan, "");
185                         } else {
186                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
187                                 dres = 0;
188                         }
189                 }
190         }
191
192         ast_stopstream(dchan);  
193         ast_hangup(dchan);
194         
195         return res;
196 }
197
198 static int unload_module(void)
199 {
200         return ast_unregister_application(app);
201 }
202
203 static int load_module(void)
204 {
205         /* return ast_register_application(app, park_exec); */
206         return ast_register_application_xml(app, parkandannounce_exec);
207 }
208
209 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");