/*! \brief SpeechCreate() Dialplan Application */ static int speech_create(struct ast_channel *chan, void *data) { struct ast_module_user *u = NULL; struct ast_speech *speech = NULL; struct ast_datastore *datastore = NULL; u = ast_module_user_add(chan); /* Request a speech object */ speech = ast_speech_new(data, AST_FORMAT_SLINEAR); if (speech == NULL) { /* Not available */ pbx_builtin_setvar_helper(chan, "ERROR", "1"); ast_module_user_remove(u); return 0; } datastore = ast_channel_datastore_alloc(&speech_datastore, NULL); if (datastore == NULL) { ast_speech_destroy(speech); pbx_builtin_setvar_helper(chan, "ERROR", "1"); ast_module_user_remove(u); return 0; } datastore->data = speech; ast_channel_datastore_add(chan, datastore); pbx_builtin_setvar_helper(chan, "ERROR", NULL); ast_module_user_remove(u); return 0; }
/*! \brief SpeechLoadGrammar(Grammar Name|Path) Dialplan Application */ static int speech_load(struct ast_channel *chan, void *data) { int res = 0, argc = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); char *argv[2], *args = NULL, *name = NULL, *path = NULL; args = ast_strdupa(data); u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } /* Parse out arguments */ argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc != 2) { ast_module_user_remove(u); return -1; } name = argv[0]; path = argv[1]; /* Load the grammar locally on the object */ res = ast_speech_grammar_load(speech, name, path); ast_module_user_remove(u); return res; }
/*! \brief SpeechDestroy() Dialplan Application */ static int speech_destroy(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); struct ast_datastore *datastore = NULL; u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } /* Destroy speech structure */ ast_speech_destroy(speech); datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL); if (datastore != NULL) { ast_channel_datastore_remove(chan, datastore); } ast_module_user_remove(u); return res; }
static int morsecode_exec(struct ast_channel *chan, void *data) { int res=0, ditlen, tone; char *digit; const char *ditlenc, *tonec; struct ast_module_user *u; u = ast_module_user_add(chan); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Syntax: Morsecode(<string>) - no argument found\n"); ast_module_user_remove(u); return 0; } /* Use variable MORESEDITLEN, if set (else 80) */ ditlenc = pbx_builtin_getvar_helper(chan, "MORSEDITLEN"); if (ast_strlen_zero(ditlenc) || (sscanf(ditlenc, "%30d", &ditlen) != 1)) { ditlen = 80; } /* Use variable MORSETONE, if set (else 800) */ tonec = pbx_builtin_getvar_helper(chan, "MORSETONE"); if (ast_strlen_zero(tonec) || (sscanf(tonec, "%30d", &tone) != 1)) { tone = 800; } for (digit = data; *digit; digit++) { int digit2 = *digit; char *dahdit; if (digit2 < 0) { continue; } for (dahdit = morsecode[digit2]; *dahdit; dahdit++) { if (*dahdit == '-') { playtone(chan, tone, 3 * ditlen); } else if (*dahdit == '.') { playtone(chan, tone, 1 * ditlen); } else { /* Account for ditlen of silence immediately following */ playtone(chan, 0, 2 * ditlen); } /* Pause slightly between each dit and dah */ playtone(chan, 0, 1 * ditlen); } /* Pause between characters */ playtone(chan, 0, 2 * ditlen); } ast_module_user_remove(u); return res; }
static int exec(struct ast_channel *chan, void *data, int dahdimode) { int res=-1; struct ast_module_user *u; int retrycnt = 0; int confflags = 0; int confno = 0; char confstr[80] = ""; u = ast_module_user_add(chan); if (!ast_strlen_zero(data)) { if (dahdimode) { if ((sscanf(data, "DAHDI/%30d", &confno) != 1) && (sscanf(data, "%30d", &confno) != 1)) { ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data); ast_module_user_remove(u); return 0; } } else { if ((sscanf(data, "Zap/%30d", &confno) != 1) && (sscanf(data, "%30d", &confno) != 1)) { ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data); ast_module_user_remove(u); return 0; } } } if (chan->_state != AST_STATE_UP) ast_answer(chan); while(!confno && (++retrycnt < 4)) { /* Prompt user for conference number */ confstr[0] = '\0'; res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0); if (res <0) goto out; if (sscanf(confstr, "%30d", &confno) != 1) confno = 0; } if (confno) { /* XXX Should prompt user for pin if pin is required XXX */ /* Run the conference */ res = conf_run(chan, confno, confflags); } out: /* Do the conference */ ast_module_user_remove(u); return res; }
static int steal_channel(struct ast_channel *chan, void *pattern) { int ret = 0; struct ast_module_user *u; struct ast_channel *cur; u = ast_module_user_add(chan); cur = find_matching_channel(chan, pattern, AST_STATE_UP); if (cur) { ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n", chan->name, cur->name); pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", cur->name); if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (cur->_bridge) { if (!ast_mutex_lock(&cur->_bridge->lock)) { ast_moh_stop(cur->_bridge); ast_mutex_unlock(&cur->_bridge->lock); } } if (ast_channel_masquerade(cur, chan)) { ast_log(LOG_ERROR, "unable to masquerade\n"); ret = -1; } ast_mutex_unlock(&cur->lock); ast_mutex_unlock(&chan->lock); } else { pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", ""); } ast_module_user_remove(u); return(ret); }
static int exec_exec(struct ast_channel *chan, void *data) { int res=0; struct ast_module_user *u; char *s, *appname, *endargs, args[MAXRESULT] = ""; struct ast_app *app; u = ast_module_user_add(chan); /* Check and parse arguments */ if (data) { s = ast_strdupa(data); appname = strsep(&s, "("); if (s) { endargs = strrchr(s, ')'); if (endargs) *endargs = '\0'; pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1); } if (appname) { app = pbx_findapp(appname); if (app) { res = pbx_exec(chan, app, args); } else { ast_log(LOG_WARNING, "Could not find application (%s)\n", appname); res = -1; } } } ast_module_user_remove(u); return res; }
static int echo_exec(struct ast_channel *chan, void *data) { int res = -1; int format; struct ast_module_user *u; u = ast_module_user_add(chan); format = ast_best_codec(chan->nativeformats); ast_set_write_format(chan, format); ast_set_read_format(chan, format); while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); if (!f) break; f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; if (ast_write(chan, f)) { ast_frfree(f); goto end; } if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) { res = 0; ast_frfree(f); goto end; } ast_frfree(f); } end: ast_module_user_remove(u); return res; }
/* Main application entry point */ static int pickup_exec(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u = NULL; char *tmp = ast_strdupa(data); char *exten = NULL, *context = NULL; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Pickup requires an argument (extension)!\n"); return -1; } u = ast_module_user_add(chan); /* Parse extension (and context if there) */ while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) { if ((context = strchr(exten, '@'))) *context++ = '\0'; if (context && !strcasecmp(context, PICKUPMARK)) { if (!pickup_by_mark(chan, exten)) break; } else { if (!pickup_by_exten(chan, exten, context ? context : chan->context)) break; } ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten); } ast_module_user_remove(u); return res; }
static int senddtmf_exec(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u; char *digits = NULL, *to = NULL; int timeout = 250; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "SendDTMF requires an argument (digits or *#aAbBcCdD)\n"); return 0; } u = ast_module_user_add(chan); digits = ast_strdupa(data); if ((to = strchr(digits,'|'))) { *to = '\0'; to++; timeout = atoi(to); } if (timeout <= 0) timeout = 250; res = ast_dtmf_stream(chan,NULL,digits,timeout); ast_module_user_remove(u); return res; }
static int readfile_exec(struct ast_channel *chan, void *data) { int res=0; struct ast_module_user *u; char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL; int len=0; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "ReadFile require an argument!\n"); return -1; } u = ast_module_user_add(chan); s = ast_strdupa(data); varname = strsep(&s, "="); file = strsep(&s, "|"); length = s; if (!varname || !file) { ast_log(LOG_ERROR, "No file or variable specified!\n"); ast_module_user_remove(u); return -1; } if (length) { if ((sscanf(length, "%30d", &len) != 1) || (len < 0)) { ast_log(LOG_WARNING, "%s is not a positive number, defaulting length to max\n", length); len = 0; } } if ((returnvar = ast_read_textfile(file))) { if (len > 0) { if (len < strlen(returnvar)) returnvar[len]='\0'; else ast_log(LOG_WARNING, "%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar)); } pbx_builtin_setvar_helper(chan, varname, returnvar); free(returnvar); } ast_module_user_remove(u); return res; }
static int log_exec(struct ast_channel *chan, void *data) { char *level, *ltext; struct ast_module_user *u; int lnum = -1; char extension[AST_MAX_EXTENSION + 5], context[AST_MAX_EXTENSION + 2]; u = ast_module_user_add(chan); if (ast_strlen_zero(data)) { ast_module_user_remove(u); return 0; } ltext = ast_strdupa(data); level = strsep(<ext, "|"); if (!strcasecmp(level, "ERROR")) { lnum = __LOG_ERROR; } else if (!strcasecmp(level, "WARNING")) { lnum = __LOG_WARNING; } else if (!strcasecmp(level, "NOTICE")) { lnum = __LOG_NOTICE; } else if (!strcasecmp(level, "DEBUG")) { lnum = __LOG_DEBUG; } else if (!strcasecmp(level, "VERBOSE")) { lnum = __LOG_VERBOSE; } else if (!strcasecmp(level, "DTMF")) { lnum = __LOG_DTMF; } else if (!strcasecmp(level, "EVENT")) { lnum = __LOG_EVENT; } else { ast_log(LOG_ERROR, "Unknown log level: '%s'\n", level); } if (lnum > -1) { snprintf(context, sizeof(context), "@ %s", chan->context); snprintf(extension, sizeof(extension), "Ext. %s", chan->exten); ast_log(lnum, extension, chan->priority, context, "%s\n", ltext); } ast_module_user_remove(u); return 0; }
/*! \brief SpeechStart() Dialplan Application */ static int speech_start(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } ast_speech_start(speech); ast_module_user_remove(u); return res; }
/*! \brief SpeechActivateGrammar(Grammar Name) Dialplan Application */ static int speech_activate(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } /* Activate the grammar on the speech object */ res = ast_speech_grammar_activate(speech, data); ast_module_user_remove(u); return res; }
/*! \brief SpeechUnloadGrammar(Grammar Name) Dialplan Application */ static int speech_unload(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } /* Unload the grammar */ res = ast_speech_grammar_unload(speech, data); ast_module_user_remove(u); return res; }
static int deltree_exec(struct ast_channel *chan, void *data) { char *argv, *family, *keytree; struct ast_module_user *u; u = ast_module_user_add(chan); argv = ast_strdupa(data); if (strchr(argv, '/')) { family = strsep(&argv, "/"); keytree = strsep(&argv, "\0"); if (!family || !keytree) { ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n"); ast_module_user_remove(u); return 0; } if (ast_strlen_zero(keytree)) keytree = 0; } else { family = argv; keytree = 0; } if (option_verbose > 2) { if (keytree) ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: family=%s, keytree=%s\n", family, keytree); else ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: family=%s\n", family); } if (ast_db_deltree(family, keytree)) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: Error deleting key from database.\n"); } ast_module_user_remove(u); return 0; }
static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) { int res; lua_State *L; struct ast_module_user *u = ast_module_user_add(chan); if (!u) { ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n"); return 0; } L = lua_get_state(chan); if (!L) { ast_module_user_remove(u); return 0; } res = lua_find_extension(L, context, exten, priority, &matchmore, 0); if (!chan) lua_close(L); ast_module_user_remove(u); return res; }
static int app_konferencecount_main(struct ast_channel* chan, ast_application_parameter data) { int res ; struct ast_module_user *u ; u = ast_module_user_add(chan); // call count thread function res = count_exec(chan, (const char *) data); ast_module_user_remove(u); return res ; }
static int app_vonferencecount_main(struct ast_channel* chan, const char* data) { int res ; struct ast_module_user *u ; u = ast_module_user_add(chan); // call count thread function res = count_exec( chan, data ) ; ast_module_user_remove(u); return res ; }
static int app_conference_main(struct ast_channel* chan, void* data) { int res ; struct ast_module_user *u ; u = ast_module_user_add(chan); // call member thread function res = member_exec( chan, data ) ; ast_module_user_remove(u); return res ; }
static int del_exec(struct ast_channel *chan, void *data) { char *argv, *family, *key; struct ast_module_user *u; static int deprecation_warning = 0; u = ast_module_user_add(chan); if (!deprecation_warning) { deprecation_warning = 1; ast_log(LOG_WARNING, "The DBdel application has been deprecated in favor of the DB_DELETE dialplan function!\n"); } argv = ast_strdupa(data); if (strchr(argv, '/')) { family = strsep(&argv, "/"); key = strsep(&argv, "\0"); if (!family || !key) { ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n"); ast_module_user_remove(u); return 0; } if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "DBdel: family=%s, key=%s\n", family, key); if (ast_db_del(family, key)) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "DBdel: Error deleting key from database.\n"); } } else { ast_log(LOG_DEBUG, "Ignoring, no parameters\n"); } ast_module_user_remove(u); return 0; }
/*! \brief SpeechProcessingSound(Sound File) Dialplan Application */ static int speech_processing_sound(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } if (speech->processing_sound != NULL) { free(speech->processing_sound); speech->processing_sound = NULL; } speech->processing_sound = strdup(data); ast_module_user_remove(u); return res; }
static int lookupblacklist_exec (struct ast_channel *chan, void *data) { char blacklist[1]; struct ast_module_user *u; int bl = 0; int priority_jump = 0; static int dep_warning = 0; u = ast_module_user_add(chan); if (!dep_warning) { dep_warning = 1; ast_log(LOG_WARNING, "LookupBlacklist is deprecated. Please use ${BLACKLIST()} instead.\n"); } if (!ast_strlen_zero(data)) { if (strchr(data, 'j')) priority_jump = 1; } if (chan->cid.cid_num) { if (!ast_db_get("blacklist", chan->cid.cid_num, blacklist, sizeof (blacklist))) { if (option_verbose > 2) ast_log(LOG_NOTICE, "Blacklisted number %s found\n",chan->cid.cid_num); bl = 1; } } if (chan->cid.cid_name) { if (!ast_db_get("blacklist", chan->cid.cid_name, blacklist, sizeof (blacklist))) { if (option_verbose > 2) ast_log (LOG_NOTICE,"Blacklisted name \"%s\" found\n",chan->cid.cid_name); bl = 1; } } if (bl) { if (priority_jump || ast_opt_priority_jumping) ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "FOUND"); } else pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "NOTFOUND"); ast_module_user_remove(u); return 0; }
static int verbose_exec(struct ast_channel *chan, void *data) { char *vtext; int vsize; struct ast_module_user *u; u = ast_module_user_add(chan); if (data) { char *tmp; vtext = ast_strdupa(data); tmp = strsep(&vtext, "|"); if (vtext) { if (sscanf(tmp, "%30d", &vsize) != 1) { vsize = 0; ast_log(LOG_WARNING, "'%s' is not a verboser number\n", vtext); } } else { vtext = tmp; vsize = 0; } if (option_verbose >= vsize) { switch (vsize) { case 0: ast_verbose("%s\n", vtext); break; case 1: ast_verbose(VERBOSE_PREFIX_1 "%s\n", vtext); break; case 2: ast_verbose(VERBOSE_PREFIX_2 "%s\n", vtext); break; case 3: ast_verbose(VERBOSE_PREFIX_3 "%s\n", vtext); break; default: ast_verbose(VERBOSE_PREFIX_4 "%s\n", vtext); } } } ast_module_user_remove(u); return 0; }
static int pickdown_channel(struct ast_channel *chan, void *pattern) { int ret = 0; struct ast_module_user *u; struct ast_channel *cur; u = ast_module_user_add(chan); cur = find_matching_channel(chan, pattern, AST_STATE_RINGING); if (cur) { ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n", chan->name, cur->name); pbx_builtin_setvar_helper(chan, "PICKDOWN_CHANNEL", cur->name); ast_softhangup_nolock(cur, AST_SOFTHANGUP_DEV); ast_mutex_unlock(&cur->lock); } else { pbx_builtin_setvar_helper(chan, "PICKDOWN_CHANNEL", ""); } ast_module_user_remove(u); return(ret); }
static int system_exec_helper(struct ast_channel *chan, void *data, int failmode) { int res=0; struct ast_module_user *u; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "System requires an argument(command)\n"); pbx_builtin_setvar_helper(chan, chanvar, "FAILURE"); return failmode; } u = ast_module_user_add(chan); /* Do our thing here */ res = ast_safe_system((char *)data); if ((res < 0) && (errno != ECHILD)) { ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data); pbx_builtin_setvar_helper(chan, chanvar, "FAILURE"); res = failmode; } else if (res == 127) { ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data); pbx_builtin_setvar_helper(chan, chanvar, "FAILURE"); res = failmode; } else { if (res < 0) res = 0; if (ast_opt_priority_jumping && res) ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); if (res != 0) pbx_builtin_setvar_helper(chan, chanvar, "APPERROR"); else pbx_builtin_setvar_helper(chan, chanvar, "SUCCESS"); res = 0; } ast_module_user_remove(u); return res; }
static int execif_exec(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u; char *myapp = NULL; char *mydata = NULL; char *expr = NULL; struct ast_app *app = NULL; u = ast_module_user_add(chan); expr = ast_strdupa(data); if ((myapp = strchr(expr,'|'))) { *myapp = '\0'; myapp++; if ((mydata = strchr(myapp,'|'))) { *mydata = '\0'; mydata++; } else mydata = ""; if (pbx_checkcondition(expr)) { if ((app = pbx_findapp(myapp))) { res = pbx_exec(chan, app, mydata); } else { ast_log(LOG_WARNING, "Could not find application! (%s)\n", myapp); res = -1; } } } else { ast_log(LOG_ERROR,"Invalid Syntax.\n"); res = -1; } ast_module_user_remove(u); return res; }
static int app_exec(struct ast_channel *chan, void *data) { struct ast_module_user *lu; struct playlist_entry *entry; const char *args = data; int child_stdin[2] = { 0,0 }; int child_stdout[2] = { 0,0 }; int child_stderr[2] = { 0,0 }; int res = -1; int test_available_fd = -1; int gen_active = 0; int pid; char *argv[32]; int argc = 1; char *buf, *command; FILE *child_commands = NULL; FILE *child_errors = NULL; FILE *child_events = NULL; struct ivr_localuser foo = { .playlist = AST_LIST_HEAD_INIT_VALUE, .finishlist = AST_LIST_HEAD_INIT_VALUE, }; struct ivr_localuser *u = &foo; sigset_t fullset, oldset; lu = ast_module_user_add(chan); sigfillset(&fullset); pthread_sigmask(SIG_BLOCK, &fullset, &oldset); u->abort_current_sound = 0; u->chan = chan; if (ast_strlen_zero(args)) { ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n"); ast_module_user_remove(lu); return -1; } buf = ast_strdupa(data); argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0])); if (pipe(child_stdin)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno)); goto exit; } if (pipe(child_stdout)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno)); goto exit; } if (pipe(child_stderr)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno)); goto exit; } if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (ast_activate_generator(chan, &gen, u) < 0) { ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n"); goto exit; } else gen_active = 1; pid = fork(); if (pid < 0) { ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); goto exit; } if (!pid) { /* child process */ int i; signal(SIGPIPE, SIG_DFL); pthread_sigmask(SIG_UNBLOCK, &fullset, NULL); if (ast_opt_high_priority) ast_set_priority(0); dup2(child_stdin[0], STDIN_FILENO); dup2(child_stdout[1], STDOUT_FILENO); dup2(child_stderr[1], STDERR_FILENO); for (i = STDERR_FILENO + 1; i < 1024; i++) close(i); execv(argv[0], argv); fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno)); _exit(1); } else { /* parent process */ int child_events_fd = child_stdin[1]; int child_commands_fd = child_stdout[0]; int child_errors_fd = child_stderr[0]; struct ast_frame *f; int ms; int exception; int ready_fd; int waitfds[2] = { child_errors_fd, child_commands_fd }; struct ast_channel *rchan; pthread_sigmask(SIG_SETMASK, &oldset, NULL); close(child_stdin[0]); child_stdin[0] = 0; close(child_stdout[1]); child_stdout[1] = 0; close(child_stderr[1]); child_stderr[1] = 0; if (!(child_events = fdopen(child_events_fd, "w"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n"); goto exit; } if (!(child_commands = fdopen(child_commands_fd, "r"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n"); goto exit; } if (!(child_errors = fdopen(child_errors_fd, "r"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n"); goto exit; } test_available_fd = open("/dev/null", O_RDONLY); setvbuf(child_events, NULL, _IONBF, 0); setvbuf(child_commands, NULL, _IONBF, 0); setvbuf(child_errors, NULL, _IONBF, 0); res = 0; while (1) { if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) { ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n"); res = -1; break; } if (ast_check_hangup(chan)) { ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n"); send_child_event(child_events, 'H', NULL, chan); res = -1; break; } ready_fd = 0; ms = 100; errno = 0; exception = 0; rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms); if (!AST_LIST_EMPTY(&u->finishlist)) { AST_LIST_LOCK(&u->finishlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) { send_child_event(child_events, 'F', entry->filename, chan); free(entry); } AST_LIST_UNLOCK(&u->finishlist); } if (rchan) { /* the channel has something */ f = ast_read(chan); if (!f) { ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n"); send_child_event(child_events, 'H', NULL, chan); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { send_child_event(child_events, f->subclass, NULL, chan); if (u->option_autoclear) { if (!u->abort_current_sound && !u->playing_silence) send_child_event(child_events, 'T', NULL, chan); AST_LIST_LOCK(&u->playlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { send_child_event(child_events, 'D', entry->filename, chan); free(entry); } if (!u->playing_silence) u->abort_current_sound = 1; AST_LIST_UNLOCK(&u->playlist); } } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n"); send_child_event(child_events, 'H', NULL, chan); ast_frfree(f); res = -1; break; } ast_frfree(f); } else if (ready_fd == child_commands_fd) { char input[1024]; if (exception || feof(child_commands)) { ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); res = -1; break; } if (!fgets(input, sizeof(input), child_commands)) continue; command = ast_strip(input); ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input); if (strlen(input) < 4) continue; if (input[0] == 'S') { if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); send_child_event(child_events, 'Z', NULL, chan); strcpy(&input[2], "exception"); } if (!u->abort_current_sound && !u->playing_silence) send_child_event(child_events, 'T', NULL, chan); AST_LIST_LOCK(&u->playlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { send_child_event(child_events, 'D', entry->filename, chan); free(entry); } if (!u->playing_silence) u->abort_current_sound = 1; entry = make_entry(&input[2]); if (entry) AST_LIST_INSERT_TAIL(&u->playlist, entry, list); AST_LIST_UNLOCK(&u->playlist); } else if (input[0] == 'A') { if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); send_child_event(child_events, 'Z', NULL, chan); strcpy(&input[2], "exception"); } entry = make_entry(&input[2]); if (entry) { AST_LIST_LOCK(&u->playlist); AST_LIST_INSERT_TAIL(&u->playlist, entry, list); AST_LIST_UNLOCK(&u->playlist); } } else if (input[0] == 'H') { ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]); send_child_event(child_events, 'H', NULL, chan); break; } else if (input[0] == 'O') { if (!strcasecmp(&input[2], "autoclear")) u->option_autoclear = 1; else if (!strcasecmp(&input[2], "noautoclear")) u->option_autoclear = 0; else ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]); } } else if (ready_fd == child_errors_fd) { char input[1024]; if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) { ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); res = -1; break; } if (fgets(input, sizeof(input), child_errors)) { command = ast_strip(input); ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command); } } else if ((ready_fd < 0) && ms) { if (errno == 0 || errno == EINTR) continue; ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno)); break; } } } exit: if (gen_active) ast_deactivate_generator(chan); if (child_events) fclose(child_events); if (child_commands) fclose(child_commands); if (child_errors) fclose(child_errors); if (test_available_fd > -1) { close(test_available_fd); } if (child_stdin[0]) close(child_stdin[0]); if (child_stdin[1]) close(child_stdin[1]); if (child_stdout[0]) close(child_stdout[0]); if (child_stdout[1]) close(child_stdout[1]); if (child_stderr[0]) close(child_stderr[0]); if (child_stderr[1]) close(child_stderr[1]); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) free(entry); ast_module_user_remove(lu); return res; }
/*! \brief SpeechBackground(Sound File|Timeout) Dialplan Application */ static int speech_background(struct ast_channel *chan, void *data) { unsigned int timeout = 0; int res = 0, done = 0, argc = 0, started = 0, quieted = 0, max_dtmf_len = 0; struct ast_module_user *u = NULL; struct ast_speech *speech = find_speech(chan); struct ast_frame *f = NULL; int oldreadformat = AST_FORMAT_SLINEAR; char dtmf[AST_MAX_EXTENSION] = ""; time_t start, current; struct ast_datastore *datastore = NULL; char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#'; const char *tmp2 = NULL; args = ast_strdupa(data); u = ast_module_user_add(chan); if (speech == NULL) { ast_module_user_remove(u); return -1; } /* If channel is not already answered, then answer it */ if (chan->_state != AST_STATE_UP && ast_answer(chan)) { ast_module_user_remove(u); return -1; } /* Record old read format */ oldreadformat = chan->readformat; /* Change read format to be signed linear */ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { ast_module_user_remove(u); return -1; } /* Parse out options */ argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])); if (argc > 0) { /* Yay sound file */ filename_tmp = ast_strdupa(argv[0]); if (!ast_strlen_zero(argv[1])) { if ((timeout = atoi(argv[1])) == 0) timeout = -1; } else timeout = 0; } /* See if the maximum DTMF length variable is set... we use a variable in case they want to carry it through their entire dialplan */ if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2)) max_dtmf_len = atoi(tmp2); /* See if a terminator is specified */ if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) { if (ast_strlen_zero(tmp2)) dtmf_terminator = '\0'; else dtmf_terminator = tmp2[0]; } /* Before we go into waiting for stuff... make sure the structure is ready, if not - start it again */ if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) { ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY); ast_speech_start(speech); } /* Ensure no streams are currently running */ ast_stopstream(chan); /* Okay it's streaming so go into a loop grabbing frames! */ while (done == 0) { /* If the filename is null and stream is not running, start up a new sound file */ if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) { /* Discard old stream information */ ast_stopstream(chan); /* Start new stream */ speech_streamfile(chan, filename, chan->language); } /* Run scheduled stuff */ ast_sched_runq(chan->sched); /* Yay scheduling */ res = ast_sched_wait(chan->sched); if (res < 0) { res = 1000; } /* If there is a frame waiting, get it - if not - oh well */ if (ast_waitfor(chan, res) > 0) { f = ast_read(chan); if (f == NULL) { /* The channel has hung up most likely */ done = 3; break; } } /* Do timeout check (shared between audio/dtmf) */ if ((!quieted || strlen(dtmf)) && started == 1) { time(¤t); if ((current-start) >= timeout) { done = 1; if (f) ast_frfree(f); break; } } /* Do checks on speech structure to see if it's changed */ ast_mutex_lock(&speech->lock); if (ast_test_flag(speech, AST_SPEECH_QUIET)) { if (chan->stream) ast_stopstream(chan); ast_clear_flag(speech, AST_SPEECH_QUIET); quieted = 1; } /* Check state so we can see what to do */ switch (speech->state) { case AST_SPEECH_STATE_READY: /* If audio playback has stopped do a check for timeout purposes */ if (chan->streamid == -1 && chan->timingfunc == NULL) ast_stopstream(chan); if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) { if (timeout == -1) { done = 1; if (f) ast_frfree(f); break; } time(&start); started = 1; } /* Write audio frame out to speech engine if no DTMF has been received */ if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) { ast_speech_write(speech, f->data, f->datalen); } break; case AST_SPEECH_STATE_WAIT: /* Cue up waiting sound if not already playing */ if (!strlen(dtmf)) { if (chan->stream == NULL) { if (speech->processing_sound != NULL) { if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) { speech_streamfile(chan, speech->processing_sound, chan->language); } } } else if (chan->streamid == -1 && chan->timingfunc == NULL) { ast_stopstream(chan); if (speech->processing_sound != NULL) { if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) { speech_streamfile(chan, speech->processing_sound, chan->language); } } } } break; case AST_SPEECH_STATE_DONE: /* Now that we are done... let's switch back to not ready state */ ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY); if (!strlen(dtmf)) { /* Copy to speech structure the results, if available */ speech->results = ast_speech_results_get(speech); /* Break out of our background too */ done = 1; /* Stop audio playback */ if (chan->stream != NULL) { ast_stopstream(chan); } } break; default: break; } ast_mutex_unlock(&speech->lock); /* Deal with other frame types */ if (f != NULL) { /* Free the frame we received */ switch (f->frametype) { case AST_FRAME_DTMF: if (dtmf_terminator != '\0' && f->subclass == dtmf_terminator) { done = 1; } else { if (chan->stream != NULL) { ast_stopstream(chan); } if (!started) { /* Change timeout to be 5 seconds for DTMF input */ timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5; started = 1; } time(&start); snprintf(tmp, sizeof(tmp), "%c", f->subclass); strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1); /* If the maximum length of the DTMF has been reached, stop now */ if (max_dtmf_len && strlen(dtmf) == max_dtmf_len) done = 1; } break; case AST_FRAME_CONTROL: switch (f->subclass) { case AST_CONTROL_HANGUP: /* Since they hung up we should destroy the speech structure */ done = 3; default: break; } default: break; } ast_frfree(f); f = NULL; } } if (strlen(dtmf)) { /* We sort of make a results entry */ speech->results = ast_calloc(1, sizeof(*speech->results)); if (speech->results != NULL) { ast_speech_dtmf(speech, dtmf); speech->results->score = 1000; speech->results->text = strdup(dtmf); speech->results->grammar = strdup("dtmf"); } ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY); } /* See if it was because they hung up */ if (done == 3) { /* Destroy speech structure */ ast_speech_destroy(speech); datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL); if (datastore != NULL) { ast_channel_datastore_remove(chan, datastore); } } else { /* Channel is okay so restore read format */ ast_set_read_format(chan, oldreadformat); } ast_module_user_remove(u); return 0; }
static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) { int res, error_func; lua_State *L; struct ast_module_user *u = ast_module_user_add(chan); if (!u) { ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n"); return -1; } L = lua_get_state(chan); if (!L) { ast_module_user_remove(u); return -1; } lua_pushcfunction(L, &lua_error_function); error_func = lua_gettop(L); /* push the extension function onto the stack */ if (!lua_find_extension(L, context, exten, priority, &exists, 1)) { lua_pop(L, 1); /* pop the debug function */ ast_log(LOG_ERROR, "Could not find extension %s in context %s\n", exten, context); if (!chan) lua_close(L); ast_module_user_remove(u); return -1; } lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); if (lua_toboolean(L, -1)) { ast_autoservice_start(chan); } lua_pop(L, 1); lua_update_registry(L, context, exten, priority); lua_pushstring(L, context); lua_pushstring(L, exten); res = lua_pcall(L, 2, 0, error_func); if (res) { if (res == LUA_ERRRUN) { res = -1; if (lua_isnumber(L, -1)) { res = lua_tointeger(L, -1); if (res == LUA_GOTO_DETECTED) { res = 0; } } else if (lua_isstring(L, -1)) { const char *error = lua_tostring(L, -1); ast_log(LOG_ERROR, "Error executing lua extension: %s\n", error); } } else if (res == LUA_ERRERR) { res = -1; ast_log(LOG_ERROR, "Error in the lua error handler (this is probably a bug in pbx_lua)\n"); } else if (res == LUA_ERRMEM) { res = -1; ast_log(LOG_ERROR, "Memory allocation error\n"); } lua_pop(L, 1); } lua_remove(L, error_func); lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); if (lua_toboolean(L, -1)) { ast_autoservice_stop(chan); } lua_pop(L, 1); if (!chan) lua_close(L); ast_module_user_remove(u); return res; }