Fix pbx_wilcalu from occupying 100% CPU now that it's nonblocking, and add malloc...
[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@linux-support.net>
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 <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <pthread.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         fd_set fds;
64         fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
65         printf("Entered Wil-Calu fd=%d\n",fd);
66         if(fd<0) {
67                 printf("Autodial: Unable to open file\n");
68                 pthread_exit(NULL);
69         }
70         memset(buf,0,257);
71         memset(lastbuf,0,257);
72         memset(sendbuf,0,257);
73         while(1){
74                 ssize_t bytes;
75                 void *pass;
76
77                 memset(buf,0,257);
78                 FD_ZERO(&fds);
79                 FD_SET(fd, &fds);
80                 ast_select(fd + 1, &fds, NULL, NULL, NULL);
81                 bytes=read(fd,buf,256);
82                 printf("Bytes: %d\n", bytes);
83                 buf[(int)bytes]=0;
84
85                 if(bytes>0){
86                         int x;
87                         printf("WilCalu : Read Buf %s\n",buf);
88                         sendbufptr=sendbuf;
89                         for(x=0;lastbuf[x]!=0 && x<257;x++);
90                         if(x) {
91                                 memcpy(sendbuf,lastbuf,x);
92                                 sendbufptr+=x;
93                                 memset(lastbuf,0,257);
94                         }
95                         /* Process bytes read */
96                         for(x=0;x<bytes;x++){
97                                 /* if & then string is complete */
98                                 if(buf[x]=='&'){
99                                         if(NULL!=(pass=(void *)strdup(sendbuf))){
100                                                 pthread_create(&dialstring_thread,NULL,dialstring,pass);
101                                                 sendbufptr=sendbuf;
102                                                 memset(sendbuf,0,257);
103                                         }
104                                         else {
105                                                 perror("Autodial:Strdup failed");
106                                                 close(fd);
107                                                 pthread_exit(NULL);
108                                         }
109                                 } else {
110                                         if(buf[x]=='\n')
111                                                 continue;
112                                         *sendbufptr=buf[x];
113                                         sendbufptr++;
114                                         *sendbufptr=0;
115                                 }
116                         }
117                         if(sendbufptr!=sendbuf)
118                                 memcpy(lastbuf,sendbuf,sendbufptr-sendbuf+1);
119                 }
120         }
121         close(fd);
122         pthread_exit(NULL);
123         return NULL;
124 }
125
126 static void *snooze_alarm(void *pass){
127         
128         pthread_t dialstring_thread;
129         struct alarm_data *data=(struct alarm_data *)pass;
130         sleep(data->snooze_len);
131         pthread_create(&dialstring_thread,NULL,dialstring,data->dialstr);
132         // dialstring will free data->dialstr
133         free(pass);
134         pthread_exit(NULL);
135         return NULL;
136 }
137 static void  set_snooze_alarm(char *dialstr,int snooze_len){
138         pthread_t snooze_alarm_thread;
139         struct alarm_data *pass;
140         printf("Answered: Snooze Requested\n");
141         if(NULL==(pass=malloc(sizeof(struct alarm_data)))){
142                 perror("snooze_alarm: data");
143                 pthread_exit(NULL);
144         }
145         if(NULL==(pass->dialstr=(void *)strdup(dialstr))){
146                 free(pass);
147                 perror("snooze_alarm: dialstr");
148                 pthread_exit(NULL);
149         }
150         pass->snooze_len=snooze_len;
151         pthread_create(&snooze_alarm_thread,NULL,snooze_alarm,pass);
152 }
153                         
154 static void *dialstring(void *string){
155         struct ast_channel *channel;
156         char *bufptr,*destptr;
157         // ms affects number of rings
158         int  ms=10000;
159         int  cnt=0,first;
160         char tech[256];
161         char tele[256];
162         char filename[256];
163         int  answered=0;
164         for(first=0,bufptr=(char *)string,destptr=tech;*bufptr&&cnt<256;cnt++){
165                 if(*bufptr=='/' && !first){
166                         *destptr=0;
167                         destptr=tele;
168                         first=1;
169                 }
170                 else if(*bufptr==','){
171                         *destptr=0;
172                         destptr=filename;
173                 } else {
174                         *destptr=*bufptr;
175                         destptr++;
176                 }
177                 bufptr++;
178         } 
179         *destptr=0;
180         printf("Printing string arg: ");
181         printf((char *)string);
182         printf(" Eos\n");
183         if(strlen(tech)+strlen(tele)+strlen(filename)>256){
184                 printf("Autodial:Error string too long\n");
185                 free(string);
186                 pthread_exit(NULL);
187         }
188         printf("Autodial Tech %s(%d) Tele %s(%d) Filename %s(%d)\n",tech,strlen(tech),tele,strlen(tele),filename,strlen(filename));
189
190         channel=ast_request(tech,AST_FORMAT_SLINEAR,tele);
191         if(channel!=NULL){
192                 ast_call(channel,tele,10000);
193         }
194         else {
195                 printf("Autodial:Sorry unable to obtain channel\n");
196                 free(string);
197                 pthread_exit(NULL);
198         }
199         if(channel->_state==AST_STATE_UP)
200                 printf("Autodial:Line is Up\n");
201         while(ms>0){
202                 struct ast_frame *f;
203                 ms=ast_waitfor(channel,ms);
204                 f=ast_read(channel);
205                 if(!f){
206                         printf("Autodial:Hung Up\n");
207                         break;
208                 }
209                 if(f->frametype==AST_FRAME_CONTROL){
210                         if(f->subclass==AST_CONTROL_ANSWER){
211                                 printf("Autodial:Phone Answered\n");
212                                 if(channel->_state==AST_STATE_UP){
213                                         char res;
214                                         ast_streamfile(channel,filename,0);
215                                         // Press Five for snooze
216                                         res=ast_waitstream(channel, "37");
217                                         if(res=='3'){
218                                                 answered=1;
219                                                 set_snooze_alarm((char *)string,60);
220                                                 ast_streamfile(channel,"demo-thanks",0);
221                                                 ast_waitstream(channel, "");
222                                         }
223                                         else if(res=='7'){
224                                                 answered=1;
225                                                 ast_streamfile(channel,"demo-thanks",0);
226                                                 ast_waitstream(channel, "");
227                                         }
228                                         ast_stopstream(channel);
229                                         ms=0;
230                                 }
231                         }
232                         else if(f->subclass==AST_CONTROL_RINGING)
233                                 printf("Autodial:Phone Ringing end\n");
234                 }
235                 ast_frfree(f);
236         }
237         if(!answered)
238                 set_snooze_alarm((char *)string,5);
239         free(string);
240         ast_hangup(channel);
241         printf("Autodial:Hung up channel\n");
242         pthread_exit(NULL);
243         return NULL;
244 }
245 int unload_module(void)
246 {
247         STANDARD_HANGUP_LOCALUSERS;
248         unlink(dialfile);
249         return 0;
250 }
251
252 int load_module(void)
253 {
254         int val;
255         snprintf((char *)dialfile,sizeof(dialfile)-1,"%s/%s",(char *)ast_config_AST_RUN_DIR,"autodial.ctl");
256         if((val=mkfifo(dialfile, 0700))){
257                 if(errno!=EEXIST){
258                         printf("Error:%d Creating Autodial FIFO\n",errno);
259                         return 0;
260                 }
261         }
262         pthread_create(&autodialer_thread,NULL,autodial,NULL);
263         return 0;
264 }
265
266 char *description(void)
267 {
268         return tdesc;
269 }
270
271 int usecount(void)
272 {
273         int res;
274         STANDARD_USECOUNT(res);
275         return res;
276 }
277
278 char *key()
279 {
280         return ASTERISK_GPL_KEY;
281 }