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.
28 * \author Mark Spencer <markster@digium.com>
30 * \ingroup applications
34 <depend>dahdi</depend>
39 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
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";
76 static struct ast_channel
*get_zap_channel_locked(int num
) {
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
)
87 res
= write(fd
, data
, len
);
89 if (errno
!= EAGAIN
) {
90 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
101 static int conf_run(struct ast_channel
*chan
, int confno
, int confflags
)
104 struct dahdi_confinfo ztc
;
106 struct ast_channel
*c
;
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
);
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
);
133 ast_indicate(chan
, -1);
134 retryzap
= strcasecmp(chan
->tech
->type
, "Zap");
136 origfd
= chan
->fds
[0];
138 fd
= open("/dev/zap/pseudo", O_RDWR
);
140 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
143 /* Make non-blocking */
144 flags
= fcntl(fd
, F_GETFL
);
146 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
150 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
151 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
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
;
161 if (ioctl(fd
, DAHDI_SET_BUFINFO
, &bi
)) {
162 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
168 /* XXX Make sure we're not running on a pseudo channel XXX */
172 memset(&ztc
, 0, sizeof(ztc
));
173 /* Check to see if we're in a conference... */
175 if (ioctl(fd
, DAHDI_GETCONF
, &ztc
)) {
176 ast_log(LOG_WARNING
, "Error getting conference\n");
181 /* Whoa, already in a conference... Retry... */
183 ast_log(LOG_DEBUG
, "Zap channel is in a conference already, retrying with pseudo\n");
188 memset(&ztc
, 0, sizeof(ztc
));
189 /* Add us to the conference */
192 ztc
.confmode
= DAHDI_CONF_MONITORBOTH
;
194 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
195 ast_log(LOG_WARNING
, "Error setting conference\n");
199 ast_log(LOG_DEBUG
, "Placed channel %s in ZAP channel %d monitor\n", chan
->name
, confno
);
204 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
206 if (c
->fds
[0] != origfd
) {
208 /* Kill old pseudo */
211 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
218 if(f
->frametype
== AST_FRAME_DTMF
) {
219 if(f
->subclass
== '#') {
223 else if (f
->subclass
== '*') {
229 input
[ic
++] = f
->subclass
;
235 ast_verbose(VERBOSE_PREFIX_3
"Zapscan: change channel to %d\n",ret
);
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
);
246 ast_log(LOG_WARNING
, "Huh? Got a non-ulaw (%d) frame in the conference\n", f
->subclass
);
250 } else if (outfd
> -1) {
251 res
= read(outfd
, buf
, CONF_SIZE
);
253 memset(&fr
, 0, sizeof(fr
));
254 fr
.frametype
= AST_FRAME_VOICE
;
255 fr
.subclass
= AST_FORMAT_ULAW
;
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
));
265 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
270 if (fd
!= chan
->fds
[0])
273 /* Take out of conference */
274 /* Add us to the conference */
278 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
279 ast_log(LOG_WARNING
, "Error setting conference\n");
288 static int conf_exec(struct ast_channel
*chan
, void *data
)
291 struct ast_module_user
*u
;
294 char confstr
[80] = "", *tmp
= NULL
;
295 struct ast_channel
*tempchan
= NULL
, *lastchan
= NULL
,*ichan
= NULL
;
298 int input
=0,search_group
=0;
300 u
= ast_module_user_add(chan
);
302 if (chan
->_state
!= AST_STATE_UP
)
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
);
312 if (ast_waitfor(chan
, 100) < 0)
318 if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '*')) {
325 ichan
= get_zap_channel_locked(input
);
329 tempchan
= ichan
? ichan
: ast_channel_walk_locked(tempchan
);
331 if ( !tempchan
&& !lastchan
)
334 if (tempchan
&& search_group
) {
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
);
339 ast_mutex_unlock(&tempchan
->lock
);
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
,'-'))) {
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
);
358 ast_mutex_unlock(&tempchan
->lock
);
361 ast_module_user_remove(u
);
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)
375 res
= ast_unregister_application(app
);
377 ast_module_user_hangup_all();
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");