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>zaptel</depend>
39 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
46 #include <sys/ioctl.h>
47 #include <zaptel/zaptel.h>
49 #include "asterisk/lock.h"
50 #include "asterisk/file.h"
51 #include "asterisk/logger.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/pbx.h"
54 #include "asterisk/module.h"
55 #include "asterisk/config.h"
56 #include "asterisk/app.h"
57 #include "asterisk/options.h"
58 #include "asterisk/utils.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/say.h"
62 static char *app
= "ZapScan";
64 static char *synopsis
= "Scan Zap channels to monitor calls";
66 static char *descrip
=
67 " ZapScan([group]) allows a call center manager to monitor Zap channels in\n"
68 "a convenient way. Use '#' to select the next channel and use '*' to exit\n"
69 "Limit scanning to a channel GROUP by setting the option group argument.\n";
74 static struct ast_channel
*get_zap_channel_locked(int num
) {
77 snprintf(name
,sizeof(name
),"Zap/%d-1",num
);
78 return ast_get_channel_by_name_locked(name
);
81 static int careful_write(int fd
, unsigned char *data
, int len
)
85 res
= write(fd
, data
, len
);
87 if (errno
!= EAGAIN
) {
88 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
99 static int conf_run(struct ast_channel
*chan
, int confno
, int confflags
)
102 struct zt_confinfo ztc
;
104 struct ast_channel
*c
;
118 char __buf
[CONF_SIZE
+ AST_FRIENDLY_OFFSET
];
119 char *buf
= __buf
+ AST_FRIENDLY_OFFSET
;
121 /* Set it into U-law mode (write) */
122 if (ast_set_write_format(chan
, AST_FORMAT_ULAW
) < 0) {
123 ast_log(LOG_WARNING
, "Unable to set '%s' to write ulaw mode\n", chan
->name
);
127 /* Set it into U-law mode (read) */
128 if (ast_set_read_format(chan
, AST_FORMAT_ULAW
) < 0) {
129 ast_log(LOG_WARNING
, "Unable to set '%s' to read ulaw mode\n", chan
->name
);
132 ast_indicate(chan
, -1);
133 retryzap
= strcasecmp(chan
->tech
->type
, "Zap");
135 origfd
= chan
->fds
[0];
137 fd
= open("/dev/zap/pseudo", O_RDWR
);
139 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
142 /* Make non-blocking */
143 flags
= fcntl(fd
, F_GETFL
);
145 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
149 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
150 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
154 /* Setup buffering information */
155 memset(&bi
, 0, sizeof(bi
));
156 bi
.bufsize
= CONF_SIZE
;
157 bi
.txbufpolicy
= ZT_POLICY_IMMEDIATE
;
158 bi
.rxbufpolicy
= ZT_POLICY_IMMEDIATE
;
160 if (ioctl(fd
, ZT_SET_BUFINFO
, &bi
)) {
161 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
167 /* XXX Make sure we're not running on a pseudo channel XXX */
171 memset(&ztc
, 0, sizeof(ztc
));
172 /* Check to see if we're in a conference... */
174 if (ioctl(fd
, ZT_GETCONF
, &ztc
)) {
175 ast_log(LOG_WARNING
, "Error getting conference\n");
180 /* Whoa, already in a conference... Retry... */
182 ast_log(LOG_DEBUG
, "Zap channel is in a conference already, retrying with pseudo\n");
187 memset(&ztc
, 0, sizeof(ztc
));
188 /* Add us to the conference */
191 ztc
.confmode
= ZT_CONF_MONITORBOTH
;
193 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
194 ast_log(LOG_WARNING
, "Error setting conference\n");
198 ast_log(LOG_DEBUG
, "Placed channel %s in ZAP channel %d monitor\n", chan
->name
, confno
);
203 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
205 if (c
->fds
[0] != origfd
) {
207 /* Kill old pseudo */
210 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
217 if(f
->frametype
== AST_FRAME_DTMF
) {
218 if(f
->subclass
== '#') {
222 else if (f
->subclass
== '*') {
228 input
[ic
++] = f
->subclass
;
234 ast_verbose(VERBOSE_PREFIX_3
"Zapscan: change channel to %d\n",ret
);
239 if (fd
!= chan
->fds
[0]) {
240 if (f
->frametype
== AST_FRAME_VOICE
) {
241 if (f
->subclass
== AST_FORMAT_ULAW
) {
242 /* Carefully write */
243 careful_write(fd
, f
->data
, f
->datalen
);
245 ast_log(LOG_WARNING
, "Huh? Got a non-ulaw (%d) frame in the conference\n", f
->subclass
);
249 } else if (outfd
> -1) {
250 res
= read(outfd
, buf
, CONF_SIZE
);
252 memset(&fr
, 0, sizeof(fr
));
253 fr
.frametype
= AST_FRAME_VOICE
;
254 fr
.subclass
= AST_FORMAT_ULAW
;
258 fr
.offset
= AST_FRIENDLY_OFFSET
;
259 if (ast_write(chan
, &fr
) < 0) {
260 ast_log(LOG_WARNING
, "Unable to write frame to channel: %s\n", strerror(errno
));
264 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
269 if (fd
!= chan
->fds
[0])
272 /* Take out of conference */
273 /* Add us to the conference */
277 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
278 ast_log(LOG_WARNING
, "Error setting conference\n");
287 static int conf_exec(struct ast_channel
*chan
, void *data
)
290 struct ast_module_user
*u
;
293 char confstr
[80] = "", *tmp
= NULL
;
294 struct ast_channel
*tempchan
= NULL
, *lastchan
= NULL
,*ichan
= NULL
;
297 int input
=0,search_group
=0;
299 u
= ast_module_user_add(chan
);
301 if (chan
->_state
!= AST_STATE_UP
)
304 desired_group
= ast_strdupa(data
);
305 if(!ast_strlen_zero(desired_group
)) {
306 ast_verbose(VERBOSE_PREFIX_3
"Scanning for group %s\n", desired_group
);
311 if (ast_waitfor(chan
, 100) < 0)
317 if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '*')) {
324 ichan
= get_zap_channel_locked(input
);
328 tempchan
= ichan
? ichan
: ast_channel_walk_locked(tempchan
);
330 if ( !tempchan
&& !lastchan
)
333 if (tempchan
&& search_group
) {
335 if((mygroup
= pbx_builtin_getvar_helper(tempchan
, "GROUP")) && (!strcmp(mygroup
, desired_group
))) {
336 ast_verbose(VERBOSE_PREFIX_3
"Found Matching Channel %s in group %s\n", tempchan
->name
, desired_group
);
338 ast_mutex_unlock(&tempchan
->lock
);
343 if (tempchan
&& (!strcmp(tempchan
->tech
->type
, "Zap")) && (tempchan
!= chan
) ) {
344 ast_verbose(VERBOSE_PREFIX_3
"Zap channel %s is in-use, monitoring...\n", tempchan
->name
);
345 ast_copy_string(confstr
, tempchan
->name
, sizeof(confstr
));
346 ast_mutex_unlock(&tempchan
->lock
);
347 if ((tmp
= strchr(confstr
,'-'))) {
350 confno
= atoi(strchr(confstr
,'/') + 1);
351 ast_stopstream(chan
);
352 ast_say_number(chan
, confno
, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
353 res
= conf_run(chan
, confno
, confflags
);
357 ast_mutex_unlock(&tempchan
->lock
);
360 ast_module_user_remove(u
);
364 static int unload_module(void)
368 res
= ast_unregister_application(app
);
370 ast_module_user_hangup_all();
375 static int load_module(void)
377 return ast_register_application(app
, conf_exec
, synopsis
, descrip
);
380 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Scan Zap channels application");