#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel/zaptel.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
Go to the source code of this file.
Defines | |
#define | CONF_SIZE 160 |
Functions | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Scan Zap channels application") | |
static int | careful_write (int fd, unsigned char *data, int len) |
static int | conf_exec (struct ast_channel *chan, void *data) |
static int | conf_run (struct ast_channel *chan, int confno, int confflags) |
static struct ast_channel * | get_zap_channel_locked (int num) |
static int | load_module (void) |
static int | unload_module (void) |
Variables | |
static char * | app = "ZapScan" |
static char * | descrip |
static char * | synopsis = "Scan Zap channels to monitor calls" |
Definition in file app_zapscan.c.
#define CONF_SIZE 160 |
Definition at line 72 of file app_zapscan.c.
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Scan Zap channels application" | ||||
) |
static int careful_write | ( | int | fd, | |
unsigned char * | data, | |||
int | len | |||
) | [static] |
Definition at line 81 of file app_zapscan.c.
References ast_log(), errno, and LOG_WARNING.
00082 { 00083 int res; 00084 while(len) { 00085 res = write(fd, data, len); 00086 if (res < 1) { 00087 if (errno != EAGAIN) { 00088 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); 00089 return -1; 00090 } else 00091 return 0; 00092 } 00093 len -= res; 00094 data += res; 00095 } 00096 return 0; 00097 }
static int conf_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 287 of file app_zapscan.c.
References ast_channel::_state, ast_answer(), ast_channel_walk_locked(), AST_DIGIT_ANY, AST_FRAME_DTMF, ast_frfree, ast_module_user_add, ast_module_user_remove, ast_mutex_unlock(), ast_read(), ast_say_number(), AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_waitfor(), conf_run(), f, ast_frame::frametype, get_zap_channel_locked(), input(), ast_channel::lock, pbx_builtin_getvar_helper(), ast_frame::subclass, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_3.
00288 { 00289 int res=-1; 00290 struct ast_module_user *u; 00291 int confflags = 0; 00292 int confno = 0; 00293 char confstr[80] = "", *tmp = NULL; 00294 struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL; 00295 struct ast_frame *f; 00296 char *desired_group; 00297 int input=0,search_group=0; 00298 00299 u = ast_module_user_add(chan); 00300 00301 if (chan->_state != AST_STATE_UP) 00302 ast_answer(chan); 00303 00304 desired_group = ast_strdupa(data); 00305 if(!ast_strlen_zero(desired_group)) { 00306 ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group); 00307 search_group = 1; 00308 } 00309 00310 for (;;) { 00311 if (ast_waitfor(chan, 100) < 0) 00312 break; 00313 00314 f = ast_read(chan); 00315 if (!f) 00316 break; 00317 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) { 00318 ast_frfree(f); 00319 break; 00320 } 00321 ast_frfree(f); 00322 ichan = NULL; 00323 if(input) { 00324 ichan = get_zap_channel_locked(input); 00325 input = 0; 00326 } 00327 00328 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan); 00329 00330 if ( !tempchan && !lastchan ) 00331 break; 00332 00333 if (tempchan && search_group) { 00334 const char *mygroup; 00335 if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) { 00336 ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group); 00337 } else { 00338 ast_mutex_unlock(&tempchan->lock); 00339 lastchan = tempchan; 00340 continue; 00341 } 00342 } 00343 if (tempchan && (!strcmp(tempchan->tech->type, "Zap")) && (tempchan != chan) ) { 00344 ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name); 00345 ast_copy_string(confstr, tempchan->name, sizeof(confstr)); 00346 ast_mutex_unlock(&tempchan->lock); 00347 if ((tmp = strchr(confstr,'-'))) { 00348 *tmp = '\0'; 00349 } 00350 confno = atoi(strchr(confstr,'/') + 1); 00351 ast_stopstream(chan); 00352 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL); 00353 res = conf_run(chan, confno, confflags); 00354 if (res<0) break; 00355 input = res; 00356 } else if (tempchan) 00357 ast_mutex_unlock(&tempchan->lock); 00358 lastchan = tempchan; 00359 } 00360 ast_module_user_remove(u); 00361 return res; 00362 }
static int conf_run | ( | struct ast_channel * | chan, | |
int | confno, | |||
int | confflags | |||
) | [static] |
Definition at line 99 of file app_zapscan.c.
References AST_FORMAT_ULAW, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_indicate(), ast_log(), ast_read(), ast_set_read_format(), ast_set_write_format(), ast_verbose(), ast_waitfor_nandfds(), ast_write(), careful_write(), CONF_SIZE, ast_frame::data, ast_frame::datalen, errno, f, ast_channel::fds, ast_frame::frametype, input(), LOG_DEBUG, LOG_WARNING, ast_frame::offset, ast_frame::samples, ast_frame::subclass, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_3.
00100 { 00101 int fd; 00102 struct zt_confinfo ztc; 00103 struct ast_frame *f; 00104 struct ast_channel *c; 00105 struct ast_frame fr; 00106 int outfd; 00107 int ms; 00108 int nfds; 00109 int res; 00110 int flags; 00111 int retryzap; 00112 int origfd; 00113 int ret = -1; 00114 char input[4]; 00115 int ic=0; 00116 00117 ZT_BUFFERINFO bi; 00118 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; 00119 char *buf = __buf + AST_FRIENDLY_OFFSET; 00120 00121 /* Set it into U-law mode (write) */ 00122 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) { 00123 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name); 00124 goto outrun; 00125 } 00126 00127 /* Set it into U-law mode (read) */ 00128 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) { 00129 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name); 00130 goto outrun; 00131 } 00132 ast_indicate(chan, -1); 00133 retryzap = strcasecmp(chan->tech->type, "Zap"); 00134 zapretry: 00135 origfd = chan->fds[0]; 00136 if (retryzap) { 00137 fd = open("/dev/zap/pseudo", O_RDWR); 00138 if (fd < 0) { 00139 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); 00140 goto outrun; 00141 } 00142 /* Make non-blocking */ 00143 flags = fcntl(fd, F_GETFL); 00144 if (flags < 0) { 00145 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); 00146 close(fd); 00147 goto outrun; 00148 } 00149 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { 00150 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); 00151 close(fd); 00152 goto outrun; 00153 } 00154 /* Setup buffering information */ 00155 memset(&bi, 0, sizeof(bi)); 00156 bi.bufsize = CONF_SIZE; 00157 bi.txbufpolicy = ZT_POLICY_IMMEDIATE; 00158 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; 00159 bi.numbufs = 4; 00160 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { 00161 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); 00162 close(fd); 00163 goto outrun; 00164 } 00165 nfds = 1; 00166 } else { 00167 /* XXX Make sure we're not running on a pseudo channel XXX */ 00168 fd = chan->fds[0]; 00169 nfds = 0; 00170 } 00171 memset(&ztc, 0, sizeof(ztc)); 00172 /* Check to see if we're in a conference... */ 00173 ztc.chan = 0; 00174 if (ioctl(fd, ZT_GETCONF, &ztc)) { 00175 ast_log(LOG_WARNING, "Error getting conference\n"); 00176 close(fd); 00177 goto outrun; 00178 } 00179 if (ztc.confmode) { 00180 /* Whoa, already in a conference... Retry... */ 00181 if (!retryzap) { 00182 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); 00183 retryzap = 1; 00184 goto zapretry; 00185 } 00186 } 00187 memset(&ztc, 0, sizeof(ztc)); 00188 /* Add us to the conference */ 00189 ztc.chan = 0; 00190 ztc.confno = confno; 00191 ztc.confmode = ZT_CONF_MONITORBOTH; 00192 00193 if (ioctl(fd, ZT_SETCONF, &ztc)) { 00194 ast_log(LOG_WARNING, "Error setting conference\n"); 00195 close(fd); 00196 goto outrun; 00197 } 00198 ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno); 00199 00200 for(;;) { 00201 outfd = -1; 00202 ms = -1; 00203 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); 00204 if (c) { 00205 if (c->fds[0] != origfd) { 00206 if (retryzap) { 00207 /* Kill old pseudo */ 00208 close(fd); 00209 } 00210 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); 00211 retryzap = 0; 00212 goto zapretry; 00213 } 00214 f = ast_read(c); 00215 if (!f) 00216 break; 00217 if(f->frametype == AST_FRAME_DTMF) { 00218 if(f->subclass == '#') { 00219 ret = 0; 00220 break; 00221 } 00222 else if (f->subclass == '*') { 00223 ret = -1; 00224 break; 00225 00226 } 00227 else { 00228 input[ic++] = f->subclass; 00229 } 00230 if(ic == 3) { 00231 input[ic++] = '\0'; 00232 ic=0; 00233 ret = atoi(input); 00234 ast_verbose(VERBOSE_PREFIX_3 "Zapscan: change channel to %d\n",ret); 00235 break; 00236 } 00237 } 00238 00239 if (fd != chan->fds[0]) { 00240 if (f->frametype == AST_FRAME_VOICE) { 00241 if (f->subclass == AST_FORMAT_ULAW) { 00242 /* Carefully write */ 00243 careful_write(fd, f->data, f->datalen); 00244 } else 00245 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass); 00246 } 00247 } 00248 ast_frfree(f); 00249 } else if (outfd > -1) { 00250 res = read(outfd, buf, CONF_SIZE); 00251 if (res > 0) { 00252 memset(&fr, 0, sizeof(fr)); 00253 fr.frametype = AST_FRAME_VOICE; 00254 fr.subclass = AST_FORMAT_ULAW; 00255 fr.datalen = res; 00256 fr.samples = res; 00257 fr.data = buf; 00258 fr.offset = AST_FRIENDLY_OFFSET; 00259 if (ast_write(chan, &fr) < 0) { 00260 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); 00261 /* break; */ 00262 } 00263 } else 00264 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); 00265 } 00266 } 00267 if (f) 00268 ast_frfree(f); 00269 if (fd != chan->fds[0]) 00270 close(fd); 00271 else { 00272 /* Take out of conference */ 00273 /* Add us to the conference */ 00274 ztc.chan = 0; 00275 ztc.confno = 0; 00276 ztc.confmode = 0; 00277 if (ioctl(fd, ZT_SETCONF, &ztc)) { 00278 ast_log(LOG_WARNING, "Error setting conference\n"); 00279 } 00280 } 00281 00282 outrun: 00283 00284 return ret; 00285 }
static struct ast_channel* get_zap_channel_locked | ( | int | num | ) | [static, read] |
Definition at line 74 of file app_zapscan.c.
References ast_get_channel_by_name_locked(), and name.
Referenced by conf_exec().
00074 { 00075 char name[80]; 00076 00077 snprintf(name,sizeof(name),"Zap/%d-1",num); 00078 return ast_get_channel_by_name_locked(name); 00079 }
static int load_module | ( | void | ) | [static] |
Definition at line 375 of file app_zapscan.c.
References ast_register_application(), and conf_exec().
00376 { 00377 return ast_register_application(app, conf_exec, synopsis, descrip); 00378 }
static int unload_module | ( | void | ) | [static] |
Definition at line 364 of file app_zapscan.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00365 { 00366 int res; 00367 00368 res = ast_unregister_application(app); 00369 00370 ast_module_user_hangup_all(); 00371 00372 return res; 00373 }
char* app = "ZapScan" [static] |
Definition at line 62 of file app_zapscan.c.
char* descrip [static] |
Initial value:
" ZapScan([group]) allows a call center manager to monitor Zap channels in\n" "a convenient way. Use '#' to select the next channel and use '*' to exit\n" "Limit scanning to a channel GROUP by setting the option group argument.\n"
Definition at line 66 of file app_zapscan.c.
Definition at line 64 of file app_zapscan.c.