Support for withheld or missing CID string
[asterisk-bristuff.git] / apps / app_dahdiscan.c
blobe1b8694e14bc9fa8de478a14732b6387312421f0
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * Modified from app_zapbarge by David Troy <dave@toad.net>
10 * Special thanks to comphealth.com for sponsoring this
11 * GPL application.
13 * See http://www.asterisk.org for more information about
14 * the Asterisk project. Please do not directly contact
15 * any of the maintainers of this project for assistance;
16 * the project provides a web site, mailing lists and IRC
17 * channels for your use.
19 * This program is free software, distributed under the terms of
20 * the GNU General Public License Version 2. See the LICENSE file
21 * at the top of the source tree.
24 /*! \file
26 * \brief Zap Scanner
28 * \author Mark Spencer <markster@digium.com>
30 * \ingroup applications
33 /*** MODULEINFO
34 <depend>dahdi</depend>
35 ***/
37 #include "asterisk.h"
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <errno.h>
46 #include <sys/ioctl.h>
48 #include "asterisk/lock.h"
49 #include "asterisk/file.h"
50 #include "asterisk/logger.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/module.h"
54 #include "asterisk/config.h"
55 #include "asterisk/app.h"
56 #include "asterisk/options.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/cli.h"
59 #include "asterisk/say.h"
61 #include "asterisk/dahdi_compat.h"
63 static char *app = "DAHDIScan";
64 static char *deprecated_app = "ZapScan";
66 static char *synopsis = "Scan Zap channels to monitor calls";
68 static char *descrip =
69 " ZapScan([group]) allows a call center manager to monitor Zap channels in\n"
70 "a convenient way. Use '#' to select the next channel and use '*' to exit\n"
71 "Limit scanning to a channel GROUP by setting the option group argument.\n";
74 #define CONF_SIZE 160
76 static struct ast_channel *get_zap_channel_locked(int num) {
77 char name[80];
79 snprintf(name,sizeof(name),"%s/%d-1", dahdi_chan_name, num);
80 return ast_get_channel_by_name_locked(name);
83 static int careful_write(int fd, unsigned char *data, int len)
85 int res;
86 while(len) {
87 res = write(fd, data, len);
88 if (res < 1) {
89 if (errno != EAGAIN) {
90 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
91 return -1;
92 } else
93 return 0;
95 len -= res;
96 data += res;
98 return 0;
101 static int conf_run(struct ast_channel *chan, int confno, int confflags)
103 int fd;
104 struct dahdi_confinfo ztc;
105 struct ast_frame *f;
106 struct ast_channel *c;
107 struct ast_frame fr;
108 int outfd;
109 int ms;
110 int nfds;
111 int res;
112 int flags;
113 int retryzap;
114 int origfd;
115 int ret = -1;
116 char input[4];
117 int ic=0;
118 struct dahdi_bufferinfo bi;
119 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
120 char *buf = __buf + AST_FRIENDLY_OFFSET;
122 /* Set it into U-law mode (write) */
123 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
124 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
125 goto outrun;
128 /* Set it into U-law mode (read) */
129 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
130 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
131 goto outrun;
133 ast_indicate(chan, -1);
134 retryzap = strcasecmp(chan->tech->type, "Zap");
135 zapretry:
136 origfd = chan->fds[0];
137 if (retryzap) {
138 fd = open("/dev/zap/pseudo", O_RDWR);
139 if (fd < 0) {
140 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
141 goto outrun;
143 /* Make non-blocking */
144 flags = fcntl(fd, F_GETFL);
145 if (flags < 0) {
146 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
147 close(fd);
148 goto outrun;
150 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
151 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
152 close(fd);
153 goto outrun;
155 /* Setup buffering information */
156 memset(&bi, 0, sizeof(bi));
157 bi.bufsize = CONF_SIZE;
158 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
159 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
160 bi.numbufs = 4;
161 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
162 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
163 close(fd);
164 goto outrun;
166 nfds = 1;
167 } else {
168 /* XXX Make sure we're not running on a pseudo channel XXX */
169 fd = chan->fds[0];
170 nfds = 0;
172 memset(&ztc, 0, sizeof(ztc));
173 /* Check to see if we're in a conference... */
174 ztc.chan = 0;
175 if (ioctl(fd, DAHDI_GETCONF, &ztc)) {
176 ast_log(LOG_WARNING, "Error getting conference\n");
177 close(fd);
178 goto outrun;
180 if (ztc.confmode) {
181 /* Whoa, already in a conference... Retry... */
182 if (!retryzap) {
183 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
184 retryzap = 1;
185 goto zapretry;
188 memset(&ztc, 0, sizeof(ztc));
189 /* Add us to the conference */
190 ztc.chan = 0;
191 ztc.confno = confno;
192 ztc.confmode = DAHDI_CONF_MONITORBOTH;
194 if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
195 ast_log(LOG_WARNING, "Error setting conference\n");
196 close(fd);
197 goto outrun;
199 ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno);
201 for(;;) {
202 outfd = -1;
203 ms = -1;
204 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
205 if (c) {
206 if (c->fds[0] != origfd) {
207 if (retryzap) {
208 /* Kill old pseudo */
209 close(fd);
211 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
212 retryzap = 0;
213 goto zapretry;
215 f = ast_read(c);
216 if (!f)
217 break;
218 if(f->frametype == AST_FRAME_DTMF) {
219 if(f->subclass == '#') {
220 ret = 0;
221 break;
223 else if (f->subclass == '*') {
224 ret = -1;
225 break;
228 else {
229 input[ic++] = f->subclass;
231 if(ic == 3) {
232 input[ic++] = '\0';
233 ic=0;
234 ret = atoi(input);
235 ast_verbose(VERBOSE_PREFIX_3 "Zapscan: change channel to %d\n",ret);
236 break;
240 if (fd != chan->fds[0]) {
241 if (f->frametype == AST_FRAME_VOICE) {
242 if (f->subclass == AST_FORMAT_ULAW) {
243 /* Carefully write */
244 careful_write(fd, f->data, f->datalen);
245 } else
246 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
249 ast_frfree(f);
250 } else if (outfd > -1) {
251 res = read(outfd, buf, CONF_SIZE);
252 if (res > 0) {
253 memset(&fr, 0, sizeof(fr));
254 fr.frametype = AST_FRAME_VOICE;
255 fr.subclass = AST_FORMAT_ULAW;
256 fr.datalen = res;
257 fr.samples = res;
258 fr.data = buf;
259 fr.offset = AST_FRIENDLY_OFFSET;
260 if (ast_write(chan, &fr) < 0) {
261 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
262 /* break; */
264 } else
265 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
268 if (f)
269 ast_frfree(f);
270 if (fd != chan->fds[0])
271 close(fd);
272 else {
273 /* Take out of conference */
274 /* Add us to the conference */
275 ztc.chan = 0;
276 ztc.confno = 0;
277 ztc.confmode = 0;
278 if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
279 ast_log(LOG_WARNING, "Error setting conference\n");
283 outrun:
285 return ret;
288 static int conf_exec(struct ast_channel *chan, void *data)
290 int res=-1;
291 struct ast_module_user *u;
292 int confflags = 0;
293 int confno = 0;
294 char confstr[80] = "", *tmp = NULL;
295 struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL;
296 struct ast_frame *f;
297 char *desired_group;
298 int input=0,search_group=0;
300 u = ast_module_user_add(chan);
302 if (chan->_state != AST_STATE_UP)
303 ast_answer(chan);
305 desired_group = ast_strdupa(data);
306 if(!ast_strlen_zero(desired_group)) {
307 ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group);
308 search_group = 1;
311 for (;;) {
312 if (ast_waitfor(chan, 100) < 0)
313 break;
315 f = ast_read(chan);
316 if (!f)
317 break;
318 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
319 ast_frfree(f);
320 break;
322 ast_frfree(f);
323 ichan = NULL;
324 if(input) {
325 ichan = get_zap_channel_locked(input);
326 input = 0;
329 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
331 if ( !tempchan && !lastchan )
332 break;
334 if (tempchan && search_group) {
335 const char *mygroup;
336 if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
337 ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
338 } else {
339 ast_mutex_unlock(&tempchan->lock);
340 lastchan = tempchan;
341 continue;
344 if (tempchan && (!strcmp(tempchan->tech->type, "Zap")) && (tempchan != chan) ) {
345 ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name);
346 ast_copy_string(confstr, tempchan->name, sizeof(confstr));
347 ast_mutex_unlock(&tempchan->lock);
348 if ((tmp = strchr(confstr,'-'))) {
349 *tmp = '\0';
351 confno = atoi(strchr(confstr,'/') + 1);
352 ast_stopstream(chan);
353 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
354 res = conf_run(chan, confno, confflags);
355 if (res<0) break;
356 input = res;
357 } else if (tempchan)
358 ast_mutex_unlock(&tempchan->lock);
359 lastchan = tempchan;
361 ast_module_user_remove(u);
362 return res;
365 static int conf_exec_warn(struct ast_channel *chan, void *data)
367 ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", deprecated_app, app);
368 return conf_exec(chan, data);
371 static int unload_module(void)
373 int res;
375 res = ast_unregister_application(app);
377 ast_module_user_hangup_all();
379 return res;
382 static int load_module(void)
384 ast_register_application(deprecated_app, conf_exec_warn, synopsis, descrip);
385 return ast_register_application(app, conf_exec, synopsis, descrip);
388 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan Zap channels application");