static int checkMax(struct ast_channel *chan, struct roomdetails *dtmfmatch) { int res=0; struct ast_app *app; char getvar[30]="AstVar"; char roomno[30]=""; char maxusers[30]=""; char currentusers[30]=""; char prompt[50]=""; char arg[255]=""; strcpy(maxusers,dtmfmatch->maxusers); strcpy(roomno,dtmfmatch->roomno); strcat(arg,roomno); strcat(arg,","); strcat(arg,getvar); if(!(app = pbx_findapp(ConfAppCount))) { ast_log(LOG_WARNING, "Invalid participant count application: %s\n", ConfAppCount); return -1; } res = pbx_exec(chan, app, arg); strcpy(currentusers, pbx_builtin_getvar_helper(chan, getvar)); if(atoi(currentusers) < atoi(maxusers)){ ast_log(LOG_NOTICE, "Currentusers: %i\n", atoi(currentusers)); if(atoi(currentusers)>0){ strcpy(prompt,"conf-thereare"); if (!ast_streamfile(chan, "conf-thereare", chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); if (!ast_say_number(chan, (atoi(currentusers)), AST_DIGIT_ANY, chan->language, (char *) NULL)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } if (!ast_streamfile(chan, "conf-otherinparty", chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } } } res=1; } else{ ast_log(LOG_NOTICE, "Maximum users exeeded, Current users in room: %s\n",currentusers); strcpy(prompt, "conf-locked"); if (!ast_streamfile(chan, prompt, chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } res=-1; } return res; }
int getConf(struct ast_channel *chan, struct userkeyin dtmfinput, struct roomdetails *dtmfmatch) { char *prompt; /* char *invalid;*/ int res=0, retry=0, skip=0; if (ast_strlen_zero(dtmfinput.inroom)){ strcpy(dtmfinput.inroom, ""); } else { skip = 1; retry = 2; } while (retry++ < 3){ if(!skip){ prompt = "conf-getconfno"; if(ast_app_getdata(chan, prompt, dtmfinput.inroom, sizeof(dtmfinput.inroom) - 2, 0) < 0) return -1; res = ast_waitstream(chan,""); } res = roomQuery(dtmfinput, dtmfmatch); if(res==1 || res==2) break; if(res == -2){ prompt = "conf-has-not-started"; if (!ast_streamfile(chan, prompt, chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } res = -1; break; } prompt = "conf-invalid"; if (!ast_streamfile(chan, prompt, chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } } if(retry>=2 && (res < 1 && !skip)){ prompt = "vm-goodbye"; if (!ast_streamfile(chan, prompt, chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } res = -1; } return res; }
int getPass(struct ast_channel *chan, struct userkeyin dtmfinput, struct roomdetails *dtmfmatch) { char *prompt; /* char *invalid; */ int res = 0, retry=0; prompt = "agent-pass"; if(ast_app_getdata(chan, prompt, dtmfinput.inpass, sizeof(dtmfinput.inpass) - 2, 0) < 0) return -1; res = ast_waitstream(chan,""); res = passQuery(dtmfinput, dtmfmatch); while (retry++ < 2 && res !=1){ prompt = "auth-incorrect"; if(ast_app_getdata(chan, prompt, dtmfinput.inpass, sizeof(dtmfinput.inpass) - 2, 0) < 0) return -1; res = ast_waitstream(chan,""); res = passQuery(dtmfinput, dtmfmatch); if(res==1) break; } if(retry>1 && res != 1){ prompt = "vm-goodbye"; if (!ast_streamfile(chan, prompt, chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } res = -1; } return res; }
static int play_and_wait(struct ast_channel *chan, char *file, char *digits) { int res = -1; if (!ast_streamfile(chan, file, chan->language)) { res = ast_waitstream(chan, digits); } return res; }
int ast_play_and_wait(struct ast_channel *chan, char *fn) { int d; d = ast_streamfile(chan, fn, chan->language); if (d) return d; d = ast_waitstream(chan, AST_DIGIT_ANY); ast_stopstream(chan); return d; }
static int saywords(struct ast_channel *chan, char *word1, char *word2, char *word5, int num) { /* Put this in a separate proc because it's bound to change */ int d = 0; if (num > 0) { if (num % 1000 == 1) { ast_streamfile(chan, word1, chan->language); d = ast_waitstream(chan,""); } else if (((num % 10) >= 2) && ((num % 10) <= 4 ) && ((num % 100) < 10 || (num % 100) > 20)) { ast_streamfile(chan, word2, chan->language); d = ast_waitstream(chan, ""); } else { ast_streamfile(chan, word5, chan->language); d = ast_waitstream(chan, ""); } } return d; }
static int s_streamwait3(const say_args_t *a, const char *fn) { int res = ast_streamfile(a->chan, fn, a->language); if (res) { ast_log(LOG_WARNING, "Unable to play message %s\n", fn); return res; } res = (a->audiofd > -1 && a->ctrlfd > -1) ? ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) : ast_waitstream(a->chan, a->ints); ast_stopstream(a->chan); return res; }
static int _play_file(struct ast_channel* chan, char* filename) { int res; ast_stopstream(chan); res = ast_streamfile(chan, filename, chan->language); if(!res) res = ast_waitstream(chan, AST_DIGIT_ANY); else res = 0; ast_stopstream(chan); return res; }
int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd) { int res,to,fto; if (prompt) { res = ast_streamfile(c, prompt, c->language); if (res < 0) return res; } fto = 6000; to = 2000; if (timeout > 0) fto = to = timeout; if (timeout < 0) fto = to = 1000000000; res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd); return res; }
/* set timeout to 0 for "standard" timeouts. Set timeout to -1 for "ludicrous time" (essentially never times out) */ int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout) { int res,to,fto; /* XXX Merge with full version? XXX */ if (maxlen) s[0] = '\0'; if (prompt) { res = ast_streamfile(c, prompt, c->language); if (res < 0) return res; } fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000; to = c->pbx ? c->pbx->dtimeout * 1000 : 2000; if (timeout > 0) fto = to = timeout; if (timeout < 0) fto = to = 1000000000; res = ast_readstring(c, s, maxlen, to, fto, "#"); return res; }
static int enterConf(struct ast_channel *chan, struct roomdetails *dtmfmatch) { int res=0; /* char *prompt; */ char prompt[50]=""; struct ast_app *app; char arg2[255]=""; char roomno2[80]=""; char roomtype2[30]=""; char recordfile[100]="conf-recordings/"; strcpy(roomno2,dtmfmatch->roomno); strcpy(roomtype2,dtmfmatch->roomtype); strcpy(arg2, roomno2); strcat(arg2, ","); strcat(arg2, roomtype2); strcat(arg2, ","); strcat(recordfile, dtmfmatch->roomno); strcat(recordfile, "-"); strcat(recordfile, dtmfmatch->bookid); ast_log(LOG_NOTICE, "Roomtype: %s\n", arg2); pbx_builtin_setvar_helper(chan, "MEETME_RECORDINGFILE", recordfile); if(strchr(dtmfmatch->aFlags, 'r')) { strcpy(prompt,"conf-call-recorded"); if (!ast_streamfile(chan, prompt, chan->language)){ res = ast_waitstream(chan,""); ast_stopstream(chan); } } if(!(app=pbx_findapp(ConfApp))){ ast_log(LOG_WARNING, "Invalid conferencing application: %s\n", ConfApp); return -1; } res = pbx_exec(chan, app, arg2); return 1; }
static int page_exec(struct ast_channel *chan, void *data) { struct ast_module_user *u; char *options, *tech, *resource, *tmp; char meetmeopts[88], originator[AST_CHANNEL_NAME]; struct ast_flags flags = { 0 }; unsigned int confid = ast_random(); struct ast_app *app; int res = 0, pos = 0, i = 0; struct ast_dial *dials[MAX_DIALS]; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n"); return -1; } u = ast_module_user_add(chan); if (!(app = pbx_findapp("MeetMe"))) { ast_log(LOG_WARNING, "There is no MeetMe application available!\n"); ast_module_user_remove(u); return -1; }; options = ast_strdupa(data); ast_copy_string(originator, chan->name, sizeof(originator)); if ((tmp = strchr(originator, '-'))) *tmp = '\0'; tmp = strsep(&options, "|"); if (options) ast_app_parse_options(page_opts, &flags, NULL, options); snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe|%ud|%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"), (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") ); /* Go through parsing/calling each device */ while ((tech = strsep(&tmp, "&"))) { struct ast_dial *dial = NULL; /* don't call the originating device */ if (!strcasecmp(tech, originator)) continue; /* If no resource is available, continue on */ if (!(resource = strchr(tech, '/'))) { ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech); continue; } *resource++ = '\0'; /* Create a dialing structure */ if (!(dial = ast_dial_create())) { ast_log(LOG_WARNING, "Failed to create dialing structure.\n"); continue; } /* Append technology and resource */ ast_dial_append(dial, tech, resource); /* Set ANSWER_EXEC as global option */ ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts); /* Run this dial in async mode */ ast_dial_run(dial, chan, 1); /* Put in our dialing array */ dials[pos++] = dial; } if (!ast_test_flag(&flags, PAGE_QUIET)) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); } if (!res) { snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"), (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") ); pbx_exec(chan, app, meetmeopts); } /* Go through each dial attempt cancelling, joining, and destroying */ for (i = 0; i < pos; i++) { struct ast_dial *dial = dials[i]; /* We have to wait for the async thread to exit as it's possible Meetme won't throw them out immediately */ ast_dial_join(dial); /* Hangup all channels */ ast_dial_hangup(dial); /* Destroy dialing structure */ ast_dial_destroy(dial); } ast_module_user_remove(u); return -1; }
/* play name of mailbox owner. * returns: -1 for bad or missing extension * '1' for selected entry from directory * '*' for skipped entry from directory */ static int play_mailbox_owner(struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name, int fromappvm) { int res = 0; int loop = 3; char fn[256]; char fn2[256]; /* Check for the VoiceMail2 greeting first */ snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet", (char *)ast_config_AST_SPOOL_DIR, context, ext); #ifdef USE_ODBC_STORAGE retrieve_file(fn); #endif /* Otherwise, check for an old-style Voicemail greeting */ snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet", (char *)ast_config_AST_SPOOL_DIR, ext); #ifdef USE_ODBC_STORAGE retrieve_file(fn2); #endif if (ast_fileexists(fn, NULL, chan->language) > 0) { res = ast_streamfile(chan, fn, chan->language); if (!res) { res = ast_waitstream(chan, AST_DIGIT_ANY); } ast_stopstream(chan); } else if (ast_fileexists(fn2, NULL, chan->language) > 0) { res = ast_streamfile(chan, fn2, chan->language); if (!res) { res = ast_waitstream(chan, AST_DIGIT_ANY); } ast_stopstream(chan); } else { res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext, AST_DIGIT_ANY, chan->language); } #ifdef USE_ODBC_STORAGE ast_filedelete(fn, NULL); ast_filedelete(fn2, NULL); #endif while (loop) { if (!res) { res = ast_streamfile(chan, "dir-instr", chan->language); } if (!res) { res = ast_waitstream(chan, AST_DIGIT_ANY); } if (!res) { res = ast_waitfordigit(chan, 3000); } ast_stopstream(chan); if (res > -1) { switch (res) { case '1': /* Name selected */ loop = 0; if (fromappvm) { /* We still want to set the exten */ ast_copy_string(chan->exten, ext, sizeof(chan->exten)); } else { if (ast_goto_if_exists(chan, dialcontext, ext, 1)) { ast_log(LOG_WARNING, "Can't find extension '%s' in context '%s'. " "Did you pass the wrong context to Directory?\n", ext, dialcontext); res = -1; } } break; case '*': /* Skip to next match in list */ loop = 0; break; default: /* Not '1', or '*', so decrement number of tries */ res = 0; loop--; break; } /* end switch */ } /* end if */ else { /* User hungup, so jump out now */ loop = 0; } } /* end while */ return(res); }
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm) { /* Read in the first three digits.. "digit" is the first digit, already read */ char ext[NUMDIGITS + 1], *cat; char name[80] = ""; struct ast_variable *v; int res; int found=0; int lastuserchoice = 0; char *start, *conv, *stringp = NULL; const char *pos; int breakout = 0; if (ast_strlen_zero(context)) { ast_log(LOG_WARNING, "Directory must be called with an argument " "(context in which to interpret extensions)\n"); return -1; } if (digit == '0') { if (!ast_goto_if_exists(chan, dialcontext, "o", 1) || (!ast_strlen_zero(chan->macrocontext) && !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) { return 0; } else { ast_log(LOG_WARNING, "Can't find extension 'o' in current context. " "Not Exiting the Directory!\n"); res = 0; } } if (digit == '*') { if (!ast_goto_if_exists(chan, dialcontext, "a", 1) || (!ast_strlen_zero(chan->macrocontext) && !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) { return 0; } else { ast_log(LOG_WARNING, "Can't find extension 'a' in current context. " "Not Exiting the Directory!\n"); res = 0; } } memset(ext, 0, sizeof(ext)); ext[0] = digit; res = 0; if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; if (!res) { /* Search for all names which start with those digits */ v = ast_variable_browse(cfg, context); while(v && !res) { /* Find all candidate extensions */ while(v) { /* Find a candidate extension */ start = strdup(v->value); if (start && !strcasestr(start, "hidefromdir=yes")) { stringp=start; strsep(&stringp, ","); pos = strsep(&stringp, ","); if (pos) { ast_copy_string(name, pos, sizeof(name)); /* Grab the last name */ if (last && strrchr(pos,' ')) pos = strrchr(pos, ' ') + 1; conv = convert(pos); if (conv) { if (!strncmp(conv, ext, strlen(ext))) { /* Match! */ found++; free(conv); free(start); break; } free(conv); } } free(start); } v = v->next; } if (v) { /* We have a match -- play a greeting if they have it */ res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm); switch (res) { case -1: /* user pressed '1' but extension does not exist, or * user hungup */ lastuserchoice = 0; break; case '1': /* user pressed '1' and extensions exists; play_mailbox_owner will already have done a goto() on the channel */ lastuserchoice = res; break; case '*': /* user pressed '*' to skip something found */ lastuserchoice = res; res = 0; break; default: break; } v = v->next; } } if (!res && ucfg) { /* Search users.conf for all names which start with those digits */ for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) { if (!strcasecmp(cat, "general")) continue; if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory"))) continue; /* Find all candidate extensions */ if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) { ast_copy_string(name, pos, sizeof(name)); /* Grab the last name */ if (last && strrchr(pos,' ')) pos = strrchr(pos, ' ') + 1; conv = convert(pos); if (conv) { if (!strcmp(conv, ext)) { /* Match! */ found++; /* We have a match -- play a greeting if they have it */ res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm); switch (res) { case -1: /* user pressed '1' but extension does not exist, or * user hungup */ lastuserchoice = 0; breakout = 1; break; case '1': /* user pressed '1' and extensions exists; play_mailbox_owner will already have done a goto() on the channel */ lastuserchoice = res; breakout = 1; break; case '*': /* user pressed '*' to skip something found */ lastuserchoice = res; breakout = 0; res = 0; break; default: breakout = 1; break; } free(conv); if (breakout) break; } else free(conv); } } } } if (lastuserchoice != '1') { res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language); if (!res) res = 1; return res; } return 0; } return res; }
static void *dialstring(void *string) { struct ast_channel *channel; char *bufptr,*destptr; int ms=10000; /* ms affects number of rings */ int cnt=0,first; char tech[256]; char tele[256]; char filename[256]; int answered=0; for(first=0, bufptr=(char *)string, destptr=tech; *bufptr&&cnt<256; cnt++){ if(*bufptr=='/' && !first) { *destptr=0; destptr=tele; first=1; } else if(*bufptr==',') { *destptr=0; destptr=filename; } else { *destptr=*bufptr; destptr++; } bufptr++; } *destptr=0; ast_log(LOG_DEBUG, "Printing string arg: %s Eos\n", (char *)string); if(strlen(tech)+strlen(tele)+strlen(filename) > 256) { ast_log(LOG_ERROR, "Autodial:Error string too long\n"); free(string); pthread_exit(NULL); } ast_log(LOG_DEBUG, "Autodial Tech %s(%d) Tele %s(%d) Filename %s(%d)\n",tech, (int)strlen(tech), tele, (int)strlen(tele), filename, (int)strlen(filename)); channel=ast_request(tech,AST_FORMAT_SLINEAR,tele); if(channel!=NULL){ ast_call(channel,tele,10000); } else { ast_log(LOG_ERROR, "Autodial:Sorry unable to obtain channel\n"); free(string); pthread_exit(NULL); } if(channel->_state==AST_STATE_UP) ast_log(LOG_DEBUG, "Autodial:Line is Up\n"); while(ms>0){ struct ast_frame *f; ms=ast_waitfor(channel,ms); f=ast_read(channel); if(!f){ ast_log(LOG_DEBUG, "Autodial:Hung Up\n"); break; } if (f->frametype==AST_FRAME_CONTROL) { if (f->subclass==AST_CONTROL_ANSWER) { ast_log(LOG_DEBUG, "Autodial:Phone Answered\n"); if (channel->_state==AST_STATE_UP) { char res; ast_streamfile(channel,filename,0); /* Press Five for snooze */ res=ast_waitstream(channel, "37"); if(res=='3'){ answered=1; set_snooze_alarm((char *)string,60); ast_streamfile(channel,"demo-thanks",0); ast_waitstream(channel, ""); } else if(res=='7'){ answered=1; ast_streamfile(channel,"demo-thanks",0); ast_waitstream(channel, ""); } ast_stopstream(channel); ms=0; } } else if (f->subclass==AST_CONTROL_RINGING) ast_log(LOG_DEBUG, "Autodial:Phone Ringing end\n"); } ast_frfree(f); } if(!answered) set_snooze_alarm((char *) string, 5); free(string); ast_hangup(channel); ast_log(LOG_DEBUG, "Autodial:Hung up channel\n"); pthread_exit(NULL); return NULL; }
static int auth_exec(struct ast_channel *chan, void *data) { int res=0; int retries; struct localuser *u; char password[256]=""; char passwd[256]; char *opts; char *prompt; if (!data || ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n"); return -1; } LOCAL_USER_ADD(u); if (chan->_state != AST_STATE_UP) { res = ast_answer(chan); if (res) { LOCAL_USER_REMOVE(u); return -1; } } strncpy(password, data, sizeof(password) - 1); opts=strchr(password, '|'); if (opts) { *opts = 0; opts++; } else opts = ""; /* Start asking for password */ prompt = "agent-pass"; for (retries = 0; retries < 3; retries++) { res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0); if (res < 0) break; res = 0; if (password[0] == '/') { if (strchr(opts, 'd')) { char tmp[256]; /* Compare against a database key */ if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) { /* It's a good password */ if (strchr(opts, 'r')) { ast_db_del(password + 1, passwd); } break; } } else { /* Compare against a file */ FILE *f; f = fopen(password, "r"); if (f) { char buf[256] = ""; while(!feof(f)) { fgets(buf, sizeof(buf), f); if (!feof(f) && !ast_strlen_zero(buf)) { buf[strlen(buf) - 1] = '\0'; if (!ast_strlen_zero(buf) && !strcmp(passwd, buf)) break; } } fclose(f); if (!ast_strlen_zero(buf) && !strcmp(passwd, buf)) break; } else ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno)); } } else { /* Compare against a fixed password */ if (!strcmp(passwd, password)) break; } prompt="auth-incorrect"; } if ((retries < 3) && !res) { if (strchr(opts, 'a')) ast_cdr_setaccount(chan, passwd); res = ast_streamfile(chan, "auth-thankyou", chan->language); if (!res) res = ast_waitstream(chan, ""); } else { if (!res) res = ast_streamfile(chan, "vm-goodbye", chan->language); if (!res) res = ast_waitstream(chan, ""); res = -1; } LOCAL_USER_REMOVE(u); return res; }
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *spec, const char *exten, const char *context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct chanspy_ds chanspy_ds = { 0, }; ast_mutex_init(&chanspy_ds.lock); snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; struct ast_channel *prev = NULL, *peer = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); peer_chanspy_ds; chanspy_ds_free(peer_chanspy_ds), prev = peer, peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { const char *group; int igrp = !mygroup; char *groups[25]; int num_groups = 0; char dup_group[512]; int x; char *s; peer = peer_chanspy_ds->chan; ast_mutex_unlock(&peer_chanspy_ds->lock); if (peer == prev) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_check_hangup(chan)) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { ast_channel_unlock(peer); continue; } if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { ast_channel_unlock(peer); continue; } if (mygroup) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0])); } for (x = 0; x < num_groups; x++) { if (!strcmp(mygroup, groups[x])) { igrp = 1; break; } } } if (!igrp) { ast_channel_unlock(peer); continue; } strcpy(peer_name, "spy-"); strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) *s = tolower(*s); /* We have to unlock the peer channel here to avoid a deadlock. * So, when we need to dereference it again, we have to lock the * datastore and get the pointer from there to see if the channel * is still valid. */ ast_channel_unlock(peer); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) { chanspy_ds_free(peer_chanspy_ds); break; } } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags); num_spyed_upon++; if (res == -1) { chanspy_ds_free(peer_chanspy_ds); break; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); } else { /* stay on this channel, if it is still valid */ ast_mutex_lock(&peer_chanspy_ds->lock); if (peer_chanspy_ds->chan) { ast_channel_lock(peer_chanspy_ds->chan); next_chanspy_ds = peer_chanspy_ds; peer_chanspy_ds = NULL; } else { /* the channel is gone */ ast_mutex_unlock(&peer_chanspy_ds->lock); next_chanspy_ds = NULL; } } peer = NULL; } } if (res == -1 || ast_check_hangup(chan)) break; } ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ast_mutex_lock(&chanspy_ds.lock); ast_mutex_unlock(&chanspy_ds.lock); ast_mutex_destroy(&chanspy_ds.lock); return res; }
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence) { int d = 0; char *fmts; char comment[256]; int x, fmtcnt=1, res=-1,outmsg=0; struct ast_frame *f; struct ast_filestream *others[MAX_OTHER_FORMATS]; struct ast_filestream *realfiles[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; char *stringp=NULL; time_t start, end; struct ast_dsp *sildet; /* silence detector dsp */ int totalsilence = 0; int dspsilence = 0; int gotsilence = 0; /* did we timeout for silence? */ int rfmt=0; char prependfile[80]; if (silencethreshold < 0) silencethreshold = global_silence_threshold; if (maxsilence < 0) maxsilence = global_maxsilence; /* barf if no pointer passed to store duration in */ if (duration == NULL) { ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n"); return -1; } ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt); snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name); if (playfile || beep) { if (!beep) d = ast_play_and_wait(chan, playfile); if (d > -1) d = ast_streamfile(chan, "beep",chan->language); if (!d) d = ast_waitstream(chan,""); if (d < 0) return -1; } strncpy(prependfile, recordfile, sizeof(prependfile) -1); strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1); fmts = ast_strdupa(fmt); stringp=fmts; strsep(&stringp, "|"); ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = ast_strdupa(fmts); while((fmt = strsep(&stringp, "|"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; } sfmt[fmtcnt++] = ast_strdupa(fmt); } time(&start); end=start; /* pre-initialize end to be same as start in case we never get into loop */ for (x=0; x<fmtcnt; x++) { others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700); ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]); if (!others[x]) { break; } } sildet = ast_dsp_new(); /* Create the silence detector */ if (!sildet) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } ast_dsp_set_threshold(sildet, silencethreshold); if (maxsilence > 0) { rfmt = chan->readformat; res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); return -1; } } if (x == fmtcnt) { /* Loop forever, writing the packets we read to the writer(s), until we read a # or get a hangup */ f = NULL; for(;;) { res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_DEBUG, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = ast_read(chan); if (!f) break; if (f->frametype == AST_FRAME_VOICE) { /* write each format */ for (x=0; x<fmtcnt; x++) { if (!others[x]) break; res = ast_writestream(others[x], f); } /* Silence Detection */ if (maxsilence > 0) { dspsilence = 0; ast_dsp_silence(sildet, f, &dspsilence); if (dspsilence) totalsilence = dspsilence; else totalsilence = 0; if (totalsilence > maxsilence) { /* Ended happily with silence */ if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); ast_frfree(f); gotsilence = 1; outmsg=2; break; } } /* Exit on any error */ if (res) { ast_log(LOG_WARNING, "Error writing frame\n"); ast_frfree(f); break; } } else if (f->frametype == AST_FRAME_VIDEO) { /* Write only once */ ast_writestream(others[0], f); } else if (f->frametype == AST_FRAME_DTMF) { /* stop recording with any digit */ if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); res = 't'; outmsg = 2; ast_frfree(f); break; } if (maxtime) { time(&end); if (maxtime < (end - start)) { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); res = 't'; outmsg=2; ast_frfree(f); break; } } ast_frfree(f); } if (end == start) time(&end); if (!f) { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "User hung up\n"); res = -1; outmsg=1; #if 0 /* delete all the prepend files */ for (x=0; x<fmtcnt; x++) { if (!others[x]) break; ast_closestream(others[x]); ast_filedelete(prependfile, sfmt[x]); } #endif } } else { ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]); } *duration = end - start; #if 0 if (outmsg > 1) { #else if (outmsg) { #endif struct ast_frame *fr; for (x=0; x<fmtcnt; x++) { snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]); realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0); if (!others[x] || !realfiles[x]) break; if (totalsilence) ast_stream_rewind(others[x], totalsilence-200); else ast_stream_rewind(others[x], 200); ast_truncstream(others[x]); /* add the original file too */ while ((fr = ast_readframe(realfiles[x]))) { ast_writestream(others[x],fr); } ast_closestream(others[x]); ast_closestream(realfiles[x]); ast_filerename(prependfile, recordfile, sfmt[x]); #if 0 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile); #endif ast_filedelete(prependfile, sfmt[x]); } } if (rfmt) { if (ast_set_read_format(chan, rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name); } } if (outmsg) { if (outmsg > 1) { /* Let them know it worked */ ast_streamfile(chan, "auth-thankyou", chan->language); ast_waitstream(chan, ""); } } return res; } int ast_lock_path(const char *path) { char *s; char *fs; int res; int fd; time_t start; s = alloca(strlen(path) + 10); fs = alloca(strlen(path) + 20); if (!fs || !s) { ast_log(LOG_WARNING, "Out of memory!\n"); return -1; } snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand()); fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) { fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno)); return -1; } close(fd); snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock"); time(&start); while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) usleep(1); if (res < 0) { ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno)); } unlink(fs); ast_log(LOG_DEBUG, "Locked path '%s'\n", path); return res; }
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct chanspy_ds chanspy_ds; if (ast_test_flag(flags, OPTION_EXIT)) { const char *c; if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) ast_copy_string(exitcontext, c, sizeof(exitcontext)); else if (!ast_strlen_zero(chan->macrocontext)) ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); else ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); } ast_mutex_init(&chanspy_ds.lock); snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; struct ast_channel *prev = NULL, *peer = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); peer_chanspy_ds; chanspy_ds_free(peer_chanspy_ds), prev = peer, peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { const char *group; int igrp = !mygroup; char *groups[25]; int num_groups = 0; char dup_group[512]; int x; char *s; char *buffer; char *end; char *ext; char *form_enforced; int ienf = !myenforced; peer = peer_chanspy_ds->chan; ast_mutex_unlock(&peer_chanspy_ds->lock); if (peer == prev) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_check_hangup(chan)) { ast_channel_unlock(peer); chanspy_ds_free(peer_chanspy_ds); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { ast_channel_unlock(peer); continue; } if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { ast_channel_unlock(peer); continue; } if (mygroup) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, ARRAY_LEN(groups)); } for (x = 0; x < num_groups; x++) { if (!strcmp(mygroup, groups[x])) { igrp = 1; break; } } } if (!igrp) { ast_channel_unlock(peer); continue; } if (myenforced) { /* We don't need to allocate more space than just the length of (peer->name) for ext as we will cut the channel name's ending before copying into ext */ ext = alloca(strlen(peer->name)); form_enforced = alloca(strlen(myenforced) + 3); strcpy(form_enforced, ":"); strcat(form_enforced, myenforced); strcat(form_enforced, ":"); buffer = ast_strdupa(peer->name); if ((end = strchr(buffer, '-'))) { *end++ = ':'; *end = '\0'; } strcpy(ext, ":"); strcat(ext, buffer); if (strcasestr(form_enforced, ext)) ienf = 1; } if (!ienf) continue; strcpy(peer_name, "spy-"); strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; for (s = peer_name; s < ptr; s++) *s = tolower(*s); /* We have to unlock the peer channel here to avoid a deadlock. * So, when we need to dereference it again, we have to lock the * datastore and get the pointer from there to see if the channel * is still valid. */ ast_channel_unlock(peer); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) { chanspy_ds_free(peer_chanspy_ds); break; } } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); num_spyed_upon++; if (res == -1) { chanspy_ds_free(peer_chanspy_ds); goto exit; } else if (res == -2) { res = 0; chanspy_ds_free(peer_chanspy_ds); goto exit; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); } else { /* stay on this channel, if it is still valid */ ast_mutex_lock(&peer_chanspy_ds->lock); if (peer_chanspy_ds->chan) { ast_channel_lock(peer_chanspy_ds->chan); next_chanspy_ds = peer_chanspy_ds; peer_chanspy_ds = NULL; } else { /* the channel is gone */ ast_mutex_unlock(&peer_chanspy_ds->lock); next_chanspy_ds = NULL; } } peer = NULL; } } if (res == -1 || ast_check_hangup(chan)) break; } exit: ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ast_mutex_lock(&chanspy_ds.lock); ast_mutex_unlock(&chanspy_ds.lock); ast_mutex_destroy(&chanspy_ds.lock); return res; }
static int directory_exec(struct ast_channel *chan, void *data) { int res = 0; struct localuser *u; struct ast_config *cfg; int last = 1; int fromappvm = 0; char *context, *dialcontext, *dirintro, *options; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n"); return -1; } LOCAL_USER_ADD(u); context = ast_strdupa(data); dialcontext = strchr(context, '|'); if (dialcontext) { *dialcontext = '\0'; dialcontext++; options = strchr(dialcontext, '|'); if (options) { *options = '\0'; options++; if (strchr(options, 'f')) last = 0; if (strchr(options, 'v')) fromappvm = 1; } } else dialcontext = context; cfg = realtime_directory(context); if (!cfg) { LOCAL_USER_REMOVE(u); return -1; } dirintro = ast_variable_retrieve(cfg, context, "directoryintro"); if (ast_strlen_zero(dirintro)) dirintro = ast_variable_retrieve(cfg, "general", "directoryintro"); if (ast_strlen_zero(dirintro)) { if (last) dirintro = "dir-intro"; else dirintro = "dir-intro-fn"; } if (chan->_state != AST_STATE_UP) res = ast_answer(chan); for (;;) { if (!res) res = ast_streamfile(chan, dirintro, chan->language); if (!res) res = ast_waitstream(chan, AST_DIGIT_ANY); ast_stopstream(chan); if (!res) res = ast_waitfordigit(chan, 5000); if (res > 0) { res = do_directory(chan, cfg, context, dialcontext, res, last, fromappvm); if (res > 0) { res = ast_waitstream(chan, AST_DIGIT_ANY); ast_stopstream(chan); if (res >= 0) { continue; } } } break; } ast_config_destroy(cfg); LOCAL_USER_REMOVE(u); return res; }
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags) { struct ast_conference *prev=NULL, *cur; struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user)); int fd; struct zt_confinfo ztc; struct ast_frame *f; struct ast_channel *c; struct ast_frame fr; int outfd; int ms; int nfds; int res; int flags; int retryzap; int origfd; int musiconhold = 0; int firstpass = 0; int origquiet; int ret = -1; int x; int menu_active = 0; int using_pseudo = 0; struct ast_app *app; char *agifile; char *agifiledefault = "conf-background.agi"; char meetmesecs[30] = ""; char exitcontext[AST_MAX_EXTENSION] = ""; int dtmf; ZT_BUFFERINFO bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; if (!user) { ast_log(LOG_ERROR, "Out of memory\n"); return(ret); } memset(user, 0, sizeof(struct ast_conf_user)); user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */ time(&user->jointime); if (conf->locked) { /* Sorry, but this confernce is locked! */ if (!ast_streamfile(chan, "conf-locked", chan->language)) ast_waitstream(chan, ""); goto outrun; } conf->users++; if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers++; ast_mutex_lock(&conflock); if (conf->firstuser == NULL) { /* Fill the first new User struct */ user->user_no = 1; user->nextuser = NULL; user->prevuser = NULL; conf->firstuser = user; conf->lastuser = user; } else { /* Fill the new user struct */ user->user_no = conf->lastuser->user_no + 1; user->prevuser = conf->lastuser; user->nextuser = NULL; if (conf->lastuser->nextuser != NULL) { ast_log(LOG_WARNING, "Error in User Management!\n"); ast_mutex_unlock(&conflock); goto outrun; } else { conf->lastuser->nextuser = user; conf->lastuser = user; } } user->chan = chan; user->userflags = confflags; user->adminflags = 0; ast_mutex_unlock(&conflock); origquiet = confflags & CONFFLAG_QUIET; if (confflags & CONFFLAG_EXIT_CONTEXT) { if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) strncpy(exitcontext, agifile, sizeof(exitcontext) - 1); else if (!ast_strlen_zero(chan->macrocontext)) strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1); else strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1); } while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers == 0)) { confflags &= ~CONFFLAG_QUIET; confflags |= origquiet; /* XXX Announce that we're waiting on the conference lead to join */ if (!(confflags & CONFFLAG_QUIET)) { res = ast_streamfile(chan, "vm-dialout", chan->language); if (!res) res = ast_waitstream(chan, ""); } else res = 0; /* If we're waiting with hold music, set to silent mode */ if (!res) { confflags |= CONFFLAG_QUIET; ast_moh_start(chan, NULL); res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf); ast_moh_stop(chan); } if (res < 0) { ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name); goto outrun; } } if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) { if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) { if (ast_waitstream(chan, "") < 0) goto outrun; } else goto outrun; } /* Set it into linear mode (write) */ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); goto outrun; } /* Set it into linear mode (read) */ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); goto outrun; } ast_indicate(chan, -1); retryzap = strcasecmp(chan->type, "Zap"); zapretry: origfd = chan->fds[0]; if (retryzap) { fd = open("/dev/zap/pseudo", O_RDWR); if (fd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); goto outrun; } using_pseudo = 1; /* Make non-blocking */ flags = fcntl(fd, F_GETFL); if (flags < 0) { ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); close(fd); goto outrun; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); close(fd); goto outrun; } /* Setup buffering information */ memset(&bi, 0, sizeof(bi)); bi.bufsize = CONF_SIZE/2; bi.txbufpolicy = ZT_POLICY_IMMEDIATE; bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; bi.numbufs = 4; if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); close(fd); goto outrun; } x = 1; if (ioctl(fd, ZT_SETLINEAR, &x)) { ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); close(fd); goto outrun; } nfds = 1; } else { /* XXX Make sure we're not running on a pseudo channel XXX */ fd = chan->fds[0]; nfds = 0; } memset(&ztc, 0, sizeof(ztc)); /* Check to see if we're in a conference... */ ztc.chan = 0; if (ioctl(fd, ZT_GETCONF, &ztc)) { ast_log(LOG_WARNING, "Error getting conference\n"); close(fd); goto outrun; } if (ztc.confmode) { /* Whoa, already in a conference... Retry... */ if (!retryzap) { ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); retryzap = 1; goto zapretry; } } memset(&ztc, 0, sizeof(ztc)); /* Add us to the conference */ ztc.chan = 0; ztc.confno = conf->zapconf; if (confflags & CONFFLAG_MONITOR) ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; else if (confflags & CONFFLAG_TALKER) ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; else ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); close(fd); goto outrun; } ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf); manager_event(EVENT_FLAG_CALL, "MeetmeJoin", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" "Usernum: %i\r\n", chan->name, chan->uniqueid, conf->confno, user->user_no); if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { firstpass = 1; if (!(confflags & CONFFLAG_QUIET)) conf_play(conf, ENTER); } if (confflags & CONFFLAG_AGI) { /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) or use default filename of conf-background.agi */ agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND"); if (!agifile) agifile = agifiledefault; if (!strcasecmp(chan->type,"Zap")) { /* Set CONFMUTE mode on Zap channel to mute DTMF tones */ x = 1; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } /* Find a pointer to the agi app and execute the script */ app = pbx_findapp("agi"); if (app) { ret = pbx_exec(chan, app, agifile, 1); } else { ast_log(LOG_WARNING, "Could not find application (agi)\n"); ret = -2; } if (!strcasecmp(chan->type,"Zap")) { /* Remove CONFMUTE mode on Zap channel */ x = 0; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } } else { if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) { /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */ x = 1; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } for(;;) { outfd = -1; ms = -1; c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); /* Update the struct with the actual confflags */ user->userflags = confflags; /* trying to add moh for single person conf */ if (confflags & CONFFLAG_MOH) { if (conf->users == 1) { if (musiconhold == 0) { ast_moh_start(chan, NULL); musiconhold = 1; } } else { if (musiconhold) { ast_moh_stop(chan); musiconhold = 0; } } } /* Leave if the last marked user left */ if (conf->markedusers == 0 && confflags & CONFFLAG_MARKEDEXIT) { ret = -1; break; } /* Check if the admin changed my modes */ if (user->adminflags) { /* Set the new modes */ if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode ^= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode |= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (user->adminflags & ADMINFLAG_KICKME) { //You have been kicked. if (!ast_streamfile(chan, "conf-kicked", chan->language)) ast_waitstream(chan, ""); ret = 0; break; } } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode |= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (c) { if (c->fds[0] != origfd) { if (using_pseudo) { /* Kill old pseudo */ close(fd); } ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); retryzap = 0; using_pseudo = 0; goto zapretry; } f = ast_read(c); if (!f) break; if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) { char tmp[2]; tmp[0] = f->subclass; tmp[1] = '\0'; if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) { strncpy(chan->context, exitcontext, sizeof(chan->context) - 1); strncpy(chan->exten, tmp, sizeof(chan->exten) - 1); chan->priority = 0; ret = 0; break; } } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { ret = 0; break; } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { if (musiconhold) { ast_moh_stop(chan); } if ((confflags & CONFFLAG_ADMIN)) { /* Admin menu */ if (!menu_active) { menu_active = 1; /* Record this sound! */ if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) dtmf = ast_waitstream(chan, AST_DIGIT_ANY); else dtmf = 0; } else dtmf = f->subclass; if (dtmf) { switch(dtmf) { case '1': /* Un/Mute */ menu_active = 0; if (ztc.confmode & ZT_CONF_TALKER) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; } else { ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; } if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } if (ztc.confmode & ZT_CONF_TALKER) { if (!ast_streamfile(chan, "conf-unmuted", chan->language)) ast_waitstream(chan, ""); } else { if (!ast_streamfile(chan, "conf-muted", chan->language)) ast_waitstream(chan, ""); } break; case '2': /* Un/Lock the Conference */ menu_active = 0; if (conf->locked) { conf->locked = 0; if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) ast_waitstream(chan, ""); } else { conf->locked = 1; if (!ast_streamfile(chan, "conf-lockednow", chan->language)) ast_waitstream(chan, ""); } break; default: menu_active = 0; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) ast_waitstream(chan, ""); break; } } } else { /* User menu */ if (!menu_active) { menu_active = 1; /* Record this sound! */ if (!ast_streamfile(chan, "conf-usermenu", chan->language)) dtmf = ast_waitstream(chan, AST_DIGIT_ANY); else dtmf = 0; } else dtmf = f->subclass; if (dtmf) { switch(dtmf) { case '1': /* Un/Mute */ menu_active = 0; if (ztc.confmode & ZT_CONF_TALKER) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; } else if (!(user->adminflags & ADMINFLAG_MUTED)) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; } if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } if (ztc.confmode & ZT_CONF_TALKER) { if (!ast_streamfile(chan, "conf-unmuted", chan->language)) ast_waitstream(chan, ""); } else { if (!ast_streamfile(chan, "conf-muted", chan->language)) ast_waitstream(chan, ""); } break; default: menu_active = 0; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) ast_waitstream(chan, ""); break; } } } if (musiconhold) { ast_moh_start(chan, NULL); } } else if (using_pseudo) { if (f->frametype == AST_FRAME_VOICE) { if (f->subclass == AST_FORMAT_SLINEAR) { /* Carefully write */ careful_write(fd, f->data, f->datalen); } else ast_log(LOG_WARNING, "Huh? Got a non-linear (%d) frame in the conference\n", f->subclass); } } ast_frfree(f); } else if (outfd > -1) { res = read(outfd, buf, CONF_SIZE); if (res > 0) { memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_VOICE; fr.subclass = AST_FORMAT_SLINEAR; fr.datalen = res; fr.samples = res/2; fr.data = buf; fr.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &fr) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); /* break; */ } } else ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); } } } if (using_pseudo) close(fd); else { /* Take out of conference */ /* Add us to the conference */ ztc.chan = 0; ztc.confno = 0; ztc.confmode = 0; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); } } if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) conf_play(conf, LEAVE); outrun: ast_mutex_lock(&conflock); if (user->user_no) { /* Only cleanup users who really joined! */ manager_event(EVENT_FLAG_CALL, "MeetmeLeave", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" "Usernum: %i\r\n", chan->name, chan->uniqueid, conf->confno, user->user_no); prev = NULL; conf->users--; if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers--; cur = confs; if (!conf->users) { /* No more users -- close this one out */ while(cur) { if (cur == conf) { if (prev) prev->next = conf->next; else confs = conf->next; break; } prev = cur; cur = cur->next; } if (!cur) ast_log(LOG_WARNING, "Conference not found\n"); if (conf->chan) ast_hangup(conf->chan); else close(conf->fd); free(conf); } else { /* Remove the user struct */ if (user == conf->firstuser) { if (user->nextuser) { /* There is another entry */ user->nextuser->prevuser = NULL; } else { /* We are the only entry */ conf->lastuser = NULL; } /* In either case */ conf->firstuser = user->nextuser; } else if (user == conf->lastuser){ if (user->prevuser) user->prevuser->nextuser = NULL; else ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n"); conf->lastuser = user->prevuser; } else { if (user->nextuser) user->nextuser->prevuser = user->prevuser; else ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n"); if (user->prevuser) user->prevuser->nextuser = user->nextuser; else ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n"); } } /* Return the number of seconds the user was in the conf */ snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime)); pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); } free(user); ast_mutex_unlock(&conflock); return ret; }
static int chanspy_exec(struct ast_channel *chan, void *data) { struct localuser *u; struct ast_channel *peer=NULL, *prev=NULL; char name[AST_NAME_STRLEN], peer_name[AST_NAME_STRLEN + 5], *args, *ptr = NULL, *options = NULL, *spec = NULL, *argv[5], *mygroup = NULL, *recbase = NULL; int res = -1, volfactor = 0, silent = 0, argc = 0, bronly = 0, chosen = 0, count=0, waitms = 100, num = 0, oldrf = 0, oldwf = 0, fd = 0; struct ast_flags flags; signed char zero_volume = 0; if (!(args = ast_strdupa((char *)data))) { ast_log(LOG_ERROR, "Out of memory!\n"); return -1; } LOCAL_USER_ADD(u); oldrf = chan->readformat; oldwf = chan->writeformat; if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); LOCAL_USER_REMOVE(u); return -1; } if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); LOCAL_USER_REMOVE(u); return -1; } ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { spec = argv[0]; if ( argc > 1) { options = argv[1]; } if (ast_strlen_zero(spec) || !strcmp(spec, "all")) { spec = NULL; } } if (options) { char *opts[OPT_ARG_ARRAY_SIZE]; ast_app_parse_options(chanspy_opts, &flags, opts, options); if (ast_test_flag(&flags, OPTION_GROUP)) { mygroup = opts[OPT_ARG_GROUP]; } if (ast_test_flag(&flags, OPTION_RECORD)) { if (!(recbase = opts[OPT_ARG_RECORD])) { recbase = "chanspy"; } } silent = ast_test_flag(&flags, OPTION_QUIET); bronly = ast_test_flag(&flags, OPTION_BRIDGED); if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { int vol; if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); else volfactor = vol; } } else ast_clear_flag(&flags, AST_FLAGS_ALL); if (recbase) { char filename[512]; snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL)); if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC, 0644)) <= 0) { ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename); fd = 0; } } for(;;) { if (!silent) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } } count = 0; res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } peer = local_channel_walk(NULL); prev=NULL; while(peer) { if (peer != chan) { char *group = NULL; int igrp = 1; if (peer == prev && !chosen) { break; } chosen = 0; group = pbx_builtin_getvar_helper(peer, "SPYGROUP"); if (mygroup) { if (!group || strcmp(mygroup, group)) { igrp = 0; } } if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) && !strncasecmp(peer->name, spec, strlen(spec)))))) { if (peer && (!bronly || ast_bridged_channel(peer)) && !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) { int x = 0; strncpy(peer_name, "spy-", 5); strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN); ptr = strchr(peer_name, '/'); *ptr = '\0'; ptr++; for (x = 0 ; x < strlen(peer_name) ; x++) { if (peer_name[x] == '/') { break; } peer_name[x] = tolower(peer_name[x]); } if (!silent) { if (ast_fileexists(peer_name, NULL, NULL) != -1) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) res = ast_waitstream(chan, ""); if (res) break; } else res = ast_say_character_str(chan, peer_name, "", chan->language); if ((num=atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } count++; prev = peer; res = channel_spy(chan, peer, &volfactor, fd); if (res == -1) { break; } else if (res > 1 && spec) { snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res); if ((peer = local_get_channel_begin_name(name))) { chosen = 1; } continue; } } } } if ((peer = local_channel_walk(peer)) == NULL) { break; } } waitms = count ? 100 : 5000; } if (fd > 0) { close(fd); } if (oldrf && ast_set_read_format(chan, oldrf) < 0) { ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); } if (oldwf && ast_set_write_format(chan, oldwf) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); } ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ALL_DONE(u, res); }
int ast_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms) { struct timeval started, ended; long elapsed = 0,last_elapsed =0; char *breaks=NULL; char *end=NULL; int blen=2; int res=0; if (stop) blen += strlen(stop); if (pause) blen += strlen(pause); if (blen > 2) { breaks = alloca(blen + 1); breaks[0] = '\0'; strcat(breaks, stop); strcat(breaks, pause); } if (chan->_state != AST_STATE_UP) res = ast_answer(chan); if (chan) ast_stopstream(chan); if (file) { if ((end = strchr(file,':'))) { if (!strcasecmp(end, ":end")) { *end = '\0'; end++; } } } for (;;) { gettimeofday(&started,NULL); if (chan) ast_stopstream(chan); res = ast_streamfile(chan, file, chan->language); if (!res) { if (end) { ast_seekstream(chan->stream, 0, SEEK_END); end=NULL; } res = 1; if (elapsed) { ast_stream_fastforward(chan->stream, elapsed); last_elapsed = elapsed - 200; } if (res) res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms); else break; } if (res < 1) break; if (pause != NULL && strchr(pause, res)) { gettimeofday(&ended, NULL); elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed); for(;;) { if (chan) ast_stopstream(chan); res = ast_waitfordigit(chan, 1000); if (res == 0) continue; else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res))) break; } if (res == *pause) { res = 0; continue; } } if (res == -1) break; /* if we get one of our stop chars, return it to the calling function */ if (stop && strchr(stop, res)) { /* res = 0; */ break; } } if (chan) ast_stopstream(chan); return res; }
/*--- conf_exec: The meetme() application */ static int conf_exec(struct ast_channel *chan, void *data) { int res=-1; struct localuser *u; char confno[AST_MAX_EXTENSION] = ""; int allowretry = 0; int retrycnt = 0; struct ast_conference *cnf; int confflags = 0; int dynamic = 0; int empty = 0, empty_no_pin = 0; char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = ""; if (!data || ast_strlen_zero(data)) { allowretry = 1; notdata = ""; } else { notdata = data; } LOCAL_USER_ADD(u); if (chan->_state != AST_STATE_UP) ast_answer(chan); info = ast_strdupa((char *)notdata); if (info) { char *tmp = strsep(&info, "|"); strncpy(confno, tmp, sizeof(confno) - 1); if (ast_strlen_zero(confno)) { allowretry = 1; } } if (info) inflags = strsep(&info, "|"); if (info) inpin = strsep(&info, "|"); if (inpin) strncpy(the_pin, inpin, sizeof(the_pin) - 1); if (inflags) { if (strchr(inflags, 'a')) confflags |= CONFFLAG_ADMIN; if (strchr(inflags, 'm')) confflags |= CONFFLAG_MONITOR; if (strchr(inflags, 'p')) confflags |= CONFFLAG_POUNDEXIT; if (strchr(inflags, 's')) confflags |= CONFFLAG_STARMENU; if (strchr(inflags, 't')) confflags |= CONFFLAG_TALKER; if (strchr(inflags, 'q')) confflags |= CONFFLAG_QUIET; if (strchr(inflags, 'M')) confflags |= CONFFLAG_MOH; if (strchr(inflags, 'x')) confflags |= CONFFLAG_MARKEDEXIT; if (strchr(inflags, 'X')) confflags |= CONFFLAG_EXIT_CONTEXT; if (strchr(inflags, 'A')) confflags |= CONFFLAG_MARKEDUSER; if (strchr(inflags, 'b')) confflags |= CONFFLAG_AGI; if (strchr(inflags, 'w')) confflags |= CONFFLAG_WAITMARKED; if (strchr(inflags, 'd')) dynamic = 1; if (strchr(inflags, 'D')) { dynamic = 1; if (! inpin) { strncpy(the_pin, "q", sizeof(the_pin) - 1); } } if (strchr(inflags, 'e')) empty = 1; if (strchr(inflags, 'E')) { empty = 1; empty_no_pin = 1; } } do { if (retrycnt > 3) allowretry = 0; if (empty) { int i, map[1024]; struct ast_config *cfg; struct ast_variable *var; int confno_int; memset(map, 0, sizeof(map)); ast_mutex_lock(&conflock); cnf = confs; while (cnf) { if (sscanf(cnf->confno, "%d", &confno_int) == 1) { /* Disqualify in use conference */ if (confno_int >= 0 && confno_int < 1024) map[confno_int]++; } cnf = cnf->next; } ast_mutex_unlock(&conflock); /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */ if ((empty_no_pin) || (!dynamic)) { cfg = ast_load("meetme.conf"); if (cfg) { var = ast_variable_browse(cfg, "rooms"); while(var) { if (!strcasecmp(var->name, "conf")) { char *stringp = ast_strdupa(var->value); if (stringp) { char *confno_tmp = strsep(&stringp, "|,"); int found = 0; if (sscanf(confno_tmp, "%d", &confno_int) == 1) { if ((confno_int >= 0) && (confno_int < 1024)) { if (stringp && empty_no_pin) { map[confno_int]++; } } } if (! dynamic) { /* For static: run through the list and see if this conference is empty */ ast_mutex_lock(&conflock); cnf = confs; while (cnf) { if (!strcmp(confno_tmp, cnf->confno)) { /* The conference exists, therefore it's not empty */ found = 1; break; } cnf = cnf->next; } ast_mutex_unlock(&conflock); if (!found) { /* At this point, we have a confno_tmp (static conference) that is empty */ if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) { /* Case 1: empty_no_pin and pin is nonexistant (NULL) * Case 2: empty_no_pin and pin is blank (but not NULL) * Case 3: not empty_no_pin */ strncpy(confno, confno_tmp, sizeof(confno) - 1); break; /* XXX the map is not complete (but we do have a confno) */ } } } } else { ast_log(LOG_ERROR, "Out of memory\n"); } } var = var->next; } ast_destroy(cfg); } } /* Select first conference number not in use */ if (ast_strlen_zero(confno) && dynamic) { for (i=0;i<1024;i++) { if (!map[i]) { snprintf(confno, sizeof(confno), "%d", i); break; } } } /* Not found? */ if (ast_strlen_zero(confno)) { res = ast_streamfile(chan, "conf-noempty", chan->language); if (!res) ast_waitstream(chan, ""); } else { if (sscanf(confno, "%d", &confno_int) == 1) { res = ast_streamfile(chan, "conf-enteringno", chan->language); if (!res) { ast_waitstream(chan, ""); res = ast_say_digits(chan, confno_int, "", chan->language); } } else { ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno); } } } while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) { /* Prompt user for conference number */ res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0); if (res < 0) { /* Don't try to validate when we catch an error */ confno[0] = '\0'; allowretry = 0; break; } } if (!ast_strlen_zero(confno)) { /* Check the validity of the conference */ cnf = find_conf(chan, confno, 1, dynamic, the_pin); if (!cnf) { res = ast_streamfile(chan, "conf-invalid", chan->language); if (!res) ast_waitstream(chan, ""); res = -1; if (allowretry) confno[0] = '\0'; } else { if (!ast_strlen_zero(cnf->pin)) { char pin[AST_MAX_EXTENSION]=""; int j; /* Allow the pin to be retried up to 3 times */ for (j=0; j<3; j++) { if (*the_pin) { strncpy(pin, the_pin, sizeof(pin) - 1); res = 0; } else { /* Prompt user for pin if pin is required */ res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0); } if (res >= 0) { if (!strcasecmp(pin, cnf->pin)) { /* Pin correct */ allowretry = 0; /* Run the conference */ res = conf_run(chan, cnf, confflags); break; } else { /* Pin invalid */ res = ast_streamfile(chan, "conf-invalidpin", chan->language); if (!res) ast_waitstream(chan, AST_DIGIT_ANY); if (res < 0) break; pin[0] = res; pin[1] = '\0'; res = -1; if (allowretry) confno[0] = '\0'; } } else { res = -1; allowretry = 0; break; } /* Don't retry pin with a static pin */ if (*the_pin) { break; } } } else { /* No pin required */ allowretry = 0; /* Run the conference */ res = conf_run(chan, cnf, confflags); } } } } while (allowretry); /* Do the conference */ LOCAL_USER_REMOVE(u); return res; }
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path) { char *fmts; int d; char comment[256]; int x, fmtcnt=1, res=-1,outmsg=0; struct ast_frame *f; struct ast_filestream *others[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; char *stringp=NULL; time_t start, end; struct ast_dsp *sildet=NULL; /* silence detector dsp */ int totalsilence = 0; int dspsilence = 0; int gotsilence = 0; /* did we timeout for silence? */ int rfmt=0; if (silencethreshold < 0) silencethreshold = global_silence_threshold; if (maxsilence < 0) maxsilence = global_maxsilence; /* barf if no pointer passed to store duration in */ if (duration == NULL) { ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n"); return -1; } ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt); snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name); if (playfile) { d = ast_play_and_wait(chan, playfile); if (d > -1) d = ast_streamfile(chan, "beep",chan->language); if (!d) d = ast_waitstream(chan,""); if (d < 0) return -1; } fmts = ast_strdupa(fmt); stringp=fmts; strsep(&stringp, "|"); ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = ast_strdupa(fmts); while((fmt = strsep(&stringp, "|"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; } sfmt[fmtcnt++] = ast_strdupa(fmt); } time(&start); end=start; /* pre-initialize end to be same as start in case we never get into loop */ for (x=0; x<fmtcnt; x++) { others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700); ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]); if (!others[x]) { break; } } if (path) ast_unlock_path(path); if (maxsilence > 0) { sildet = ast_dsp_new(); /* Create the silence detector */ if (!sildet) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } ast_dsp_set_threshold(sildet, silencethreshold); rfmt = chan->readformat; res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); ast_dsp_free(sildet); return -1; } } if (x == fmtcnt) { /* Loop forever, writing the packets we read to the writer(s), until we read a # or get a hangup */ f = NULL; for(;;) { res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_DEBUG, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = ast_read(chan); if (!f) break; if (f->frametype == AST_FRAME_VOICE) { /* write each format */ for (x=0; x<fmtcnt; x++) { res = ast_writestream(others[x], f); } /* Silence Detection */ if (maxsilence > 0) { dspsilence = 0; ast_dsp_silence(sildet, f, &dspsilence); if (dspsilence) totalsilence = dspsilence; else totalsilence = 0; if (totalsilence > maxsilence) { /* Ended happily with silence */ if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); ast_frfree(f); gotsilence = 1; outmsg=2; break; } } /* Exit on any error */ if (res) { ast_log(LOG_WARNING, "Error writing frame\n"); ast_frfree(f); break; } } else if (f->frametype == AST_FRAME_VIDEO) { /* Write only once */ ast_writestream(others[0], f); } else if (f->frametype == AST_FRAME_DTMF) { if (f->subclass == '#') { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); res = '#'; outmsg = 2; ast_frfree(f); break; } } if (f->subclass == '0') { /* Check for a '0' during message recording also, in case caller wants operator */ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass); res = '0'; outmsg = 0; ast_frfree(f); break; } if (maxtime) { time(&end); if (maxtime < (end - start)) { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); outmsg = 2; res = 't'; ast_frfree(f); break; } } ast_frfree(f); } if (end == start) time(&end); if (!f) { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "User hung up\n"); res = -1; outmsg=1; } } else { ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]); } *duration = end - start; for (x=0; x<fmtcnt; x++) { if (!others[x]) break; if (res > 0) { if (totalsilence) ast_stream_rewind(others[x], totalsilence-200); else ast_stream_rewind(others[x], 200); } ast_truncstream(others[x]); ast_closestream(others[x]); } if (rfmt) { if (ast_set_read_format(chan, rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name); } } if (outmsg > 1) { /* Let them know recording is stopped */ if(!ast_streamfile(chan, "auth-thankyou", chan->language)) ast_waitstream(chan, ""); } if (sildet) ast_dsp_free(sildet); return res; }
static int nv_background_detect_exec(struct ast_channel *chan, const char *data) { int res = 0; char tmp[256] = "\0"; char *p = NULL; char *filename = NULL; char *options = NULL; char *silstr = NULL; char *minstr = NULL; char *maxstr = NULL; struct ast_frame *fr = NULL; struct ast_frame *fr2 = NULL; int notsilent = 0; struct timeval start = {0, 0}, end = {0, 0}; int sildur = 1000; int mindur = 100; int maxdur = -1; int skipanswer = 0; int noextneeded = 0; int ignoredtmf = 0; int ignorefax = 0; int ignoretalk = 0; int x = 0; struct ast_format* origrformat = NULL; int features = 0; struct ast_dsp *dsp = NULL; struct ast_format_cap *cap; struct ast_format linearFormat; /* linear format capabilities */ ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0); cap = ast_format_cap_alloc_nolock(); ast_format_cap_add(cap, &linearFormat); /* done */ pbx_builtin_setvar_helper(chan, "FAX_DETECTED", ""); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ""); pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", ""); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ""); if (!data || ast_strlen_zero(data)) { ast_log(LOG_WARNING, "NVBackgroundDetect requires an argument (filename)\n"); return -1; } strncpy(tmp, data, sizeof(tmp)-1); p = tmp; filename = strsep(&p, ","); options = strsep(&p, ","); silstr = strsep(&p, ","); minstr = strsep(&p, ","); maxstr = strsep(&p, ","); if (options) { if (strchr(options, 'n')) skipanswer = 1; if (strchr(options, 'x')) noextneeded = 1; if (strchr(options, 'd')) ignoredtmf = 1; if (strchr(options, 'f')) ignorefax = 1; if (strchr(options, 't')) ignoretalk = 1; } if (silstr) { if ((sscanf(silstr, "%d", &x) == 1) && (x > 0)) sildur = x; } if (minstr) { if ((sscanf(minstr, "%d", &x) == 1) && (x > 0)) mindur = x; } if (maxstr) { if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0)) maxdur = x; } ast_log(LOG_DEBUG, "Preparing detect of '%s' (sildur=%dms, mindur=%dms, maxdur=%dms)\n", tmp, sildur, mindur, maxdur); // LOCAL_USER_ADD(u); if (ast_channel_state(chan) != AST_STATE_UP && !skipanswer) { /* Otherwise answer unless we're supposed to send this while on-hook */ res = ast_answer(chan); } if (!res) { origrformat = ast_channel_readformat(chan); //chan->readformat; // if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) // ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); if ((res = ast_set_read_format_from_cap(chan, cap)) ){ ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); } } if (!(dsp = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); res = -1; } if (dsp) { if (!ignoretalk) ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */ if (!ignorefax) features |= DSP_FEATURE_FAX_DETECT; //if (!ignoredtmf) features |= DSP_FEATURE_DIGIT_DETECT; ast_dsp_set_threshold(dsp, 256); ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF); ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF); } if (!res) { ast_stopstream(chan); // res = ast_streamfile(chan, tmp, chan->language); res = ast_streamfile(chan, tmp, ast_channel_language(chan)); if (!res) { // while(chan->stream) { while( ast_channel_stream(chan) ) { // res = ast_sched_wait(chan->sched); res = ast_sched_wait( ast_channel_sched(chan) ); // if ((res < 0) && !chan->timingfunc) { if ((res < 0) && !ast_channel_timingfunc(chan)) { res = 0; break; } if (res < 0) res = 1000; res = ast_waitfor(chan, res); if (res < 0) { // ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name); ast_log(LOG_WARNING, "Waitfor failed on %s\n", ast_channel_name(chan)); break; } else if (res > 0) { fr = ast_read(chan); if (!fr) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; break; } fr2 = ast_dsp_process(chan, dsp, fr); if (!fr2) { ast_log(LOG_WARNING, "Bad DSP received (what happened!!)\n"); fr2 = fr; } if (fr2->frametype == AST_FRAME_DTMF) { // if (fr2->subclass == 'f' && !ignorefax) { if (fr2->subclass.integer == 'f' && !ignorefax) { /* Fax tone -- Handle and return NULL */ // ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name); ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); // if (strcmp(chan->exten, "fax")) { if (strcmp(ast_channel_exten(chan), "fax")) { ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan)); pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1"); // pbx_builtin_setvar_helper(chan,"FAXEXTEN",chan->exten); pbx_builtin_setvar_helper(chan,"FAXEXTEN", ast_channel_exten(chan)); // if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) { if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) { /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ // strncpy(chan->exten, "fax", sizeof(chan->exten)-1); // chan->priority = 0; ast_channel_exten_set(chan, "fax"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Fax detected, but no fax extension\n"); } else ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n"); res = 0; ast_frfree(fr); break; } else if (!ignoredtmf) { ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan)); char t[2]; // t[0] = fr2->subclass; t[0] = fr2->subclass.integer; t[1] = '\0'; // if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) { if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) { pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1"); /* They entered a valid extension, or might be anyhow */ if (noextneeded) { ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n"); res = 0; } else { ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n"); // res = fr2->subclass; res = fr2->subclass.integer; } ast_frfree(fr); break; } else ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n"); } // } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) { } else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !ignoretalk) { int totalsilence; int ms; res = ast_dsp_silence(dsp, fr, &totalsilence); if (res && (totalsilence > sildur)) { /* We've been quiet a little while */ if (notsilent) { /* We had heard some talking */ gettimeofday(&end, NULL); ms = (end.tv_sec - start.tv_sec) * 1000; ms += (end.tv_usec - start.tv_usec) / 1000; ms -= sildur; if (ms < 0) ms = 0; if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) { char ms_str[10]; ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms); // ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name); ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", ast_channel_name(chan)); /* Save detected talk time (in milliseconds) */ sprintf(ms_str, "%d", ms); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str); // if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) { if (ast_exists_extension(chan, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) { // strncpy(chan->exten, "talk", sizeof(chan->exten) - 1); // chan->priority = 0; ast_channel_exten_set(chan, "talk"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Talk detected, but no talk extension\n"); res = 0; ast_frfree(fr); break; } else ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms); notsilent = 0; } } else { if (!notsilent) { /* Heard some audio, mark the begining of the token */ gettimeofday(&start, NULL); ast_log(LOG_DEBUG, "Start of voice token!\n"); notsilent = 1; } } } ast_frfree(fr); } // ast_sched_runq(chan->sched); ast_sched_runq( ast_channel_sched(chan) ); } ast_stopstream(chan); } else { // ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data); ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char *)data); res = 0; } } else // ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan)); if (res > -1) { if (origrformat && ast_set_read_format(chan, origrformat)) { // ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", chan->name, ast_getformatname(origrformat)); ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", ast_channel_name(chan), ast_getformatname(origrformat)); } } if (dsp) ast_dsp_free(dsp); // LOCAL_USER_REMOVE(u); ast_format_cap_destroy(cap); return res; }
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec) { int res; struct ast_filestream *writer; int rfmt; int totalms=0, total; struct ast_frame *f; struct ast_dsp *sildet; /* Play prompt if requested */ if (prompt) { res = ast_streamfile(c, prompt, c->language); if (res < 0) return res; res = ast_waitstream(c,""); if (res < 0) return res; } rfmt = c->readformat; res = ast_set_read_format(c, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); return -1; } sildet = ast_dsp_new(); if (!sildet) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666); if (!writer) { ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt); ast_dsp_free(sildet); return -1; } for(;;) { if ((res = ast_waitfor(c, 2000)) < 0) { ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt); break; } if (res) { f = ast_read(c); if (!f) { ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt); break; } if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) { /* Ended happily with DTMF */ ast_frfree(f); break; } else if (f->frametype == AST_FRAME_VOICE) { ast_dsp_silence(sildet, f, &total); if (total > silence) { /* Ended happily with silence */ ast_frfree(f); break; } totalms += f->samples / 8; if (totalms > maxsec * 1000) { /* Ended happily with too much stuff */ ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec); ast_frfree(f); break; } } ast_frfree(f); } } res = ast_set_read_format(c, rfmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name); ast_dsp_free(sildet); ast_closestream(writer); return 0; }
static int common_exec(struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct ast_channel_iterator *iter = NULL; if (ast_test_flag(flags, OPTION_EXIT)) { const char *c; ast_channel_lock(chan); if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { ast_copy_string(exitcontext, c, sizeof(exitcontext)); } else if (!ast_strlen_zero(chan->macrocontext)) { ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); } else { ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); } ast_channel_unlock(chan); } if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct ast_autochan *autochan = NULL, *next_autochan = NULL; struct ast_channel *prev = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } } /* Set up the iterator we'll be using during this call */ if (!ast_strlen_zero(spec)) { iter = ast_channel_iterator_by_name_new(spec, strlen(spec)); } else if (!ast_strlen_zero(exten)) { iter = ast_channel_iterator_by_exten_new(exten, context); } else { iter = ast_channel_iterator_all_new(); } if (!iter) { return -1; } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (autochan = next_channel(iter, autochan, chan); autochan; prev = autochan->chan, ast_autochan_destroy(autochan), autochan = next_autochan ? next_autochan : next_channel(iter, autochan, chan), next_autochan = NULL) { int igrp = !mygroup; int ienf = !myenforced; char *s; if (autochan->chan == prev) { ast_autochan_destroy(autochan); break; } if (ast_check_hangup(chan)) { ast_autochan_destroy(autochan); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) { continue; } if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) { continue; } if (mygroup) { int num_groups = 0; int num_mygroups = 0; char dup_group[512]; char dup_mygroup[512]; char *groups[NUM_SPYGROUPS]; char *mygroups[NUM_SPYGROUPS]; const char *group = NULL; int x; int y; ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, ARRAY_LEN(mygroups)); /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable * rather than "SPYGROUP", this check is done to preserve expected behavior */ if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) { group = pbx_builtin_getvar_helper(autochan->chan, "GROUP"); } else { group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"); } if (!ast_strlen_zero(group)) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, ARRAY_LEN(groups)); } for (y = 0; y < num_mygroups; y++) { for (x = 0; x < num_groups; x++) { if (!strcmp(mygroups[y], groups[x])) { igrp = 1; break; } } } } if (!igrp) { continue; } if (myenforced) { char ext[AST_CHANNEL_NAME + 3]; char buffer[512]; char *end; snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1); if ((end = strchr(ext, '-'))) { *end++ = ':'; *end = '\0'; } ext[0] = ':'; if (strcasestr(buffer, ext)) { ienf = 1; } } if (!ienf) { continue; } strcpy(peer_name, "spy-"); strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; ptr = strsep(&ptr, "-"); for (s = peer_name; s < ptr; s++) *s = tolower(*s); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_test_flag(flags, OPTION_NAME)) { const char *local_context = S_OR(name_context, "default"); const char *local_mailbox = S_OR(mailbox, ptr); res = ast_app_sayname(chan, local_mailbox, local_context); } if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { if (!ast_test_flag(flags, OPTION_NOTECH)) { if (ast_fileexists(peer_name, NULL, NULL) > 0) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) { res = ast_waitstream(chan, ""); } if (res) { ast_autochan_destroy(autochan); break; } } else { res = ast_say_character_str(chan, peer_name, "", chan->language); } } if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } } res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext); num_spyed_upon++; if (res == -1) { ast_autochan_destroy(autochan); goto exit; } else if (res == -2) { res = 0; ast_autochan_destroy(autochan); goto exit; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) { next_autochan = ast_autochan_setup(next); next = ast_channel_unref(next); } else { /* stay on this channel, if it is still valid */ if (!ast_check_hangup(autochan->chan)) { next_autochan = ast_autochan_setup(autochan->chan); } else { /* the channel is gone */ next_autochan = NULL; } } } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) { goto exit; } } iter = ast_channel_iterator_destroy(iter); if (res == -1 || ast_check_hangup(chan)) break; if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) { break; } } exit: ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); return res; }
static int record_exec(struct ast_channel *chan, void *data) { int res = 0; int count = 0; int percentflag = 0; char *filename, *ext = NULL, *silstr, *maxstr, *options; char *vdata, *p; int i = 0; char tmp[256]; struct ast_filestream *s = '\0'; struct localuser *u; struct ast_frame *f = NULL; struct ast_dsp *sildet = NULL; /* silence detector dsp */ int totalsilence = 0; int dspsilence = 0; int silence = 0; /* amount of silence to allow */ int gotsilence = 0; /* did we timeout for silence? */ int maxduration = 0; /* max duration of recording in milliseconds */ int gottimeout = 0; /* did we timeout for maxduration exceeded? */ int option_skip = 0; int option_noanswer = 0; int option_append = 0; int terminator = '#'; int option_quiet = 0; int rfmt = 0; int flags; int waitres; struct ast_silence_generator *silgen = NULL; /* The next few lines of code parse out the filename and header from the input string */ if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ ast_log(LOG_WARNING, "Record requires an argument (filename)\n"); return -1; } LOCAL_USER_ADD(u); /* Yay for strsep being easy */ vdata = ast_strdupa(data); if (!vdata) { ast_log(LOG_ERROR, "Out of memory\n"); LOCAL_USER_REMOVE(u); return -1; } p = vdata; filename = strsep(&p, "|"); silstr = strsep(&p, "|"); maxstr = strsep(&p, "|"); options = strsep(&p, "|"); if (filename) { if (strstr(filename, "%d")) percentflag = 1; ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */ if (!ext) ext = strchr(filename, ':'); if (ext) { *ext = '\0'; ext++; } } if (!ext) { ast_log(LOG_WARNING, "No extension specified to filename!\n"); LOCAL_USER_REMOVE(u); return -1; } if (silstr) { if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) { silence = i * 1000; } else if (!ast_strlen_zero(silstr)) { ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr); } } if (maxstr) { if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1)) /* Convert duration to milliseconds */ maxduration = i * 1000; else if (!ast_strlen_zero(maxstr)) ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr); } if (options) { /* Retain backwards compatibility with old style options */ if (!strcasecmp(options, "skip")) option_skip = 1; else if (!strcasecmp(options, "noanswer")) option_noanswer = 1; else { if (strchr(options, 's')) option_skip = 1; if (strchr(options, 'n')) option_noanswer = 1; if (strchr(options, 'a')) option_append = 1; if (strchr(options, 't')) terminator = '*'; if (strchr(options, 'q')) option_quiet = 1; } } /* done parsing */ /* these are to allow the use of the %d in the config file for a wild card of sort to create a new file with the inputed name scheme */ if (percentflag) { do { snprintf(tmp, sizeof(tmp), filename, count); count++; } while ( ast_fileexists(tmp, ext, chan->language) != -1 ); pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); } else strncpy(tmp, filename, sizeof(tmp)-1); /* end of routine mentioned */ if (chan->_state != AST_STATE_UP) { if (option_skip) { /* At the user's option, skip if the line is not up */ LOCAL_USER_REMOVE(u); return 0; } else if (!option_noanswer) { /* Otherwise answer unless we're supposed to record while on-hook */ res = ast_answer(chan); } } if (res) { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); goto out; } if (!option_quiet) { /* Some code to play a nice little beep to signify the start of the record operation */ res = ast_streamfile(chan, "beep", chan->language); if (!res) { res = ast_waitstream(chan, ""); } else { ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name); } ast_stopstream(chan); } /* The end of beep code. Now the recording starts */ if (silence > 0) { rfmt = chan->readformat; res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); LOCAL_USER_REMOVE(u); return -1; } sildet = ast_dsp_new(); if (!sildet) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); LOCAL_USER_REMOVE(u); return -1; } ast_dsp_set_threshold(sildet, 256); } flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; s = ast_writefile( tmp, ext, NULL, flags , 0, 0644); if (!s) { ast_log(LOG_WARNING, "Could not create file %s\n", filename); goto out; } if (option_transmit_silence_during_record) silgen = ast_channel_start_silence_generator(chan); /* Request a video update */ ast_indicate(chan, AST_CONTROL_VIDUPDATE); if (maxduration <= 0) maxduration = -1; while ((waitres = ast_waitfor(chan, maxduration)) > -1) { if (maxduration > 0) { if (waitres == 0) { gottimeout = 1; break; } maxduration = waitres; } f = ast_read(chan); if (!f) { res = -1; break; } if (f->frametype == AST_FRAME_VOICE) { res = ast_writestream(s, f); if (res) { ast_log(LOG_WARNING, "Problem writing frame\n"); ast_frfree(f); break; } if (silence > 0) { dspsilence = 0; ast_dsp_silence(sildet, f, &dspsilence); if (dspsilence) { totalsilence = dspsilence; } else { totalsilence = 0; } if (totalsilence > silence) { /* Ended happily with silence */ ast_frfree(f); gotsilence = 1; break; } } } else if (f->frametype == AST_FRAME_VIDEO) { res = ast_writestream(s, f); if (res) { ast_log(LOG_WARNING, "Problem writing frame\n"); ast_frfree(f); break; } } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == terminator)) { ast_frfree(f); break; } ast_frfree(f); } if (!f) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; } if (gotsilence) { ast_stream_rewind(s, silence-1000); ast_truncstream(s); } else if (!gottimeout) { /* Strip off the last 1/4 second of it */ ast_stream_rewind(s, 250); ast_truncstream(s); } ast_closestream(s); if (silgen) ast_channel_stop_silence_generator(chan, silgen); out: if ((silence > 0) && rfmt) { res = ast_set_read_format(chan, rfmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); if (sildet) ast_dsp_free(sildet); } LOCAL_USER_REMOVE(u); return res; }