Temporarily revert poll changes
[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, 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   }
102   else {
103     dialtech=strsep(&dial, "/");
104     dialstr=dial;
105     ast_verbose( VERBOSE_PREFIX_3 "Dial Tech,String: (%s,%s)\n", dialtech,dialstr);
106   }
107
108   return_context = s;
109   
110   if (return_context != NULL) {
111     /* set the return context. Code borrowed from the Goto builtin */
112     
113     working = return_context;
114     context = strsep(&working, "|");
115     exten = strsep(&working, "|");
116     if (!exten) {
117       /* Only a priority in this one */
118       priority = context;
119       exten = NULL;
120       context = NULL;
121     } else {
122       priority = strsep(&working, "|");
123       if (!priority) {
124         /* Only an extension and priority in this one */
125         priority = exten;
126         exten = context;
127         context = NULL;
128       }
129     }
130     if (atoi(priority) < 0) {
131       ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
132       free(orig_s);
133       return -1;
134     }
135     /* At this point we have a priority and maybe an extension and a context */
136     chan->priority = atoi(priority);
137     if (exten && strcasecmp(exten, "BYEXTENSION"))
138       strncpy(chan->exten, exten, sizeof(chan->exten)-1);
139     if (context)
140       strncpy(chan->context, context, sizeof(chan->context)-1);
141   }
142   else {  /* increment the priority by default*/
143     chan->priority++;
144   }
145
146
147   if (option_verbose > 2) {
148     ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->callerid);
149     if (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
150       ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
151     }
152   }
153   
154   LOCAL_USER_ADD(u);
155
156   /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
157      before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
158
159   ast_masq_park_call(chan, NULL, timeout, &lot);
160
161   res=-1; 
162
163   ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
164
165   /* Now place the call to the extention */
166
167   dchan = ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->callerid);
168
169   if (dchan) {
170     if (dchan->_state == AST_STATE_UP) {
171       if (option_verbose > 3)
172         ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", dchan->name);
173     } else {
174       if (option_verbose > 3)
175         ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", dchan->name);
176         ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
177       ast_hangup(dchan);
178       free(orig_s);
179       LOCAL_USER_REMOVE(u);
180       return -1;
181     }
182   }
183   else {
184     ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
185     free(orig_s);
186     LOCAL_USER_REMOVE(u);
187     return -1; 
188   }
189
190   ast_stopstream(dchan);
191
192   /* now we have the call placed and are ready to play stuff to it */
193
194   ast_verbose(VERBOSE_PREFIX_4 "Announce Template:%s\n", template);
195
196   tpl_working = template;
197   tpl_current=strsep(&tpl_working, ":");
198
199   while ( tpl_current && looptemp < sizeof(tmp)) {
200     tmp[looptemp]=tpl_current;
201     looptemp++;
202     tpl_current=strsep(&tpl_working,":");
203   }
204
205   for(i=0; i<looptemp; i++) {
206     ast_verbose(VERBOSE_PREFIX_4 "Announce:%s\n", tmp[i]);
207     if (!strcmp(tmp[i], "PARKED")) {
208       ast_say_digits(dchan, lot, "", dchan->language);
209     }
210     else {
211       dres = ast_streamfile(dchan, tmp[i], dchan->language);
212       if (!dres)
213         dres = ast_waitstream(dchan, "");
214       else {
215         ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
216         dres = 0;
217       }
218     }
219   }
220
221   ast_stopstream(dchan);  
222   ast_hangup(dchan);
223
224   LOCAL_USER_REMOVE(u);
225   free(orig_s);
226   return res;
227 }
228
229
230
231 int unload_module(void)
232 {
233         STANDARD_HANGUP_LOCALUSERS;
234         return ast_unregister_application(app);
235 }
236
237 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 char *description(void)
244 {
245         return tdesc;
246 }
247
248 int usecount(void)
249 {
250         int res;
251         STANDARD_USECOUNT(res);
252         return res;
253 }
254
255 char *key()
256 {
257         return ASTERISK_GPL_KEY;
258 }