435fc6048345fe0f3b95e13676821a89fa4cf25e
[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_parseable_goto(chan, args.return_context);
126
127         ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n", chan->context, chan->exten, chan->priority, chan->cid.cid_num);
128                 if (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
129                 ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
130                 }
131
132         /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
133         before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
134
135         res = ast_masq_park_call(chan, NULL, timeout, &lot);
136         if (res == -1)
137                 return res;
138
139         ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, args.return_context);
140
141         /* Now place the call to the extension */
142
143         snprintf(buf, sizeof(buf), "%d", lot);
144         oh.parent_channel = chan;
145         oh.vars = ast_variable_new("_PARKEDAT", buf, "");
146         dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, args.dial, 30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
147
148         if (dchan) {
149                 if (dchan->_state == AST_STATE_UP) {
150                         ast_verb(4, "Channel %s was answered.\n", dchan->name);
151                 } else {
152                         ast_verb(4, "Channel %s was never answered.\n", dchan->name);
153                         ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
154                         ast_hangup(dchan);
155                         return -1;
156                 }
157         } else {
158                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
159                 return -1; 
160         }
161
162         ast_stopstream(dchan);
163
164         /* now we have the call placed and are ready to play stuff to it */
165
166         ast_verb(4, "Announce Template:%s\n", args.template);
167
168         for (looptemp = 0; looptemp < ARRAY_LEN(tmp); looptemp++) {
169                 if ((tmp[looptemp] = strsep(&args.template, ":")) != NULL)
170                         continue;
171                 else
172                         break;
173         }
174
175         for (i = 0; i < looptemp; i++) {
176                 ast_verb(4, "Announce:%s\n", tmp[i]);
177                 if (!strcmp(tmp[i], "PARKED")) {
178                         ast_say_digits(dchan, lot, "", dchan->language);
179                 } else {
180                         dres = ast_streamfile(dchan, tmp[i], dchan->language);
181                         if (!dres) {
182                                 dres = ast_waitstream(dchan, "");
183                         } else {
184                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
185                                 dres = 0;
186                         }
187                 }
188         }
189
190         ast_stopstream(dchan);  
191         ast_hangup(dchan);
192         
193         return res;
194 }
195
196 static int unload_module(void)
197 {
198         return ast_unregister_application(app);
199 }
200
201 static int load_module(void)
202 {
203         /* return ast_register_application(app, park_exec); */
204         return ast_register_application_xml(app, parkandannounce_exec);
205 }
206
207 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");