Use find_user for existsmailbox
[asterisk/asterisk.git] / apps / app_nbscat.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Silly application to play an NBScat file -- uses nbscat8k
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13  
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/frame.h>
19 #include <asterisk/pbx.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <pthread.h>
29 #include <sys/time.h>
30 #include <sys/socket.h>
31
32 #define LOCAL_NBSCAT "/usr/local/bin/nbscat8k"
33 #define NBSCAT "/usr/bin/nbscat8k"
34
35 static char *tdesc = "Silly NBS Stream Application";
36
37 static char *app = "NBScat";
38
39 static char *synopsis = "Play an NBS local stream";
40
41 static char *descrip = 
42 "  NBScat: Executes nbscat to listen to the local NBS stream.\n"
43 "Returns  -1  on\n hangup or 0 otherwise. User can exit by \n"
44 "pressing any key\n.";
45
46 STANDARD_LOCAL_USER;
47
48 LOCAL_USER_DECL;
49
50 static int NBScatplay(int fd)
51 {
52         int res;
53         int x;
54         res = fork();
55         if (res < 0) 
56                 ast_log(LOG_WARNING, "Fork failed\n");
57         if (res)
58                 return res;
59         dup2(fd, STDOUT_FILENO);
60         for (x=0;x<256;x++) {
61                 if (x != STDOUT_FILENO)
62                         close(x);
63         }
64         /* Most commonly installed in /usr/local/bin */
65         execl(NBSCAT, "nbscat8k", "-d", (char *)NULL);
66         execl(LOCAL_NBSCAT, "nbscat8k", "-d", (char *)NULL);
67         ast_log(LOG_WARNING, "Execute of nbscat8k failed\n");
68         return -1;
69 }
70
71 static int timed_read(int fd, void *data, int datalen)
72 {
73         int res;
74         struct pollfd fds[1];
75         fds[0].fd = fd;
76         fds[0].events = POLLIN;
77         res = poll(fds, 1, 2000);
78         if (res < 1) {
79                 ast_log(LOG_NOTICE, "Selected timed out/errored out with %d\n", res);
80                 return -1;
81         }
82         return read(fd, data, datalen);
83         
84 }
85
86 static int NBScat_exec(struct ast_channel *chan, void *data)
87 {
88         int res=0;
89         struct localuser *u;
90         int fds[2];
91         int ms = -1;
92         int pid = -1;
93         int owriteformat;
94         struct timeval now, next;
95         struct ast_frame *f;
96         struct myframe {
97                 struct ast_frame f;
98                 char offset[AST_FRIENDLY_OFFSET];
99                 short frdata[160];
100         } myf;
101         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
102                 ast_log(LOG_WARNING, "Unable to create socketpair\n");
103                 return -1;
104         }
105         LOCAL_USER_ADD(u);
106         ast_stopstream(chan);
107
108         owriteformat = chan->writeformat;
109         res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
110         if (res < 0) {
111                 ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
112                 return -1;
113         }
114         
115         res = NBScatplay(fds[1]);
116         /* Wait 1000 ms first */
117         next = now;
118         next.tv_sec += 1;
119         if (res >= 0) {
120                 pid = res;
121                 /* Order is important -- there's almost always going to be mp3...  we want to prioritize the
122                    user */
123                 for (;;) {
124                         gettimeofday(&now, NULL);
125                         ms = (next.tv_sec - now.tv_sec) * 1000;
126                         ms += (next.tv_usec - now.tv_usec) / 1000;
127 #if 0
128                         printf("ms: %d\n", ms);
129 #endif                  
130                         if (ms <= 0) {
131 #if 0
132                                 {
133                                         static struct timeval last;
134                                         struct timeval tv;
135                                         gettimeofday(&tv, NULL);
136                                         printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
137                                         last = tv;
138                                 }
139 #endif
140                                 res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
141                                 if (res > 0) {
142                                         myf.f.frametype = AST_FRAME_VOICE;
143                                         myf.f.subclass = AST_FORMAT_SLINEAR;
144                                         myf.f.datalen = res;
145                                         myf.f.samples = res / 2;
146                                         myf.f.mallocd = 0;
147                                         myf.f.offset = AST_FRIENDLY_OFFSET;
148                                         myf.f.src = __PRETTY_FUNCTION__;
149                                         myf.f.delivery.tv_sec = 0;
150                                         myf.f.delivery.tv_usec = 0;
151                                         myf.f.data = myf.frdata;
152                                         if (ast_write(chan, &myf.f) < 0) {
153                                                 res = -1;
154                                                 break;
155                                         }
156                                 } else {
157                                         ast_log(LOG_DEBUG, "No more mp3\n");
158                                         res = 0;
159                                         break;
160                                 }
161                                 next.tv_usec += res / 2 * 125;
162                                 if (next.tv_usec >= 1000000) {
163                                         next.tv_usec -= 1000000;
164                                         next.tv_sec++;
165                                 }
166 #if 0
167                                 printf("Next: %d\n", ms);
168 #endif                          
169                         } else {
170                                 ms = ast_waitfor(chan, ms);
171                                 if (ms < 0) {
172                                         ast_log(LOG_DEBUG, "Hangup detected\n");
173                                         res = -1;
174                                         break;
175                                 }
176                                 if (ms) {
177                                         f = ast_read(chan);
178                                         if (!f) {
179                                                 ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
180                                                 res = -1;
181                                                 break;
182                                         }
183                                         if (f->frametype == AST_FRAME_DTMF) {
184                                                 ast_log(LOG_DEBUG, "User pressed a key\n");
185                                                 ast_frfree(f);
186                                                 res = 0;
187                                                 break;
188                                         }
189                                         ast_frfree(f);
190                                 } 
191                         }
192                 }
193         }
194         close(fds[0]);
195         close(fds[1]);
196         LOCAL_USER_REMOVE(u);
197         if (pid > -1)
198                 kill(pid, SIGKILL);
199         if (!res && owriteformat)
200                 ast_set_write_format(chan, owriteformat);
201         return res;
202 }
203
204 int unload_module(void)
205 {
206         STANDARD_HANGUP_LOCALUSERS;
207         return ast_unregister_application(app);
208 }
209
210 int load_module(void)
211 {
212         return ast_register_application(app, NBScat_exec, synopsis, descrip);
213 }
214
215 char *description(void)
216 {
217         return tdesc;
218 }
219
220 int usecount(void)
221 {
222         int res;
223         STANDARD_USECOUNT(res);
224         return res;
225 }
226
227 char *key()
228 {
229         return ASTERISK_GPL_KEY;
230 }