2b92239f4ed2e222a1110b5bf28f63c2e4c6e717
[asterisk/asterisk.git] / pbx / pbx_wilcalu.c
1 /** @file pbx_wilcalu.c 
2  *
3  * Asterisk -- A telephony toolkit for Linux.
4  *
5  * Trivial application to playback a sound file
6  * 
7  * Copyright (C) 1999, Mark Spencer
8  *
9  * Mark Spencer <markster@digium.com>
10  *
11  * This program is free software, distributed under the terms of
12  * the GNU General Public License
13
14  *  Autodialer for Asterisk 
15  *  Redirect dialstring thru fifo "/var/run/autodial.ctl"
16  *  Format of string is :
17  *  "tech/tele,filename&" ie. "tor1/23,file&"
18  */
19  
20 #include <asterisk/lock.h>
21 #include <asterisk/file.h>
22 #include <asterisk/logger.h>
23 #include <asterisk/channel.h>
24 #include <asterisk/pbx.h>
25 #include <asterisk/module.h>
26 #include <asterisk/translate.h>
27 #include <asterisk/options.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34 #include "../astconf.h"
35
36
37 /* Globals */
38 const   char dialfile[255];
39 static  char *tdesc = "Wil Cal U (Auto Dialer)";
40 static  pthread_t autodialer_thread;
41 static  char buf[257];
42 static  char lastbuf[257]; /* contains last partial buffer */
43 static  char sendbuf[257];
44 STANDARD_LOCAL_USER;
45 LOCAL_USER_DECL;
46
47 /* prototype */
48 static void *dialstring(void *string);
49
50 /*  types */
51 struct alarm_data {
52         time_t  alarm_time;
53         int     snooze_len;
54         void    *dialstr;
55 };
56
57 static void *autodial(void *ignore)
58 {
59         pthread_t dialstring_thread;
60         char * sendbufptr=sendbuf;
61         int fd=open(dialfile,O_RDONLY|O_NONBLOCK);
62         int flags = fcntl(fd, F_GETFL);
63         struct pollfd fds[1];
64
65         fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
66         if (option_debug)
67                 ast_log(LOG_DEBUG, "Entered Wil-Calu fd=%d\n",fd);
68         if(fd<0) {
69                 ast_log(LOG_WARNING, "Autodial: Unable to open file\n");
70                 pthread_exit(NULL);
71         }
72         memset(buf,0,257);
73         memset(lastbuf,0,257);
74         memset(sendbuf,0,257);
75         while(1){
76                 ssize_t bytes;
77                 void *pass;
78
79                 memset(buf,0,257);
80                 fds[0].fd = fd;
81                 fds[0].events = POLLIN;
82                 poll(fds, 1, -1);
83                 bytes=read(fd,buf,256);
84                 buf[(int)bytes]=0;
85
86                 if(bytes>0){
87                         int x;
88                         ast_log(LOG_DEBUG, "WilCalu : Read Buf %s\n",buf);
89                         sendbufptr=sendbuf;
90                         for(x=0; lastbuf[x]!=0 && x<257; x++);
91                         if(x) {
92                                 memcpy(sendbuf, lastbuf, x);
93                                 sendbufptr+=x;
94                                 memset(lastbuf, 0, 257);
95                         }
96                         /* Process bytes read */
97                         for(x=0; x<bytes; x++){
98                                 /* if & then string is complete */
99                                 if(buf[x]=='&'){
100                                         if(NULL!=(pass=(void *)strdup(sendbuf))){
101                                                 pthread_create(&dialstring_thread, NULL, dialstring, pass);
102                                                 sendbufptr=sendbuf;
103                                                 memset(sendbuf, 0, 257);
104                                         }
105                                         else {
106                                                 perror("Autodial: Strdup failed");
107                                                 close(fd);
108                                                 pthread_exit(NULL);
109                                         }
110                                 } else {
111                                         if(buf[x]=='\n')
112                                                 continue;
113                                         *sendbufptr=buf[x];
114                                         sendbufptr++;
115                                         *sendbufptr=0;
116                                 }
117                         }
118                         if(sendbufptr!=sendbuf)
119                                 memcpy(lastbuf, sendbuf, sendbufptr-sendbuf+1);
120                 }
121         }
122         close(fd);
123         pthread_exit(NULL);
124         return NULL;
125 }
126
127 static void *snooze_alarm(void *pass)
128 {
129         pthread_t dialstring_thread;
130         struct alarm_data *data = (struct alarm_data *) pass;
131
132         sleep(data->snooze_len);
133         pthread_create(&dialstring_thread, NULL, dialstring, data->dialstr);
134         /* dialstring will free data->dialstr */
135         free(pass);
136         pthread_exit(NULL);
137         return NULL;
138 }
139
140 static void  set_snooze_alarm(char *dialstr, int snooze_len)
141 {
142         pthread_t snooze_alarm_thread;
143         struct alarm_data *pass;
144
145         ast_log(LOG_DEBUG, "Answered: Snooze Requested\n");
146         if (NULL==(pass=malloc(sizeof(struct alarm_data)))){
147                 perror("snooze_alarm: data");
148                 pthread_exit(NULL);
149         }
150         if (NULL==(pass->dialstr=(void *)strdup(dialstr))){
151                 free(pass);
152                 perror("snooze_alarm: dialstr");
153                 pthread_exit(NULL);
154         }
155         pass->snooze_len=snooze_len;
156         pthread_create(&snooze_alarm_thread,NULL,snooze_alarm,pass);
157 }
158                         
159 static void *dialstring(void *string)
160 {
161         struct ast_channel *channel;
162         char *bufptr,*destptr;
163         int  ms=10000;          /* ms affects number of rings */
164         int  cnt=0,first;
165         char tech[256];
166         char tele[256];
167         char filename[256];
168         int  answered=0;
169
170         for(first=0, bufptr=(char *)string, destptr=tech; *bufptr&&cnt<256; cnt++){
171                 if(*bufptr=='/' && !first) {
172                         *destptr=0;
173                         destptr=tele;
174                         first=1;
175                 }
176                 else if(*bufptr==',') {
177                         *destptr=0;
178                         destptr=filename;
179                 } else {
180                         *destptr=*bufptr;
181                         destptr++;
182                 }
183                 bufptr++;
184         } 
185         *destptr=0;
186         ast_log(LOG_DEBUG, "Printing string arg: %s Eos\n", (char *)string);
187         if(strlen(tech)+strlen(tele)+strlen(filename) > 256) {
188                 ast_log(LOG_ERROR, "Autodial:Error string too long\n");
189                 free(string);
190                 pthread_exit(NULL);
191         }
192         ast_log(LOG_DEBUG, "Autodial Tech %s(%d) Tele %s(%d) Filename %s(%d)\n",tech, (int)strlen(tech), tele, (int)strlen(tele), filename, (int)strlen(filename));
193
194         channel=ast_request(tech,AST_FORMAT_SLINEAR,tele);
195         if(channel!=NULL){
196                 ast_call(channel,tele,10000);
197         } else {
198                 ast_log(LOG_ERROR, "Autodial:Sorry unable to obtain channel\n");
199                 free(string);
200                 pthread_exit(NULL);
201         }
202         if(channel->_state==AST_STATE_UP)
203                 ast_log(LOG_DEBUG, "Autodial:Line is Up\n");
204         while(ms>0){
205                 struct ast_frame *f;
206
207                 ms=ast_waitfor(channel,ms);
208                 f=ast_read(channel);
209                 if(!f){
210                         ast_log(LOG_DEBUG, "Autodial:Hung Up\n");
211                         break;
212                 }
213                 if (f->frametype==AST_FRAME_CONTROL) {
214                         if (f->subclass==AST_CONTROL_ANSWER) {
215                                 ast_log(LOG_DEBUG, "Autodial:Phone Answered\n");
216                                 if (channel->_state==AST_STATE_UP) {
217                                         char res;
218
219                                         ast_streamfile(channel,filename,0);
220                                         /* Press Five for snooze */
221                                         res=ast_waitstream(channel, "37");
222                                         if(res=='3'){
223                                                 answered=1;
224                                                 set_snooze_alarm((char *)string,60);
225                                                 ast_streamfile(channel,"demo-thanks",0);
226                                                 ast_waitstream(channel, "");
227                                         }
228                                         else if(res=='7'){
229                                                 answered=1;
230                                                 ast_streamfile(channel,"demo-thanks",0);
231                                                 ast_waitstream(channel, "");
232                                         }
233                                         ast_stopstream(channel);
234                                         ms=0;
235                                 }
236                         }
237                         else if (f->subclass==AST_CONTROL_RINGING)
238                                 ast_log(LOG_DEBUG, "Autodial:Phone Ringing end\n");
239                 }
240                 ast_frfree(f);
241         }
242         if(!answered)
243                 set_snooze_alarm((char *) string, 5);
244         free(string);
245         ast_hangup(channel);
246         ast_log(LOG_DEBUG, "Autodial:Hung up channel\n");
247         pthread_exit(NULL);
248         return NULL;
249 }
250
251 int unload_module(void)
252 {
253         STANDARD_HANGUP_LOCALUSERS;
254         unlink(dialfile);
255         return 0;
256 }
257
258 int load_module(void)
259 {
260         int val;
261
262         snprintf((char *)dialfile, sizeof(dialfile)-1,"%s/%s", (char *)ast_config_AST_RUN_DIR,"autodial.ctl");
263         if((val=mkfifo(dialfile, 0700))) {
264                 if(errno!=EEXIST){
265                         ast_log(LOG_ERROR, "Error:%d Creating Autodial FIFO\n",errno);
266                         return 0;
267                 }
268         }
269         pthread_create(&autodialer_thread, NULL, autodial, NULL);
270         return 0;
271 }
272
273 char *description(void)
274 {
275         return tdesc;
276 }
277
278 int usecount(void)
279 {
280         int res;
281         STANDARD_USECOUNT(res);
282         return res;
283 }
284
285 char *key()
286 {
287         return ASTERISK_GPL_KEY;
288 }