Use find_user for existsmailbox
[asterisk/asterisk.git] / apps / app_parkandannounce.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * ParkAndAnnounce application for Asterisk
5  * Author: Ben Miller <bgmiller@dccinc.com>
6  *    With TONS of help from Mark!
7  * 
8  * Asterisk is Copyrighted as follows
9  * Copyright (C) 1999, Mark Spencer
10  *
11  * Mark Spencer <markster@linux-support.net>
12  *
13  * This program is free software, distributed under the terms of
14  * the GNU General Public License
15  */
16
17 #include <sys/types.h>
18 #include <asterisk/file.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/channel_pvt.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/module.h>
24 #include <asterisk/parking.h>
25 #include <asterisk/options.h>
26 #include <asterisk/logger.h>
27 #include <asterisk/say.h>
28
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include <pthread.h>
35
36 static char *tdesc = "Call Parking and Announce Application";
37
38 static char *app = "ParkAndAnnounce";
39
40 static char *synopsis = "Park and Announce";
41
42 static char *descrip =
43 "  ParkAndAnnounce(announce:template|timeout|dial|[return_context]):\n"
44 "Park a call into the parkinglot and announce the call over the console.\n"
45 "announce template: colon seperated list of files to announce, the word PARKED\n"
46 "                   will be replaced by a say_digits of the ext the call is parked in\n"
47 "timeout: time in seconds before the call returns into the return context.\n"
48 "dial: The app_dial style resource to call to make the announcement. Console/dsp calls the console.\n"
49 "return_context: the goto style label to jump the call back into after timeout. default=prio+1\n";
50
51
52 STANDARD_LOCAL_USER;
53
54 LOCAL_USER_DECL;
55
56 static int parkandannounce_exec(struct ast_channel *chan, void *data)
57 {
58         int res=0;
59         char *return_context;
60         int l, lot, timeout = 0, dres;
61         char *working, *context, *exten, *priority, *dial, *dialtech, *dialstr;
62         char *template, *tpl_working, *tpl_current;
63         char *tmp[100];
64         int looptemp=0,i=0;
65         char *s,*orig_s;
66
67         struct ast_channel *dchan;
68         int outstate;
69
70         struct localuser *u;
71         if(!data || (data && !strlen(data))) {
72                 ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
73                 return -1;
74         }
75   
76         l=strlen(data)+2;
77         orig_s=malloc(l);
78         if(!orig_s) {
79                 ast_log(LOG_WARNING, "Out of memory\n");
80                 return -1;
81         }
82         s=orig_s;
83         strncpy(s,data,l);
84
85         template=strsep(&s,"|");
86         if(! template) {
87                 ast_log(LOG_WARNING, "PARK: An announce template must be defined\n");
88                 free(orig_s);
89                 return -1;
90         }
91   
92         if(s) {
93                 timeout = atoi(strsep(&s, "|"));
94                 timeout *= 1000;
95         }
96         dial=strsep(&s, "|");
97         if(!dial) {
98                 ast_log(LOG_WARNING, "PARK: A dial resouce must be specified i.e: Console/dsp or Zap/g1/5551212\n");
99                 free(orig_s);
100                 return -1;
101         } else {
102                 dialtech=strsep(&dial, "/");
103                 dialstr=dial;
104                 ast_verbose( VERBOSE_PREFIX_3 "Dial Tech,String: (%s,%s)\n", dialtech,dialstr);
105         }
106
107         return_context = s;
108   
109         if(return_context != NULL) {
110                 /* set the return context. Code borrowed from the Goto builtin */
111     
112                 working = return_context;
113                 context = strsep(&working, "|");
114                 exten = strsep(&working, "|");
115                 if(!exten) {
116                         /* Only a priority in this one */
117                         priority = context;
118                         exten = NULL;
119                         context = NULL;
120                 } else {
121                         priority = strsep(&working, "|");
122                         if(!priority) {
123                                 /* Only an extension and priority in this one */
124                                 priority = exten;
125                                 exten = context;
126                                 context = NULL;
127                 }
128         }
129         if(atoi(priority) < 0) {
130                 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
131                 free(orig_s);
132                 return -1;
133         }
134         /* At this point we have a priority and maybe an extension and a context */
135         chan->priority = atoi(priority);
136         if(exten && strcasecmp(exten, "BYEXTENSION"))
137                 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
138         if(context)
139                 strncpy(chan->context, context, sizeof(chan->context)-1);
140         } else {  /* increment the priority by default*/
141                 chan->priority++;
142         }
143
144
145         if(option_verbose > 2) {
146                 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->callerid);
147                 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
148                         ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
149                 }
150         }
151   
152         LOCAL_USER_ADD(u);
153
154         /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
155         before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
156
157         ast_masq_park_call(chan, NULL, timeout, &lot);
158
159         res=-1; 
160
161         ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
162
163         /* Now place the call to the extention */
164
165         dchan = ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->callerid);
166
167         if(dchan) {
168                 if(dchan->_state == AST_STATE_UP) {
169                         if(option_verbose > 3)
170                                 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", dchan->name);
171                 } else {
172                         if(option_verbose > 3)
173                                 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", dchan->name);
174                                 ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
175                         ast_hangup(dchan);
176                         free(orig_s);
177                         LOCAL_USER_REMOVE(u);
178                         return -1;
179                 }
180         } else {
181                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
182                 free(orig_s);
183                 LOCAL_USER_REMOVE(u);
184                 return -1; 
185         }
186
187         ast_stopstream(dchan);
188
189         /* now we have the call placed and are ready to play stuff to it */
190
191         ast_verbose(VERBOSE_PREFIX_4 "Announce Template:%s\n", template);
192
193         tpl_working = template;
194         tpl_current=strsep(&tpl_working, ":");
195
196         while(tpl_current && looptemp < sizeof(tmp)) {
197                 tmp[looptemp]=tpl_current;
198                 looptemp++;
199                 tpl_current=strsep(&tpl_working,":");
200         }
201
202         for(i=0; i<looptemp; i++) {
203                 ast_verbose(VERBOSE_PREFIX_4 "Announce:%s\n", tmp[i]);
204                 if(!strcmp(tmp[i], "PARKED")) {
205                         ast_say_digits(dchan, lot, "", dchan->language);
206                 } else {
207                         dres = ast_streamfile(dchan, tmp[i], dchan->language);
208                         if(!dres) {
209                                 dres = ast_waitstream(dchan, "");
210                         } else {
211                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
212                                 dres = 0;
213                         }
214                 }
215         }
216
217         ast_stopstream(dchan);  
218         ast_hangup(dchan);
219
220         LOCAL_USER_REMOVE(u);
221         free(orig_s);
222         return res;
223 }
224
225
226
227 int unload_module(void)
228 {
229         STANDARD_HANGUP_LOCALUSERS;
230         return ast_unregister_application(app);
231 }
232
233 int load_module(void)
234 {
235         /* return ast_register_application(app, park_exec); */
236         return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
237 }
238
239 char *description(void)
240 {
241         return tdesc;
242 }
243
244 int usecount(void)
245 {
246         int res;
247         STANDARD_USECOUNT(res);
248         return res;
249 }
250
251 char *key()
252 {
253         return ASTERISK_GPL_KEY;
254 }