Applications no longer need to call ast_module_user_add and ast_module_user_remove...
[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 <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41
42 #include "asterisk/file.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/module.h"
47 #include "asterisk/features.h"
48 #include "asterisk/options.h"
49 #include "asterisk/logger.h"
50 #include "asterisk/say.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/utils.h"
53
54 static char *app = "ParkAndAnnounce";
55
56 static char *synopsis = "Park and Announce";
57
58 static char *descrip =
59 "  ParkAndAnnounce(announce:template|timeout|dial|[return_context]):\n"
60 "Park a call into the parkinglot and announce the call to another channel.\n"
61 "\n"
62 "announce template: Colon-separated list of files to announce.  The word PARKED\n"
63 "                   will be replaced by a say_digits of the extension in which\n"
64 "                   the call is parked.\n"
65 "timeout:           Time in seconds before the call returns into the return\n"
66 "                   context.\n"
67 "dial:              The app_dial style resource to call to make the\n"
68 "                   announcement.  Console/dsp calls the console.\n"
69 "return_context:    The goto-style label to jump the call back into after\n"
70 "                   timeout.  Default <priority+1>.\n"
71 "\n"
72 "The variable ${PARKEDAT} will contain the parking extension into which the\n"
73 "call was placed.  Use with the Local channel to allow the dialplan to make\n"
74 "use of this information.\n";
75
76
77 static int parkandannounce_exec(struct ast_channel *chan, void *data)
78 {
79         int res=0;
80         char *return_context;
81         int lot, timeout = 0, dres;
82         char *working, *context, *exten, *priority, *dial, *dialtech, *dialstr;
83         char *template, *tpl_working, *tpl_current;
84         char *tmp[100];
85         char buf[13];
86         int looptemp=0,i=0;
87         char *s;
88
89         struct ast_channel *dchan;
90         struct outgoing_helper oh;
91         int outstate;
92
93         if (ast_strlen_zero(data)) {
94                 ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
95                 return -1;
96         }
97   
98         s = ast_strdupa(data);
99
100         template=strsep(&s,"|");
101         if(! template) {
102                 ast_log(LOG_WARNING, "PARK: An announce template must be defined\n");
103                 return -1;
104         }
105   
106         if(s) {
107                 timeout = atoi(strsep(&s, "|"));
108                 timeout *= 1000;
109         }
110         dial=strsep(&s, "|");
111         if(!dial) {
112                 ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or Zap/g1/5551212\n");
113                 return -1;
114         } else {
115                 dialtech=strsep(&dial, "/");
116                 dialstr=dial;
117                 ast_verbose( VERBOSE_PREFIX_3 "Dial Tech,String: (%s,%s)\n", dialtech,dialstr);
118         }
119
120         return_context = s;
121   
122         if(return_context != NULL) {
123                 /* set the return context. Code borrowed from the Goto builtin */
124     
125                 working = return_context;
126                 context = strsep(&working, "|");
127                 exten = strsep(&working, "|");
128                 if(!exten) {
129                         /* Only a priority in this one */
130                         priority = context;
131                         exten = NULL;
132                         context = NULL;
133                 } else {
134                         priority = strsep(&working, "|");
135                         if(!priority) {
136                                 /* Only an extension and priority in this one */
137                                 priority = exten;
138                                 exten = context;
139                                 context = NULL;
140                 }
141         }
142         if(atoi(priority) < 0) {
143                 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
144                 return -1;
145         }
146         /* At this point we have a priority and maybe an extension and a context */
147         chan->priority = atoi(priority);
148         if (exten)
149                 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
150         if (context)
151                 ast_copy_string(chan->context, context, sizeof(chan->context));
152         } else {  /* increment the priority by default*/
153                 chan->priority++;
154         }
155
156         if(option_verbose > 2) {
157                 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
158                 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
159                         ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
160                 }
161         }
162   
163         /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
164         before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
165
166         ast_masq_park_call(chan, NULL, timeout, &lot);
167
168         res=-1; 
169
170         ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
171
172         /* Now place the call to the extention */
173
174         snprintf(buf, sizeof(buf), "%d", lot);
175         memset(&oh, 0, sizeof(oh));
176         oh.parent_channel = chan;
177         oh.vars = ast_variable_new("_PARKEDAT", buf);
178         dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
179
180         if(dchan) {
181                 if(dchan->_state == AST_STATE_UP) {
182                         if(option_verbose > 3)
183                                 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", dchan->name);
184                 } else {
185                         if(option_verbose > 3)
186                                 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", dchan->name);
187                                 ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
188                         ast_hangup(dchan);
189                         return -1;
190                 }
191         } else {
192                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
193                 return -1; 
194         }
195
196         ast_stopstream(dchan);
197
198         /* now we have the call placed and are ready to play stuff to it */
199
200         ast_verbose(VERBOSE_PREFIX_4 "Announce Template:%s\n", template);
201
202         tpl_working = template;
203         tpl_current=strsep(&tpl_working, ":");
204
205         while(tpl_current && looptemp < sizeof(tmp)) {
206                 tmp[looptemp]=tpl_current;
207                 looptemp++;
208                 tpl_current=strsep(&tpl_working,":");
209         }
210
211         for(i=0; i<looptemp; i++) {
212                 ast_verbose(VERBOSE_PREFIX_4 "Announce:%s\n", tmp[i]);
213                 if(!strcmp(tmp[i], "PARKED")) {
214                         ast_say_digits(dchan, lot, "", dchan->language);
215                 } else {
216                         dres = ast_streamfile(dchan, tmp[i], dchan->language);
217                         if(!dres) {
218                                 dres = ast_waitstream(dchan, "");
219                         } else {
220                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
221                                 dres = 0;
222                         }
223                 }
224         }
225
226         ast_stopstream(dchan);  
227         ast_hangup(dchan);
228         
229         return res;
230 }
231
232 static int unload_module(void)
233 {
234         return ast_unregister_application(app);
235 }
236
237 static int load_module(void)
238 {
239         /* return ast_register_application(app, park_exec); */
240         return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
241 }
242
243 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");