#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel.h>
#include "asterisk.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"
Include dependency graph for app_zapscan.c:
Go to the source code of this file.
Defines | |
#define | CONF_SIZE 160 |
Functions | |
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) |
char * | description (void) |
Provides a description of the module. | |
static struct ast_channel * | get_zap_channel_locked (int num) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
int | load_module (void) |
Initialize the module. | |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static char * | app = "ZapScan" |
static char * | descrip |
LOCAL_USER_DECL | |
STANDARD_LOCAL_USER | |
static char * | synopsis = "Scan Zap channels to monitor calls" |
static char * | tdesc = "Scan Zap channels application" |
Definition in file app_zapscan.c.
|
Definition at line 77 of file app_zapscan.c. |
|
Definition at line 86 of file app_zapscan.c. References ast_log(), and LOG_WARNING. 00087 { 00088 int res; 00089 while(len) { 00090 res = write(fd, data, len); 00091 if (res < 1) { 00092 if (errno != EAGAIN) { 00093 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); 00094 return -1; 00095 } else 00096 return 0; 00097 } 00098 len -= res; 00099 data += res; 00100 } 00101 return 0; 00102 }
|
|
Definition at line 292 of file app_zapscan.c. References ast_channel::_state, ast_answer(), ast_channel_walk_locked(), AST_DIGIT_ANY, AST_FRAME_DTMF, ast_frfree(), ast_mutex_unlock(), ast_read(), ast_say_number(), AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_waitfor(), conf_run(), ast_frame::frametype, get_zap_channel_locked(), input(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, ast_channel::lock, ast_channel::name, pbx_builtin_getvar_helper(), ast_frame::subclass, ast_channel::type, and VERBOSE_PREFIX_3. 00293 { 00294 int res=-1; 00295 struct localuser *u; 00296 int confflags = 0; 00297 int confno = 0; 00298 char confstr[80] = "", *tmp = NULL; 00299 struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL; 00300 struct ast_frame *f; 00301 char *mygroup; 00302 char *desired_group; 00303 int input=0,search_group=0; 00304 00305 LOCAL_USER_ADD(u); 00306 00307 if (chan->_state != AST_STATE_UP) 00308 ast_answer(chan); 00309 00310 desired_group = ast_strdupa((char *) data); 00311 if(!ast_strlen_zero(desired_group)) { 00312 ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group); 00313 search_group = 1; 00314 } 00315 00316 for (;;) { 00317 if (ast_waitfor(chan, 100) < 0) 00318 break; 00319 00320 f = ast_read(chan); 00321 if (!f) 00322 break; 00323 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) { 00324 ast_frfree(f); 00325 break; 00326 } 00327 ast_frfree(f); 00328 ichan = NULL; 00329 if(input) { 00330 ichan = get_zap_channel_locked(input); 00331 input = 0; 00332 } 00333 00334 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan); 00335 00336 if ( !tempchan && !lastchan ) 00337 break; 00338 00339 if (tempchan && search_group) { 00340 if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) { 00341 ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group); 00342 } else { 00343 ast_mutex_unlock(&tempchan->lock); 00344 lastchan = tempchan; 00345 continue; 00346 } 00347 } 00348 if ( tempchan && tempchan->type && (!strcmp(tempchan->type, "Zap")) && (tempchan != chan) ) { 00349 ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name); 00350 ast_copy_string(confstr, tempchan->name, sizeof(confstr)); 00351 ast_mutex_unlock(&tempchan->lock); 00352 if ((tmp = strchr(confstr,'-'))) { 00353 *tmp = '\0'; 00354 } 00355 confno = atoi(strchr(confstr,'/') + 1); 00356 ast_stopstream(chan); 00357 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL); 00358 res = conf_run(chan, confno, confflags); 00359 if (res<0) break; 00360 input = res; 00361 } else if (tempchan) 00362 ast_mutex_unlock(&tempchan->lock); 00363 lastchan = tempchan; 00364 } 00365 LOCAL_USER_REMOVE(u); 00366 return res; 00367 }
|
|
Definition at line 104 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, ast_channel::fds, ast_frame::frametype, input(), LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_frame::subclass, ast_channel::type, and VERBOSE_PREFIX_3. 00105 { 00106 int fd; 00107 struct zt_confinfo ztc; 00108 struct ast_frame *f; 00109 struct ast_channel *c; 00110 struct ast_frame fr; 00111 int outfd; 00112 int ms; 00113 int nfds; 00114 int res; 00115 int flags; 00116 int retryzap; 00117 int origfd; 00118 int ret = -1; 00119 char input[4]; 00120 int ic=0; 00121 00122 ZT_BUFFERINFO bi; 00123 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; 00124 char *buf = __buf + AST_FRIENDLY_OFFSET; 00125 00126 /* Set it into U-law mode (write) */ 00127 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) { 00128 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name); 00129 goto outrun; 00130 } 00131 00132 /* Set it into U-law mode (read) */ 00133 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) { 00134 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name); 00135 goto outrun; 00136 } 00137 ast_indicate(chan, -1); 00138 retryzap = strcasecmp(chan->type, "Zap"); 00139 zapretry: 00140 origfd = chan->fds[0]; 00141 if (retryzap) { 00142 fd = open("/dev/zap/pseudo", O_RDWR); 00143 if (fd < 0) { 00144 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); 00145 goto outrun; 00146 } 00147 /* Make non-blocking */ 00148 flags = fcntl(fd, F_GETFL); 00149 if (flags < 0) { 00150 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); 00151 close(fd); 00152 goto outrun; 00153 } 00154 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { 00155 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); 00156 close(fd); 00157 goto outrun; 00158 } 00159 /* Setup buffering information */ 00160 memset(&bi, 0, sizeof(bi)); 00161 bi.bufsize = CONF_SIZE; 00162 bi.txbufpolicy = ZT_POLICY_IMMEDIATE; 00163 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; 00164 bi.numbufs = 4; 00165 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { 00166 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); 00167 close(fd); 00168 goto outrun; 00169 } 00170 nfds = 1; 00171 } else { 00172 /* XXX Make sure we're not running on a pseudo channel XXX */ 00173 fd = chan->fds[0]; 00174 nfds = 0; 00175 } 00176 memset(&ztc, 0, sizeof(ztc)); 00177 /* Check to see if we're in a conference... */ 00178 ztc.chan = 0; 00179 if (ioctl(fd, ZT_GETCONF, &ztc)) { 00180 ast_log(LOG_WARNING, "Error getting conference\n"); 00181 close(fd); 00182 goto outrun; 00183 } 00184 if (ztc.confmode) { 00185 /* Whoa, already in a conference... Retry... */ 00186 if (!retryzap) { 00187 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); 00188 retryzap = 1; 00189 goto zapretry; 00190 } 00191 } 00192 memset(&ztc, 0, sizeof(ztc)); 00193 /* Add us to the conference */ 00194 ztc.chan = 0; 00195 ztc.confno = confno; 00196 ztc.confmode = ZT_CONF_MONITORBOTH; 00197 00198 if (ioctl(fd, ZT_SETCONF, &ztc)) { 00199 ast_log(LOG_WARNING, "Error setting conference\n"); 00200 close(fd); 00201 goto outrun; 00202 } 00203 ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno); 00204 00205 for(;;) { 00206 outfd = -1; 00207 ms = -1; 00208 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); 00209 if (c) { 00210 if (c->fds[0] != origfd) { 00211 if (retryzap) { 00212 /* Kill old pseudo */ 00213 close(fd); 00214 } 00215 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); 00216 retryzap = 0; 00217 goto zapretry; 00218 } 00219 f = ast_read(c); 00220 if (!f) 00221 break; 00222 if(f->frametype == AST_FRAME_DTMF) { 00223 if(f->subclass == '#') { 00224 ret = 0; 00225 break; 00226 } 00227 else if (f->subclass == '*') { 00228 ret = -1; 00229 break; 00230 00231 } 00232 else { 00233 input[ic++] = f->subclass; 00234 } 00235 if(ic == 3) { 00236 input[ic++] = '\0'; 00237 ic=0; 00238 ret = atoi(input); 00239 ast_verbose(VERBOSE_PREFIX_3 "Zapscan: change channel to %d\n",ret); 00240 break; 00241 } 00242 } 00243 00244 if (fd != chan->fds[0]) { 00245 if (f->frametype == AST_FRAME_VOICE) { 00246 if (f->subclass == AST_FORMAT_ULAW) { 00247 /* Carefully write */ 00248 careful_write(fd, f->data, f->datalen); 00249 } else 00250 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass); 00251 } 00252 } 00253 ast_frfree(f); 00254 } else if (outfd > -1) { 00255 res = read(outfd, buf, CONF_SIZE); 00256 if (res > 0) { 00257 memset(&fr, 0, sizeof(fr)); 00258 fr.frametype = AST_FRAME_VOICE; 00259 fr.subclass = AST_FORMAT_ULAW; 00260 fr.datalen = res; 00261 fr.samples = res; 00262 fr.data = buf; 00263 fr.offset = AST_FRIENDLY_OFFSET; 00264 if (ast_write(chan, &fr) < 0) { 00265 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); 00266 /* break; */ 00267 } 00268 } else 00269 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); 00270 } 00271 } 00272 if (f) 00273 ast_frfree(f); 00274 if (fd != chan->fds[0]) 00275 close(fd); 00276 else { 00277 /* Take out of conference */ 00278 /* Add us to the conference */ 00279 ztc.chan = 0; 00280 ztc.confno = 0; 00281 ztc.confmode = 0; 00282 if (ioctl(fd, ZT_SETCONF, &ztc)) { 00283 ast_log(LOG_WARNING, "Error setting conference\n"); 00284 } 00285 } 00286 00287 outrun: 00288 00289 return ret; 00290 }
|
|
Provides a description of the module.
Definition at line 385 of file app_zapscan.c. References tdesc. 00386 { 00387 return tdesc; 00388 }
|
|
Definition at line 79 of file app_zapscan.c. References ast_get_channel_by_name_locked(), and name. Referenced by conf_exec(). 00079 { 00080 char name[80]; 00081 00082 snprintf(name,sizeof(name),"Zap/%d-1",num); 00083 return ast_get_channel_by_name_locked(name); 00084 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 397 of file app_zapscan.c. References ASTERISK_GPL_KEY. 00398 { 00399 return ASTERISK_GPL_KEY; 00400 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 380 of file app_zapscan.c. References app, ast_register_application(), conf_exec(), descrip, and synopsis. 00381 { 00382 return ast_register_application(app, conf_exec, synopsis, descrip); 00383 }
|
|
Cleanup all module structures, sockets, etc. This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).
Definition at line 369 of file app_zapscan.c. References app, ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS. 00370 { 00371 int res; 00372 00373 res = ast_unregister_application(app); 00374 00375 STANDARD_HANGUP_LOCALUSERS; 00376 00377 return res; 00378 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 390 of file app_zapscan.c. References STANDARD_USECOUNT. 00391 { 00392 int res; 00393 STANDARD_USECOUNT(res); 00394 return res; 00395 }
|
|
Definition at line 63 of file app_zapscan.c. |
|
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 67 of file app_zapscan.c. |
|
Definition at line 74 of file app_zapscan.c. |
|
Definition at line 72 of file app_zapscan.c. |
|
Definition at line 65 of file app_zapscan.c. |
|
Definition at line 61 of file app_zapscan.c. |