Remove the code that decided when device state changes should be cached or not.
[asterisk-bristuff.git] / apps / app_dahdiscan.c
blobd1d37fa51bfcecac3bbfb45c524142c0f52535a3
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 DAHDI 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 <dahdi/user.h>
43 #include "asterisk/lock.h"
44 #include "asterisk/file.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/module.h"
48 #include "asterisk/config.h"
49 #include "asterisk/app.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/say.h"
53 #include "asterisk/options.h"
55 static char *app = "DAHDIScan";
56 static char *deprecated_app = "ZapScan";
58 static char *synopsis = "Scan DAHDI channels to monitor calls";
60 static char *descrip =
61 " DAHDIScan([group]) allows a call center manager to monitor DAHDI channels in\n"
62 "a convenient way. Use '#' to select the next channel and use '*' to exit\n"
63 "Limit scanning to a channel GROUP by setting the option group argument.\n";
66 #define CONF_SIZE 160
68 static struct ast_channel *get_dahdi_channel_locked(int num) {
69 char name[80];
71 snprintf(name, sizeof(name), "%s/%d-1", dahdi_chan_name, num);
72 return ast_get_channel_by_name_locked(name);
75 static int careful_write(int fd, unsigned char *data, int len)
77 int res;
78 while (len) {
79 res = write(fd, data, len);
80 if (res < 1) {
81 if (errno != EAGAIN) {
82 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
83 return -1;
84 } else {
85 return 0;
88 len -= res;
89 data += res;
91 return 0;
94 static int conf_run(struct ast_channel *chan, int confno, int confflags)
96 int fd;
97 struct dahdi_confinfo dahdic;
98 struct ast_frame *f;
99 struct ast_channel *c;
100 struct ast_frame fr;
101 int outfd;
102 int ms;
103 int nfds;
104 int res;
105 int flags;
106 int retrydahdi;
107 int origfd;
108 int ret = -1;
109 char input[4];
110 int ic = 0;
112 DAHDI_BUFFERINFO bi;
113 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
114 char *buf = __buf + AST_FRIENDLY_OFFSET;
116 /* Set it into U-law mode (write) */
117 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
118 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
119 goto outrun;
122 /* Set it into U-law mode (read) */
123 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
124 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
125 goto outrun;
127 ast_indicate(chan, -1);
128 retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
129 dahdiretry:
130 origfd = chan->fds[0];
131 if (retrydahdi) {
132 fd = open("/dev/dahdi/pseudo", O_RDWR);
133 if (fd < 0) {
134 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
135 goto outrun;
137 /* Make non-blocking */
138 flags = fcntl(fd, F_GETFL);
139 if (flags < 0) {
140 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
141 close(fd);
142 goto outrun;
144 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
145 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
146 close(fd);
147 goto outrun;
149 /* Setup buffering information */
150 memset(&bi, 0, sizeof(bi));
151 bi.bufsize = CONF_SIZE;
152 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
153 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
154 bi.numbufs = 4;
155 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
156 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
157 close(fd);
158 goto outrun;
160 nfds = 1;
161 } else {
162 /* XXX Make sure we're not running on a pseudo channel XXX */
163 fd = chan->fds[0];
164 nfds = 0;
166 memset(&dahdic, 0, sizeof(dahdic));
167 /* Check to see if we're in a conference... */
168 dahdic.chan = 0;
169 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
170 ast_log(LOG_WARNING, "Error getting conference\n");
171 close(fd);
172 goto outrun;
174 if (dahdic.confmode) {
175 /* Whoa, already in a conference... Retry... */
176 if (!retrydahdi) {
177 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
178 retrydahdi = 1;
179 goto dahdiretry;
182 memset(&dahdic, 0, sizeof(dahdic));
183 /* Add us to the conference */
184 dahdic.chan = 0;
185 dahdic.confno = confno;
186 dahdic.confmode = DAHDI_CONF_MONITORBOTH;
188 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
189 ast_log(LOG_WARNING, "Error setting conference\n");
190 close(fd);
191 goto outrun;
193 ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
195 for (;;) {
196 outfd = -1;
197 ms = -1;
198 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
199 if (c) {
200 if (c->fds[0] != origfd) {
201 if (retrydahdi) {
202 /* Kill old pseudo */
203 close(fd);
205 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
206 retrydahdi = 0;
207 goto dahdiretry;
209 f = ast_read(c);
210 if (!f) {
211 break;
213 if (f->frametype == AST_FRAME_DTMF) {
214 if (f->subclass == '#') {
215 ret = 0;
216 break;
217 } else if (f->subclass == '*') {
218 ret = -1;
219 break;
220 } else {
221 input[ic++] = f->subclass;
223 if (ic == 3) {
224 input[ic++] = '\0';
225 ic = 0;
226 ret = atoi(input);
227 ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
228 break;
232 if (fd != chan->fds[0]) {
233 if (f->frametype == AST_FRAME_VOICE) {
234 if (f->subclass == AST_FORMAT_ULAW) {
235 /* Carefully write */
236 careful_write(fd, f->data.ptr, f->datalen);
237 } else {
238 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
242 ast_frfree(f);
243 } else if (outfd > -1) {
244 res = read(outfd, buf, CONF_SIZE);
245 if (res > 0) {
246 memset(&fr, 0, sizeof(fr));
247 fr.frametype = AST_FRAME_VOICE;
248 fr.subclass = AST_FORMAT_ULAW;
249 fr.datalen = res;
250 fr.samples = res;
251 fr.data.ptr = buf;
252 fr.offset = AST_FRIENDLY_OFFSET;
253 if (ast_write(chan, &fr) < 0) {
254 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
255 /* break; */
257 } else {
258 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
262 if (f) {
263 ast_frfree(f);
265 if (fd != chan->fds[0]) {
266 close(fd);
267 } else {
268 /* Take out of conference */
269 /* Add us to the conference */
270 dahdic.chan = 0;
271 dahdic.confno = 0;
272 dahdic.confmode = 0;
273 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
274 ast_log(LOG_WARNING, "Error setting conference\n");
278 outrun:
280 return ret;
283 static int conf_exec(struct ast_channel *chan, void *data)
285 int res=-1;
286 int confflags = 0;
287 int confno = 0;
288 char confstr[80] = "", *tmp = NULL;
289 struct ast_channel *tempchan = NULL, *lastchan = NULL, *ichan = NULL;
290 struct ast_frame *f;
291 char *desired_group;
292 int input = 0, search_group = 0;
294 if (chan->_state != AST_STATE_UP)
295 ast_answer(chan);
297 desired_group = ast_strdupa(data);
298 if (!ast_strlen_zero(desired_group)) {
299 ast_verb(3, "Scanning for group %s\n", desired_group);
300 search_group = 1;
303 for (;;) {
304 if (ast_waitfor(chan, 100) < 0)
305 break;
307 f = ast_read(chan);
308 if (!f)
309 break;
310 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
311 ast_frfree(f);
312 break;
314 ast_frfree(f);
315 ichan = NULL;
316 if(input) {
317 ichan = get_dahdi_channel_locked(input);
318 input = 0;
321 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
323 if (!tempchan && !lastchan) {
324 break;
327 if (tempchan && search_group) {
328 const char *mygroup;
329 if ((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
330 ast_verb(3, "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
331 } else {
332 ast_channel_unlock(tempchan);
333 lastchan = tempchan;
334 continue;
337 if (tempchan && (!strcmp(tempchan->tech->type, "DAHDI")) && (tempchan != chan)) {
338 ast_verb(3, "DAHDI channel %s is in-use, monitoring...\n", tempchan->name);
339 ast_copy_string(confstr, tempchan->name, sizeof(confstr));
340 ast_channel_unlock(tempchan);
341 if ((tmp = strchr(confstr, '-'))) {
342 *tmp = '\0';
344 confno = atoi(strchr(confstr, '/') + 1);
345 ast_stopstream(chan);
346 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
347 res = conf_run(chan, confno, confflags);
348 if (res < 0) {
349 break;
351 input = res;
352 } else if (tempchan) {
353 ast_channel_unlock(tempchan);
355 lastchan = tempchan;
357 return res;
360 static int conf_exec_warn(struct ast_channel *chan, void *data)
362 ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", deprecated_app, app);
363 return conf_exec(chan, data);
366 static int unload_module(void)
368 return ast_unregister_application(app);
371 static int load_module(void)
373 ast_register_application(deprecated_app, conf_exec_warn, synopsis, descrip);
374 return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
377 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan DAHDI channels application");