Use find_user for existsmailbox
[asterisk/asterisk.git] / apps / app_zapbarge.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Zap Barge support
5  * 
6  * Copyright (C) 2003, Digium
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  *
13  * Special thanks to comphealth.com for sponsoring this
14  * GPL application.
15  */
16
17 #include <asterisk/lock.h>
18 #include <asterisk/file.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/pbx.h>
22 #include <asterisk/module.h>
23 #include <asterisk/config.h>
24 #include <asterisk/app.h>
25 #include <asterisk/options.h>
26 #include <asterisk/cli.h>
27 #include <asterisk/say.h>
28 #include <asterisk/utils.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <sys/ioctl.h>
35
36 #include <pthread.h>
37 #include <linux/zaptel.h>
38 static char *tdesc = "Barge in on Zap channel application";
39
40 static char *app = "ZapBarge";
41
42 static char *synopsis = "Barge in (monitor) Zap channel";
43
44 static char *descrip = 
45 "  ZapBarge([channel]): Barges in on a specified zap\n"
46 "channel or prompts if one is not specified.  Returns\n"
47 "-1 when caller user hangs up and is independent of the\n"
48 "state of the channel being monitored.";
49
50
51 STANDARD_LOCAL_USER;
52
53 LOCAL_USER_DECL;
54
55
56 #define CONF_SIZE 160
57
58 static int careful_write(int fd, unsigned char *data, int len)
59 {
60         int res;
61         while(len) {
62                 res = write(fd, data, len);
63                 if (res < 1) {
64                         if (errno != EAGAIN) {
65                                 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
66                                 return -1;
67                         } else
68                                 return 0;
69                 }
70                 len -= res;
71                 data += res;
72         }
73         return 0;
74 }
75
76 static int conf_run(struct ast_channel *chan, int confno, int confflags)
77 {
78         int fd;
79         struct zt_confinfo ztc;
80         struct ast_frame *f;
81         struct ast_channel *c;
82         struct ast_frame fr;
83         int outfd;
84         int ms;
85         int nfds;
86         int res;
87         int flags;
88         int retryzap;
89         int origfd;
90         int ret = -1;
91
92         ZT_BUFFERINFO bi;
93         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
94         char *buf = __buf + AST_FRIENDLY_OFFSET;
95
96         /* Set it into U-law mode (write) */
97         if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
98                 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
99                 goto outrun;
100         }
101
102         /* Set it into U-law mode (read) */
103         if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
104                 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
105                 goto outrun;
106         }
107         ast_indicate(chan, -1);
108         retryzap = strcasecmp(chan->type, "Zap");
109 zapretry:
110         origfd = chan->fds[0];
111         if (retryzap) {
112                 fd = open("/dev/zap/pseudo", O_RDWR);
113                 if (fd < 0) {
114                         ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
115                         goto outrun;
116                 }
117                 /* Make non-blocking */
118                 flags = fcntl(fd, F_GETFL);
119                 if (flags < 0) {
120                         ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
121                         close(fd);
122                         goto outrun;
123                 }
124                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
125                         ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
126                         close(fd);
127                         goto outrun;
128                 }
129                 /* Setup buffering information */
130                 memset(&bi, 0, sizeof(bi));
131                 bi.bufsize = CONF_SIZE;
132                 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
133                 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
134                 bi.numbufs = 4;
135                 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
136                         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
137                         close(fd);
138                         goto outrun;
139                 }
140                 nfds = 1;
141         } else {
142                 /* XXX Make sure we're not running on a pseudo channel XXX */
143                 fd = chan->fds[0];
144                 nfds = 0;
145         }
146         memset(&ztc, 0, sizeof(ztc));
147         /* Check to see if we're in a conference... */
148         ztc.chan = 0;   
149         if (ioctl(fd, ZT_GETCONF, &ztc)) {
150                 ast_log(LOG_WARNING, "Error getting conference\n");
151                 close(fd);
152                 goto outrun;
153         }
154         if (ztc.confmode) {
155                 /* Whoa, already in a conference...  Retry... */
156                 if (!retryzap) {
157                         ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
158                         retryzap = 1;
159                         goto zapretry;
160                 }
161         }
162         memset(&ztc, 0, sizeof(ztc));
163         /* Add us to the conference */
164         ztc.chan = 0;   
165         ztc.confno = confno;
166         ztc.confmode = ZT_CONF_MONITORBOTH;
167
168         if (ioctl(fd, ZT_SETCONF, &ztc)) {
169                 ast_log(LOG_WARNING, "Error setting conference\n");
170                 close(fd);
171                 goto outrun;
172         }
173         ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno);
174
175         for(;;) {
176                 outfd = -1;
177                 ms = -1;
178                 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
179                 if (c) {
180                         if (c->fds[0] != origfd) {
181                                 if (retryzap) {
182                                         /* Kill old pseudo */
183                                         close(fd);
184                                 }
185                                 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
186                                 retryzap = 0;
187                                 goto zapretry;
188                         }
189                         f = ast_read(c);
190                         if (!f) 
191                                 break;
192                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
193                                 ret = 0;
194                                 break;
195                         } else if (fd != chan->fds[0]) {
196                                 if (f->frametype == AST_FRAME_VOICE) {
197                                         if (f->subclass == AST_FORMAT_ULAW) {
198                                                 /* Carefully write */
199                                                 careful_write(fd, f->data, f->datalen);
200                                         } else
201                                                 ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
202                                 }
203                         }
204                         ast_frfree(f);
205                 } else if (outfd > -1) {
206                         res = read(outfd, buf, CONF_SIZE);
207                         if (res > 0) {
208                                 memset(&fr, 0, sizeof(fr));
209                                 fr.frametype = AST_FRAME_VOICE;
210                                 fr.subclass = AST_FORMAT_ULAW;
211                                 fr.datalen = res;
212                                 fr.samples = res;
213                                 fr.data = buf;
214                                 fr.offset = AST_FRIENDLY_OFFSET;
215                                 if (ast_write(chan, &fr) < 0) {
216                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
217                                         /* break; */
218                                 }
219                         } else 
220                                 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
221                 }
222         }
223         if (fd != chan->fds[0])
224                 close(fd);
225         else {
226                 /* Take out of conference */
227                 /* Add us to the conference */
228                 ztc.chan = 0;   
229                 ztc.confno = 0;
230                 ztc.confmode = 0;
231                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
232                         ast_log(LOG_WARNING, "Error setting conference\n");
233                 }
234         }
235
236 outrun:
237
238         return ret;
239 }
240
241 static int conf_exec(struct ast_channel *chan, void *data)
242 {
243         int res=-1;
244         struct localuser *u;
245         int retrycnt = 0;
246         int confflags = 0;
247         int confno = 0;
248         char confstr[80];
249
250         if (data && !ast_strlen_zero(data)) {
251                 if ((sscanf(data, "Zap/%d", &confno) != 1) &&
252                     (sscanf(data, "%d", &confno) != 1)) {
253                         ast_log(LOG_WARNING, "ZapBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
254                         return 0;
255                 }
256         }
257         LOCAL_USER_ADD(u);
258         if (chan->_state != AST_STATE_UP)
259                 ast_answer(chan);
260
261         while(!confno && (++retrycnt < 4)) {
262                 /* Prompt user for conference number */
263                 strcpy(confstr, "");
264                 res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
265                 if (res <0) goto out;
266                 if (sscanf(confstr, "%d", &confno) != 1)
267                         confno = 0;
268         }
269         if (confno) {
270                 /* XXX Should prompt user for pin if pin is required XXX */
271                 /* Run the conference */
272                 res = conf_run(chan, confno, confflags);
273         }
274 out:
275         /* Do the conference */
276         LOCAL_USER_REMOVE(u);
277         return res;
278 }
279
280 int unload_module(void)
281 {
282         STANDARD_HANGUP_LOCALUSERS;
283         return ast_unregister_application(app);
284 }
285
286 int load_module(void)
287 {
288         return ast_register_application(app, conf_exec, synopsis, descrip);
289 }
290
291 char *description(void)
292 {
293         return tdesc;
294 }
295
296 int usecount(void)
297 {
298         int res;
299         STANDARD_USECOUNT(res);
300         return res;
301 }
302
303 char *key()
304 {
305         return ASTERISK_GPL_KEY;
306 }