static int directory_exec(struct cw_channel *chan, int argc, char **argv) { struct localuser *u; struct cw_config *cfg; char *context, *dialcontext, *dirintro; int res = 0; int last = 1; if (argc < 1 || argc > 3) { cw_log(LOG_ERROR, "Syntax: %s\n", directory_syntax); return -1; } LOCAL_USER_ADD(u); context = argv[0]; dialcontext = (argc > 1 && argv[1][0] ? argv[1] : context); if (argc > 2 && strchr(argv[2], 'f')) last = 0; cfg = realtime_directory(context); if (!cfg) { LOCAL_USER_REMOVE(u); return -1; } dirintro = cw_variable_retrieve(cfg, context, "directoryintro"); if (cw_strlen_zero(dirintro)) dirintro = cw_variable_retrieve(cfg, "general", "directoryintro"); if (cw_strlen_zero(dirintro)) { if (last) dirintro = "dir-intro"; else dirintro = "dir-intro-fn"; } for (;;) { if (!res) res = cw_streamfile(chan, dirintro, chan->language); if (!res) res = cw_waitstream(chan, CW_DIGIT_ANY); cw_stopstream(chan); if (!res) res = cw_waitfordigit(chan, 5000); if (res >0) { res = do_directory(chan, cfg, context, dialcontext, res, last); if (res > 0){ res = cw_waitstream(chan, CW_DIGIT_ANY); cw_stopstream(chan); if (res >= 0) { continue; } } } break; } cw_config_destroy(cfg); LOCAL_USER_REMOVE(u); return res; }
static int conf_play_soundfile( struct cw_conf_member *member, char * file ) { int res = 0; if ( member->dont_play_any_sound ) return 0; if ( !member->chan ) return 0; cw_stopstream(member->chan); queue_incoming_silent_frame(member,3); if ( ( strrchr(file,'/')!=NULL ) || (cw_fileexists(file, NULL, member->chan->language) > 0) ) { res = cw_streamfile(member->chan, file, member->chan->language); if (!res) { res = cw_waitstream(member->chan, CW_DIGIT_ANY); cw_stopstream(member->chan); } //cw_log(LOG_DEBUG, "Soundfile found %s - %d\n", file, cw_fileexists(file, NULL, member->chan->language) ); } else cw_log(LOG_DEBUG, "Soundfile not found %s - lang: %s\n", file, member->chan->language ); cw_set_write_format( member->chan, CW_FORMAT_SLINEAR ); return res; }
int cw_play_and_wait(struct cw_channel *chan, const char *fn) { int d; d = cw_streamfile(chan, fn, chan->language); if (d) return d; d = cw_waitstream(chan, CW_DIGIT_ANY); cw_stopstream(chan); return d; }
int cw_app_getdata_full(struct cw_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd) { int res,to,fto; if (prompt) { res = cw_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 = cw_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd); return res; }
int cw_app_getdata(struct cw_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 = cw_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 = cw_readstring(c, s, maxlen, to, fto, "#"); return res; }
static int record_exec(struct cw_channel *chan, int argc, char **argv) { int res = 0; int count = 0; int percentflag = 0; char *ext = NULL; int i = 0; char tmp[256]; struct cw_filestream *s = '\0'; struct localuser *u; struct cw_frame *f = NULL; struct cw_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; if (argc < 1 || argc > 4 || !argv[0][0]) { cw_log(LOG_ERROR, "Syntax: %s\n", record_syntax); return -1; } LOCAL_USER_ADD(u); if (strstr(argv[0], "%d")) percentflag = 1; ext = strrchr(argv[0], '.'); /* to support filename with a . in the filename, not format */ if (!ext) ext = strchr(argv[0], ':'); if (ext) { *ext = '\0'; ext++; } if (!ext) { cw_log(LOG_WARNING, "No extension specified to filename!\n"); LOCAL_USER_REMOVE(u); return -1; } if (argc > 1) { silence = atoi(argv[1]); if (silence > 0) silence *= 1000; else if (silence < 0) silence = 0; } if (argc > 2) { maxduration = atoi(argv[2]); if (maxduration > 0) maxduration *= 1000; else if (maxduration < 0) maxduration = 0; } if (argc > 3) { /* Retain backwards compatibility with old style options */ if (!strcasecmp(argv[3], "skip")) option_skip = 1; else if (!strcasecmp(argv[3], "noanswer")) option_noanswer = 1; else { if (strchr(argv[3], 's')) option_skip = 1; if (strchr(argv[3], 'n')) option_noanswer = 1; if (strchr(argv[3], 'a')) option_append = 1; if (strchr(argv[3], 't')) terminator = '*'; if (strchr(argv[3], '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) { char *piece[100]; int pieces; /* Separate each piece out by the format specifier */ pieces = cw_separate_app_args(argv[0], '%', arraysize(piece), piece); do { int tmplen; /* First piece has no leading percent, so it's copied verbatim */ cw_copy_string(tmp, piece[0], sizeof(tmp)); tmplen = strlen(tmp); for (i = 1; i < pieces; i++) { if (piece[i][0] == 'd') { /* Substitute the count */ snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%d", count); tmplen += strlen(tmp + tmplen); } else if (tmplen + 2 < sizeof(tmp)) { /* Unknown format specifier - just copy it verbatim */ tmp[tmplen++] = '%'; tmp[tmplen++] = piece[i][0]; } /* Copy the remaining portion of the piece */ cw_copy_string(tmp + tmplen, &(piece[i][1]), sizeof(tmp) - tmplen); } count++; } while ( cw_fileexists(tmp, ext, chan->language) != -1 ); pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); } else strncpy(tmp, argv[0], sizeof(tmp)-1); /* end of routine mentioned */ if (chan->_state != CW_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 = cw_answer(chan); } } if (!res) { if (!option_quiet) { /* Some code to play a nice little beep to signify the start of the record operation */ res = cw_streamfile(chan, "beep", chan->language); if (!res) { res = cw_waitstream(chan, ""); } else { cw_log(LOG_WARNING, "cw_streamfile failed on %s\n", chan->name); } cw_stopstream(chan); } /* The end of beep code. Now the recording starts */ if (silence > 0) { rfmt = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); LOCAL_USER_REMOVE(u); return -1; } sildet = cw_dsp_new(); if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); LOCAL_USER_REMOVE(u); return -1; } cw_dsp_set_threshold(sildet, 256); } flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; s = cw_writefile( tmp, ext, NULL, flags , 0, 0644); if (s) { int waitres; /* Request a video update */ cw_indicate(chan, CW_CONTROL_VIDUPDATE); if (maxduration <= 0) maxduration = -1; while ((waitres = cw_waitfor(chan, maxduration)) > -1) { if (maxduration > 0) { if (waitres == 0) { gottimeout = 1; break; } maxduration = waitres; } f = cw_read(chan); if (!f) { res = -1; break; } if (f->frametype == CW_FRAME_VOICE) { res = cw_writestream(s, f); if (res) { cw_log(LOG_WARNING, "Problem writing frame\n"); cw_fr_free(f); break; } if (silence > 0) { dspsilence = 0; cw_dsp_silence(sildet, f, &dspsilence); if (dspsilence) { totalsilence = dspsilence; } else { totalsilence = 0; } if (totalsilence > silence) { /* Ended happily with silence */ cw_fr_free(f); gotsilence = 1; break; } } } if (f->frametype == CW_FRAME_VIDEO) { res = cw_writestream(s, f); if (res) { cw_log(LOG_WARNING, "Problem writing frame\n"); cw_fr_free(f); break; } } if ((f->frametype == CW_FRAME_DTMF) && (f->subclass == terminator)) { cw_fr_free(f); break; } cw_fr_free(f); } if (!f) { cw_log(LOG_DEBUG, "Got hangup\n"); res = -1; } if (gotsilence) { cw_stream_rewind(s, silence-1000); cw_truncstream(s); } else if (!gottimeout) { /* Strip off the last 1/4 second of it */ cw_stream_rewind(s, 250); cw_truncstream(s); } cw_closestream(s); } else cw_log(LOG_WARNING, "Could not create file %s\n", tmp); } else cw_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); if ((silence > 0) && rfmt) { res = cw_set_read_format(chan, rfmt); if (res) cw_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); if (sildet) cw_dsp_free(sildet); } LOCAL_USER_REMOVE(u); return res; }
static int do_directory(struct cw_channel *chan, struct cw_config *cfg, char *context, char *dialcontext, char digit, int last) { /* Read in the first three digits.. "digit" is the first digit, already read */ char ext[NUMDIGITS + 1]; char name[80] = ""; struct cw_variable *v; int res; int found=0; int lastuserchoice = 0; char *start, *pos, *conv,*stringp=NULL; if (cw_strlen_zero(context)) { cw_log(LOG_WARNING, "Directory must be called with an argument " "(context in which to interpret extensions)\n"); return -1; } if (digit == '0') { if (!cw_goto_if_exists(chan, chan->context, "o", 1) || (!cw_strlen_zero(chan->proc_context) && !cw_goto_if_exists(chan, chan->proc_context, "o", 1))) { return 0; } else { cw_log(LOG_WARNING, "Can't find extension 'o' in current context. " "Not Exiting the Directory!\n"); res = 0; } } if (digit == '*') { if (!cw_goto_if_exists(chan, chan->context, "a", 1) || (!cw_strlen_zero(chan->proc_context) && !cw_goto_if_exists(chan, chan->proc_context, "a", 1))) { return 0; } else { cw_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 (cw_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1; if (!res) { /* Search for all names which start with those digits */ v = cw_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) { cw_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++; 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); 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 (lastuserchoice != '1') { if (found) res = cw_streamfile(chan, "dir-nomore", chan->language); else res = cw_streamfile(chan, "dir-nomatch", chan->language); if (!res) res = 1; return res; } return 0; } return res; }
/* 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 cw_channel *chan, char *context, char *dialcontext, char *ext, char *name) { 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 *)cw_config_CW_SPOOL_DIR, context, ext); /* Otherwise, check for an old-style Voicemail greeting */ snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet", (char *)cw_config_CW_SPOOL_DIR, ext); if (cw_fileexists(fn, NULL, chan->language) > 0) { res = cw_streamfile(chan, fn, chan->language); if (!res) { res = cw_waitstream(chan, CW_DIGIT_ANY); } cw_stopstream(chan); } else if (cw_fileexists(fn2, NULL, chan->language) > 0) { res = cw_streamfile(chan, fn2, chan->language); if (!res) { res = cw_waitstream(chan, CW_DIGIT_ANY); } cw_stopstream(chan); } else { res = cw_say_character_str(chan, !cw_strlen_zero(name) ? name : ext, CW_DIGIT_ANY, chan->language); } while (loop) { if (!res) { res = cw_streamfile(chan, "dir-instr", chan->language); } if (!res) { res = cw_waitstream(chan, CW_DIGIT_ANY); } if (!res) { res = cw_waitfordigit(chan, 3000); } cw_stopstream(chan); if (res > -1) { switch (res) { case '1': /* Name selected */ loop = 0; if (cw_goto_if_exists(chan, dialcontext, ext, 1)) { cw_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); }
int cw_play_and_prepend(struct cw_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 cw_frame *f; struct cw_filestream *others[MAX_OTHER_FORMATS]; struct cw_filestream *realfiles[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; char *stringp=NULL; time_t start, end; struct cw_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) { cw_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n"); return -1; } cw_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 = cw_play_and_wait(chan, playfile); if (d > -1) d = cw_streamfile(chan, "beep",chan->language); if (!d) d = cw_waitstream(chan,""); if (d < 0) return -1; } cw_copy_string(prependfile, recordfile, sizeof(prependfile)); strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1); fmts = cw_strdupa(fmt); stringp=fmts; strsep(&stringp, "|,"); cw_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = cw_strdupa(fmts); while((fmt = strsep(&stringp, "|,"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { cw_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; } sfmt[fmtcnt++] = cw_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] = cw_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700); cw_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]); if (!others[x]) { break; } } sildet = cw_dsp_new(); /* Create the silence detector */ if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } cw_dsp_set_threshold(sildet, silencethreshold); if (maxsilence > 0) { rfmt = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_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 = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_DEBUG, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = cw_read(chan); if (!f) break; if (f->frametype == CW_FRAME_VOICE) { /* write each format */ for (x=0;x<fmtcnt;x++) { if (!others[x]) break; res = cw_writestream(others[x], f); } /* Silence Detection */ if (maxsilence > 0) { dspsilence = 0; cw_dsp_silence(sildet, f, &dspsilence); if (dspsilence) totalsilence = dspsilence; else totalsilence = 0; if (totalsilence > maxsilence) { /* Ended happily with silence */ if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); cw_fr_free(f); gotsilence = 1; outmsg=2; break; } } /* Exit on any error */ if (res) { cw_log(LOG_WARNING, "Error writing frame\n"); cw_fr_free(f); break; } } else if (f->frametype == CW_FRAME_VIDEO) { /* Write only once */ cw_writestream(others[0], f); } else if (f->frametype == CW_FRAME_DTMF) { /* stop recording with any digit */ if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); res = 't'; outmsg = 2; cw_fr_free(f); break; } if (maxtime) { time(&end); if (maxtime < (end - start)) { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); res = 't'; outmsg=2; cw_fr_free(f); break; } } cw_fr_free(f); } if (end == start) time(&end); if (!f) { if (option_verbose > 2) cw_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; cw_closestream(others[x]); cw_filedelete(prependfile, sfmt[x]); } #endif } } else { cw_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 cw_frame *fr; for (x=0;x<fmtcnt;x++) { snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]); realfiles[x] = cw_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0); if (!others[x] || !realfiles[x]) break; if (totalsilence) cw_stream_rewind(others[x], totalsilence-200); else cw_stream_rewind(others[x], 200); cw_truncstream(others[x]); /* add the original file too */ while ((fr = cw_readframe(realfiles[x]))) { cw_writestream(others[x],fr); } cw_closestream(others[x]); cw_closestream(realfiles[x]); cw_filerename(prependfile, recordfile, sfmt[x]); #if 0 cw_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile); #endif cw_filedelete(prependfile, sfmt[x]); } } if (rfmt) { if (cw_set_read_format(chan, rfmt)) { cw_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", cw_getformatname(rfmt), chan->name); } } if (outmsg) { if (outmsg > 1) { /* Let them know it worked */ cw_streamfile(chan, "auth-thankyou", chan->language); cw_waitstream(chan, ""); } } return res; } /* Channel group core functions */ int cw_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max) { int res=0; char tmp[256]; char *grp=NULL, *cat=NULL; if (!cw_strlen_zero(data)) { cw_copy_string(tmp, data, sizeof(tmp)); grp = tmp; cat = strchr(tmp, '@'); if (cat) { *cat = '\0'; cat++; } } if (!cw_strlen_zero(grp)) cw_copy_string(group, grp, group_max); else res = -1; if (cat) snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat); else cw_copy_string(category, GROUP_CATEGORY_PREFIX, category_max); return res; }
int cw_play_and_record(struct cw_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path) { int d; char *fmts; char comment[256]; int x, fmtcnt=1, res=-1,outmsg=0; struct cw_frame *f; struct cw_filestream *others[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; char *stringp=NULL; time_t start, end; struct cw_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) { cw_log(LOG_WARNING, "Error play_and_record called without duration pointer\n"); return -1; } cw_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 = cw_play_and_wait(chan, playfile); if (d > -1) d = cw_streamfile(chan, "beep",chan->language); if (!d) d = cw_waitstream(chan,""); if (d < 0) return -1; } fmts = cw_strdupa(fmt); stringp=fmts; strsep(&stringp, "|,"); cw_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = cw_strdupa(fmts); while((fmt = strsep(&stringp, "|,"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { cw_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; } sfmt[fmtcnt++] = cw_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] = cw_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700); cw_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]); if (!others[x]) { break; } } if (path) cw_unlock_path(path); if (maxsilence > 0) { sildet = cw_dsp_new(); /* Create the silence detector */ if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } cw_dsp_set_threshold(sildet, silencethreshold); rfmt = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); cw_dsp_free(sildet); return -1; } } /* Request a video update */ cw_indicate(chan, CW_CONTROL_VIDUPDATE); 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 = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_DEBUG, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = cw_read(chan); if (!f) break; if (f->frametype == CW_FRAME_VOICE) { /* write each format */ for (x=0;x<fmtcnt;x++) { res = cw_writestream(others[x], f); } /* Silence Detection */ if (maxsilence > 0) { dspsilence = 0; cw_dsp_silence(sildet, f, &dspsilence); if (dspsilence) totalsilence = dspsilence; else totalsilence = 0; if (totalsilence > maxsilence) { /* Ended happily with silence */ if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); cw_fr_free(f); gotsilence = 1; outmsg=2; break; } } /* Exit on any error */ if (res) { cw_log(LOG_WARNING, "Error writing frame\n"); cw_fr_free(f); break; } } else if (f->frametype == CW_FRAME_VIDEO) { /* Write only once */ cw_writestream(others[0], f); } else if (f->frametype == CW_FRAME_DTMF) { if (f->subclass == '#') { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); res = '#'; outmsg = 2; cw_fr_free(f); break; } if (f->subclass == '0') { /* Check for a '0' during message recording also, in case caller wants operator */ if (option_verbose > 2) cw_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass); res = '0'; outmsg = 0; cw_fr_free(f); break; } } if (maxtime) { time(&end); if (maxtime < (end - start)) { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); outmsg = 2; res = 't'; cw_fr_free(f); break; } } cw_fr_free(f); } if (end == start) time(&end); if (!f) { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "User hung up\n"); res = -1; outmsg=1; } } else { cw_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) cw_stream_rewind(others[x], totalsilence-200); else cw_stream_rewind(others[x], 200); } cw_truncstream(others[x]); cw_closestream(others[x]); } if (rfmt) { if (cw_set_read_format(chan, rfmt)) { cw_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", cw_getformatname(rfmt), chan->name); } } if (outmsg > 1) { /* Let them know recording is stopped */ if(!cw_streamfile(chan, "auth-thankyou", chan->language)) cw_waitstream(chan, ""); } if (sildet) cw_dsp_free(sildet); return res; }
int cw_control_streamfile(struct cw_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms) { long elapsed = 0, last_elapsed = 0; char *breaks = NULL; char *end = NULL; int blen = 2; int res; if (stop) blen += strlen(stop); if (pause) blen += strlen(pause); if (restart) blen += strlen(restart); if (blen > 2) { breaks = alloca(blen + 1); breaks[0] = '\0'; if (stop) strcat(breaks, stop); if (pause) strcat(breaks, pause); if (restart) strcat(breaks, restart); } if (chan->_state != CW_STATE_UP) res = cw_answer(chan); if (chan) cw_stopstream(chan); if (file) { if ((end = strchr(file,':'))) { if (!strcasecmp(end, ":end")) { *end = '\0'; end++; } } } for (;;) { struct timeval started = cw_tvnow(); if (chan) cw_stopstream(chan); res = cw_streamfile(chan, file, chan->language); if (!res) { if (end) { cw_seekstream(chan->stream, 0, SEEK_END); end=NULL; } res = 1; if (elapsed) { cw_stream_fastforward(chan->stream, elapsed); last_elapsed = elapsed - 200; } if (res) res = cw_waitstream_fr(chan, breaks, fwd, rev, skipms); else break; } if (res < 1) break; /* We go at next loop if we got the restart char */ if (restart && strchr(restart, res)) { cw_log(LOG_DEBUG, "we'll restart the stream here at next loop\n"); elapsed=0; /* To make sure the next stream will start at beginning */ continue; } if (pause != NULL && strchr(pause, res)) { elapsed = cw_tvdiff_ms(cw_tvnow(), started) + last_elapsed; for(;;) { if (chan) cw_stopstream(chan); res = cw_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) cw_stopstream(chan); return res; }
int cw_app_getvoice(struct cw_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec) { int res; struct cw_filestream *writer; int rfmt; int totalms=0, total; struct cw_frame *f; struct cw_dsp *sildet; /* Play prompt if requested */ if (prompt) { res = cw_streamfile(c, prompt, c->language); if (res < 0) return res; res = cw_waitstream(c,""); if (res < 0) return res; } rfmt = c->readformat; res = cw_set_read_format(c, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); return -1; } sildet = cw_dsp_new(); if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } writer = cw_writefile(dest, dstfmt, "Voice file", 0, 0, 0666); if (!writer) { cw_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt); cw_dsp_free(sildet); return -1; } for(;;) { if ((res = cw_waitfor(c, 2000)) < 0) { cw_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt); break; } if (res) { f = cw_read(c); if (!f) { cw_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt); break; } if ((f->frametype == CW_FRAME_DTMF) && (f->subclass == '#')) { /* Ended happily with DTMF */ cw_fr_free(f); break; } else if (f->frametype == CW_FRAME_VOICE) { cw_dsp_silence(sildet, f, &total); if (total > silence) { /* Ended happily with silence */ cw_fr_free(f); break; } totalms += f->samples / 8; if (totalms > maxsec * 1000) { /* Ended happily with too much stuff */ cw_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec); cw_fr_free(f); break; } res = cw_writestream(writer, f); if (res < 0) { cw_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest); cw_fr_free(f); break; } } cw_fr_free(f); } } res = cw_set_read_format(c, rfmt); if (res) cw_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name); cw_dsp_free(sildet); cw_closestream(writer); return 0; }
static int ivr_dispatch(struct cw_channel *chan, struct cw_ivr_option *option, char *exten, void *cbdata) { int res; int (*ivr_func)(struct cw_channel *, void *); char *c; char *n; switch(option->action) { case CW_ACTION_UPONE: return RES_UPONE; case CW_ACTION_EXIT: return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff); case CW_ACTION_REPEAT: return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff); case CW_ACTION_RESTART: return RES_RESTART ; case CW_ACTION_NOOP: return 0; case CW_ACTION_BACKGROUND: res = cw_streamfile(chan, (char *)option->adata, chan->language); if (!res) { res = cw_waitstream(chan, CW_DIGIT_ANY); } else { cw_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata); res = 0; } return res; case CW_ACTION_PLAYBACK: res = cw_streamfile(chan, (char *)option->adata, chan->language); if (!res) { res = cw_waitstream(chan, ""); } else { cw_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata); res = 0; } return res; case CW_ACTION_MENU: res = cw_ivr_menu_run_internal(chan, (struct cw_ivr_menu *)option->adata, cbdata); /* Do not pass entry errors back up, treat as though it was an "UPONE" */ if (res == -2) res = 0; return res; case CW_ACTION_WAITOPTION: res = cw_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10)); if (!res) return 't'; return res; case CW_ACTION_CALLBACK: ivr_func = option->adata; res = ivr_func(chan, cbdata); return res; case CW_ACTION_TRANSFER: res = cw_parseable_goto(chan, option->adata); return 0; case CW_ACTION_PLAYLIST: case CW_ACTION_BACKLIST: res = 0; c = cw_strdupa(option->adata); while((n = strsep(&c, ";"))) if ((res = cw_streamfile(chan, n, chan->language)) || (res = cw_waitstream(chan, (option->action == CW_ACTION_BACKLIST) ? CW_DIGIT_ANY : ""))) break; cw_stopstream(chan); return res; default: cw_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action); return 0; }; return -1; }
int cw_record_review(struct cw_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) { int silencethreshold = 128; int maxsilence=0; int res = 0; int cmd = 0; int max_attempts = 3; int attempts = 0; int recorded = 0; int message_exists = 0; /* Note that urgent and private are for flagging messages as such in the future */ /* barf if no pointer passed to store duration in */ if (duration == NULL) { cw_log(LOG_WARNING, "Error cw_record_review called without duration pointer\n"); return -1; } cmd = '3'; /* Want to start by recording */ while ((cmd >= 0) && (cmd != 't')) { switch (cmd) { case '1': if (!message_exists) { /* In this case, 1 is to record a message */ cmd = '3'; break; } else { cw_streamfile(chan, "vm-msgsaved", chan->language); cw_waitstream(chan, ""); cmd = 't'; return res; } case '2': /* Review */ cw_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n"); cw_streamfile(chan, recordfile, chan->language); cmd = cw_waitstream(chan, CW_DIGIT_ANY); break; case '3': message_exists = 0; /* Record */ if (recorded == 1) cw_verbose(VERBOSE_PREFIX_3 "Re-recording\n"); else cw_verbose(VERBOSE_PREFIX_3 "Recording\n"); recorded = 1; cmd = cw_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path); if (cmd == -1) { /* User has hung up, no options to give */ return cmd; } if (cmd == '0') { break; } else if (cmd == '*') { break; } else { /* If all is well, a message exists */ message_exists = 1; cmd = 0; } break; case '4': case '5': case '6': case '7': case '8': case '9': case '*': case '#': cmd = cw_play_and_wait(chan, "vm-sorry"); break; default: if (message_exists) { cmd = cw_play_and_wait(chan, "vm-review"); } else { cmd = cw_play_and_wait(chan, "vm-torerecord"); if (!cmd) cmd = cw_waitfordigit(chan, 600); } if (!cmd) cmd = cw_waitfordigit(chan, 6000); if (!cmd) { attempts++; } if (attempts > max_attempts) { cmd = 't'; } } } if (cmd == 't') cmd = 0; return cmd; }
static int privacy_exec (struct cw_channel *chan, int argc, char **argv) { char phone[30]; struct localuser *u; struct cw_config *cfg; char *s; int res=0; int retries; int maxretries = 3; int minlength = 10; int x; LOCAL_USER_ADD (u); if (!cw_strlen_zero(chan->cid.cid_num)) { if (option_verbose > 2) cw_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n"); pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS"); } else { /*Answer the channel if it is not already*/ if (chan->_state != CW_STATE_UP) { res = cw_answer(chan); if (res) { pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAIL"); LOCAL_USER_REMOVE(u); return 0; } } /*Read in the config file*/ cfg = cw_config_load(PRIV_CONFIG); /*Play unidentified call*/ res = cw_safe_sleep(chan, 1000); if (!res) res = cw_streamfile(chan, "privacy-unident", chan->language); if (!res) res = cw_waitstream(chan, ""); if (cfg && (s = cw_variable_retrieve(cfg, "general", "maxretries"))) { if (sscanf(s, "%d", &x) == 1) { maxretries = x; } else { cw_log(LOG_WARNING, "Invalid max retries argument\n"); } } if (cfg && (s = cw_variable_retrieve(cfg, "general", "minlength"))) { if (sscanf(s, "%d", &x) == 1) { minlength = x; } else { cw_log(LOG_WARNING, "Invalid min length argument\n"); } } /*Ask for 10 digit number, give 3 attempts*/ for (retries = 0; retries < maxretries; retries++) { if (!res ) res = cw_app_getdata(chan, "privacy-prompt", phone, sizeof(phone), 0); if (res < 0) break; /*Make sure we get at least our minimum of digits*/ if (strlen(phone) >= minlength ) break; else { res = cw_streamfile(chan, "privacy-incorrect", chan->language); if (!res) res = cw_waitstream(chan, ""); } } /*Got a number, play sounds and send them on their way*/ if ((retries < maxretries) && res == 1 ) { res = cw_streamfile(chan, "privacy-thankyou", chan->language); if (!res) res = cw_waitstream(chan, ""); cw_set_callerid (chan, phone, "Privacy Manager", NULL); if (option_verbose > 2) cw_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",phone); pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS"); } else { /* Flag Failure */ pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAIL"); } if (cfg) cw_config_destroy(cfg); } LOCAL_USER_REMOVE (u); return 0; }