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
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.
26 * \brief DAHDI Scanner
28 * \author Mark Spencer <markster@digium.com>
30 * \ingroup applications
34 <depend>dahdi</depend>
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";
68 static struct ast_channel
*get_dahdi_channel_locked(int num
) {
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
)
79 res
= write(fd
, data
, len
);
81 if (errno
!= EAGAIN
) {
82 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
94 static int conf_run(struct ast_channel
*chan
, int confno
, int confflags
)
97 struct dahdi_confinfo dahdic
;
99 struct ast_channel
*c
;
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
);
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
);
127 ast_indicate(chan
, -1);
128 retrydahdi
= strcasecmp(chan
->tech
->type
, "DAHDI");
130 origfd
= chan
->fds
[0];
132 fd
= open("/dev/dahdi/pseudo", O_RDWR
);
134 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
137 /* Make non-blocking */
138 flags
= fcntl(fd
, F_GETFL
);
140 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
144 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
145 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
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
;
155 if (ioctl(fd
, DAHDI_SET_BUFINFO
, &bi
)) {
156 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
162 /* XXX Make sure we're not running on a pseudo channel XXX */
166 memset(&dahdic
, 0, sizeof(dahdic
));
167 /* Check to see if we're in a conference... */
169 if (ioctl(fd
, DAHDI_GETCONF
, &dahdic
)) {
170 ast_log(LOG_WARNING
, "Error getting conference\n");
174 if (dahdic
.confmode
) {
175 /* Whoa, already in a conference... Retry... */
177 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
182 memset(&dahdic
, 0, sizeof(dahdic
));
183 /* Add us to the conference */
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");
193 ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan
->name
, confno
);
198 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
200 if (c
->fds
[0] != origfd
) {
202 /* Kill old pseudo */
205 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
213 if (f
->frametype
== AST_FRAME_DTMF
) {
214 if (f
->subclass
== '#') {
217 } else if (f
->subclass
== '*') {
221 input
[ic
++] = f
->subclass
;
227 ast_verb(3, "DAHDIScan: change channel to %d\n", ret
);
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
);
238 ast_log(LOG_WARNING
, "Huh? Got a non-ulaw (%d) frame in the conference\n", f
->subclass
);
243 } else if (outfd
> -1) {
244 res
= read(outfd
, buf
, CONF_SIZE
);
246 memset(&fr
, 0, sizeof(fr
));
247 fr
.frametype
= AST_FRAME_VOICE
;
248 fr
.subclass
= AST_FORMAT_ULAW
;
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
));
258 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
265 if (fd
!= chan
->fds
[0]) {
268 /* Take out of conference */
269 /* Add us to the conference */
273 if (ioctl(fd
, DAHDI_SETCONF
, &dahdic
)) {
274 ast_log(LOG_WARNING
, "Error setting conference\n");
283 static int conf_exec(struct ast_channel
*chan
, void *data
)
288 char confstr
[80] = "", *tmp
= NULL
;
289 struct ast_channel
*tempchan
= NULL
, *lastchan
= NULL
, *ichan
= NULL
;
292 int input
= 0, search_group
= 0;
294 if (chan
->_state
!= AST_STATE_UP
)
297 desired_group
= ast_strdupa(data
);
298 if (!ast_strlen_zero(desired_group
)) {
299 ast_verb(3, "Scanning for group %s\n", desired_group
);
304 if (ast_waitfor(chan
, 100) < 0)
310 if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '*')) {
317 ichan
= get_dahdi_channel_locked(input
);
321 tempchan
= ichan
? ichan
: ast_channel_walk_locked(tempchan
);
323 if (!tempchan
&& !lastchan
) {
327 if (tempchan
&& search_group
) {
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
);
332 ast_channel_unlock(tempchan
);
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
, '-'))) {
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
);
352 } else if (tempchan
) {
353 ast_channel_unlock(tempchan
);
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");