int start_profiling(void) { struct app_list_t *app = NULL; const struct app_info_t *app_info = NULL; int res = 0; app_info = app_info_get_first(&app); if (app_info == NULL) { LOGE("No app info found\n"); return -1; } // remove previous screen capture files remove_indir(SCREENSHOT_DIR); if (mkdir(SCREENSHOT_DIR, 0777) == -1 && errno != EEXIST) { GETSTRERROR(errno, buf); LOGW("Failed to create directory for screenshot : %s\n", buf); } set_label_for_all(SCREENSHOT_DIR); if (samplingStart() < 0) { LOGE("Cannot start sampling\n"); res = -1; goto exit; } if (IS_OPT_SET(FL_RECORDING)) add_input_events(); while (app_info != NULL) { if (exec_app(app_info)) { LOGE("Cannot exec app\n"); res = -1; goto recording_stop; } app_info = app_info_get_next(&app); } if (start_app_launch_timer(get_apps_to_run()) < 0) { res = -1; goto recording_stop; } goto exit; recording_stop: if (IS_OPT_SET(FL_RECORDING)) del_input_events(); samplingStop(); exit: LOGI("return %d\n", res); return res; }
/* This is where we actually charge the guy This can be called anytime a call is in progress or at the end of a call before the session is destroyed */ static switch_status_t do_billing(switch_core_session_t *session) { /* FS vars we will use */ switch_channel_t *channel; switch_caller_profile_t *profile; /* Local vars */ nibble_data_t *nibble_data; switch_time_t ts = switch_micro_time_now(); double billamount; char date[80] = ""; char *uuid; switch_size_t retsize; switch_time_exp_t tm; const char *billrate; const char *billincrement; const char *billaccount; double nobal_amt = globals.nobal_amt; double lowbal_amt = globals.lowbal_amt; double balance; if (!session) { /* Why are we here? */ return SWITCH_STATUS_SUCCESS; } uuid = switch_core_session_get_uuid(session); /* Get channel var */ if (!(channel = switch_core_session_get_channel(session))) { return SWITCH_STATUS_SUCCESS; } /* Variables kept in FS but relevant only to this module */ billrate = switch_channel_get_variable(channel, "nibble_rate"); billincrement = switch_channel_get_variable(channel, "nibble_increment"); billaccount = switch_channel_get_variable(channel, "nibble_account"); if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) { nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt")); } if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) { lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt")); } /* Return if there's no billing information on this session */ if (!billrate || !billaccount) { return SWITCH_STATUS_SUCCESS; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Attempting to bill at $%s per minute to account %s\n", billrate, billaccount); /* Get caller profile info from channel */ profile = switch_channel_get_caller_profile(channel); if (!profile || !profile->times) { /* No caller profile (why would this happen?) */ return SWITCH_STATUS_SUCCESS; } if (profile->times->answered < 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Not billing %s - call is not in answered state\n", billaccount); /* See if this person has enough money left to continue the call */ balance = get_balance(billaccount, channel); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f\n", balance, nobal_amt); if (balance <= nobal_amt) { /* Not enough money - reroute call to nobal location */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below allowed amount of %f! (Account %s)\n", balance, nobal_amt, billaccount); transfer_call(session, globals.nobal_action); } return SWITCH_STATUS_SUCCESS; } /* Lock this session's data for this module while we tinker with it */ if (globals.mutex) { switch_mutex_lock(globals.mutex); } /* Get our nibble data var. This will be NULL if it's our first call here for this session */ nibble_data = (nibble_data_t *) switch_channel_get_private(channel, "_nibble_data_"); /* Are we in paused mode? If so, we don't do anything here - go back! */ if (nibble_data && (nibble_data->pausets > 0)) { if (globals.mutex) { switch_mutex_unlock(globals.mutex); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Received heartbeat, but we're paused - ignoring\n"); return SWITCH_STATUS_SUCCESS; } /* Have we done any billing on this channel yet? If no, set up vars for doing so */ if (!nibble_data) { nibble_data = switch_core_session_alloc(session, sizeof(*nibble_data)); memset(nibble_data, 0, sizeof(*nibble_data)); /* Setup new billing data (based on call answer time, in case this module started late with active calls) */ nibble_data->lastts = profile->times->answered; /* Set the initial answer time to match when the call was really answered */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Beginning new billing on %s\n", uuid); } switch_time_exp_lt(&tm, nibble_data->lastts); switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%d seconds passed since last bill time of %s\n", (int) ((ts - nibble_data->lastts) / 1000000), date); if ((ts - nibble_data->lastts) >= 0) { /* If billincrement is set we bill by it and not by time elapsed */ if (!(switch_strlen_zero(billincrement))) { switch_time_t chargedunits = (ts - nibble_data->lastts) / 1000000 <= atol(billincrement) ? atol(billincrement) * 1000000 : (switch_time_t)(ceil((ts - nibble_data->lastts) / (atol(billincrement) * 1000000.0))) * atol(billincrement) * 1000000; billamount = (atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments; /* Account for the prepaid amount */ nibble_data->lastts += chargedunits; } else { /* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */ billamount = (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments; /* Update the last time we billed */ nibble_data->lastts = ts; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount, uuid, nibble_data->total); /* DO ODBC BILLING HERE and reset counters if it's successful! */ if (bill_event(billamount, billaccount, channel) == SWITCH_STATUS_SUCCESS) { /* Increment total cost */ nibble_data->total += billamount; /* Reset manual billing adjustments from pausing */ nibble_data->bill_adjustments = 0; /* Update channel variable with current billing */ switch_channel_set_variable_printf(channel, "nibble_total_billed", "%f", nibble_data->total); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n"); } } else { if (switch_strlen_zero(billincrement)) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid); } /* Save this location */ if (channel) { switch_channel_set_private(channel, "_nibble_data_", nibble_data); /* don't verify balance and transfer to nobal if we're done with call */ if (switch_channel_get_state(channel) != CS_REPORTING && switch_channel_get_state(channel) != CS_HANGUP) { balance = get_balance(billaccount, channel); /* See if we've achieved low balance */ if (!nibble_data->lowbal_action_executed && balance <= lowbal_amt) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below low balance amount of %f! (Account %s)\n", balance, lowbal_amt, billaccount); if (exec_app(session, globals.lowbal_action) != SWITCH_STATUS_SUCCESS) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Low balance action didn't execute\n"); else nibble_data->lowbal_action_executed = 1; } /* See if this person has enough money left to continue the call */ if (balance <= nobal_amt) { /* Not enough money - reroute call to nobal location */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Balance of %f fell below allowed amount of %f! (Account %s)\n", balance, nobal_amt, billaccount); /* IMPORTANT: Billing must be paused before the transfer occurs! This prevents infinite loops, since the transfer will result */ /* in nibblebill checking the call again in the routing process for an allowed balance! */ /* If you intend to give the user the option to re-up their balance, you must clear & resume billing once the balance is updated! */ nibblebill_pause(session); transfer_call(session, globals.nobal_action); } } } /* Done changing - release lock */ if (globals.mutex) { switch_mutex_unlock(globals.mutex); } /* Go check if this call is allowed to continue */ return SWITCH_STATUS_SUCCESS; }
static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *caller_profile, switch_xml_t xexten, switch_caller_extension_t **extension, const char *exten_name, int recur) { switch_xml_t xcond, xaction, xexpression, xregex; switch_channel_t *channel = switch_core_session_get_channel(session); int proceed = 0, save_proceed = 0; char *expression_expanded = NULL, *field_expanded = NULL; switch_regex_t *re = NULL, *save_re = NULL; int offset = 0; const char *tmp, *tzoff = NULL, *tzname = NULL, *req_nesta = NULL; char nbuf[128] = ""; int req_nest = 1; char space[MAX_RECUR_SPACE] = ""; const char *orig_exten_name = exten_name; check_tz(); if (!exten_name) { exten_name = "_anon_"; } if (!orig_exten_name) { orig_exten_name = "_anon_"; } if (recur) { int i, j = 0, k = 0; if (recur > MAX_RECUR) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Recursion LIMIT!\n"); return 0; } switch_snprintf(nbuf, sizeof(nbuf), "%s_recur_%d", exten_name, recur); exten_name = nbuf; space[j++] = '|'; for (i = 0; i < recur; i++) { for (k = 0; k < RECUR_SPACE; k++) { if (i == recur-1 && k == RECUR_SPACE-1) { space[j++] = ' '; } else { space[j++] = '-'; } } } if ((req_nesta = switch_xml_attr(xexten, "require-nested"))) { req_nest = switch_true(req_nesta); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: Processing recursive conditions level:%d [%s] require-nested=%s\n", space, recur, exten_name, req_nest ? "TRUE" : "FALSE"); } else { if ((tmp = switch_xml_attr(xexten, "name"))) { exten_name = tmp; } } for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next) { char *field = NULL; char *do_break_a = NULL; char *expression = NULL, *save_expression = NULL, *save_field_data = NULL; char *regex_rule = NULL; const char *field_data = NULL; int ovector[30]; switch_bool_t anti_action = SWITCH_TRUE; break_t do_break_i = BREAK_ON_FALSE; int time_match; check_tz(); time_match = switch_xml_std_datetime_check(xcond, tzoff ? &offset : NULL, tzname); switch_safe_free(field_expanded); switch_safe_free(expression_expanded); field = (char *) switch_xml_attr(xcond, "field"); if ((do_break_a = (char *) switch_xml_attr(xcond, "break"))) { if (!strcasecmp(do_break_a, "on-true")) { do_break_i = BREAK_ON_TRUE; } else if (!strcasecmp(do_break_a, "on-false")) { do_break_i = BREAK_ON_FALSE; } else if (!strcasecmp(do_break_a, "always")) { do_break_i = BREAK_ALWAYS; } else if (!strcasecmp(do_break_a, "never")) { do_break_i = BREAK_NEVER; } else { do_break_a = NULL; } } if (switch_xml_child(xcond, "condition")) { if (!(proceed = parse_exten(session, caller_profile, xcond, extension, orig_exten_name, recur + 1))) { if (do_break_i == BREAK_NEVER) { continue; } goto done; } } if (time_match == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/Time Match (PASS) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); anti_action = SWITCH_FALSE; proceed = 1; } else if (time_match == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); } if ((regex_rule = (char *) switch_xml_attr(xcond, "regex"))) { int all = !strcasecmp(regex_rule, "all"); int xor = !strcasecmp(regex_rule, "xor"); int pass = 0; int fail = 0; int total = 0; switch_channel_del_variable_prefix(channel, "DP_REGEX_MATCH"); for (xregex = switch_xml_child(xcond, "regex"); xregex; xregex = xregex->next) { check_tz(); time_match = switch_xml_std_datetime_check(xregex, tzoff ? &offset : NULL, tzname); if (time_match == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/Time Match (PASS) [%s]\n", space, switch_channel_get_name(channel), exten_name); anti_action = SWITCH_FALSE; } else if (time_match == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Date/TimeMatch (FAIL) [%s]\n", space, switch_channel_get_name(channel), exten_name); } if ((xexpression = switch_xml_child(xregex, "expression"))) { expression = switch_str_nil(xexpression->txt); } else { expression = (char *) switch_xml_attr_soft(xregex, "expression"); } if ((expression_expanded = switch_channel_expand_variables(channel, expression)) == expression) { expression_expanded = NULL; } else { expression = expression_expanded; } total++; field = (char *) switch_xml_attr(xregex, "field"); if (field) { if (strchr(field, '$')) { if ((field_expanded = switch_channel_expand_variables(channel, field)) == field) { field_expanded = NULL; field_data = field; } else { field_data = field_expanded; } } else { field_data = switch_caller_get_field_by_name(caller_profile, field); } if (!field_data) { field_data = ""; } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); pass++; if (!all && !xor) break; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); fail++; if (all && !xor) break; } } else if (time_match == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Absolute Condition [%s] match=%s\n", space, switch_channel_get_name(channel), exten_name, all ? "all" : "any"); pass++; proceed = 1; if (!all && !xor) break; } else if (time_match == 1) { pass++; proceed = 1; if (!all && !xor) break; } if (field && strchr(expression, '(')) { char var[256]; switch_snprintf(var, sizeof(var), "DP_REGEX_MATCH_%d", total); switch_channel_set_variable(channel, var, NULL); switch_capture_regex(re, proceed, field_data, ovector, var, switch_regex_set_var_callback, session); switch_safe_free(save_expression); switch_safe_free(save_field_data); switch_regex_safe_free(save_re); save_expression = strdup(expression); save_field_data = strdup(field_data); save_re = re; save_proceed = proceed; re = NULL; } switch_regex_safe_free(re); switch_safe_free(field_expanded); switch_safe_free(expression_expanded); } if (xor) { if (pass == 1) { anti_action = SWITCH_FALSE; } } else { if ((all && !fail) || (!all && pass)) { anti_action = SWITCH_FALSE; } } switch_safe_free(field_expanded); switch_safe_free(expression_expanded); } else { if ((xexpression = switch_xml_child(xcond, "expression"))) { expression = switch_str_nil(xexpression->txt); } else { expression = (char *) switch_xml_attr_soft(xcond, "expression"); } if ((expression_expanded = switch_channel_expand_variables(channel, expression)) == expression) { expression_expanded = NULL; } else { expression = expression_expanded; } if (field) { if (strchr(field, '$')) { if ((field_expanded = switch_channel_expand_variables(channel, field)) == field) { field_expanded = NULL; field_data = field; } else { field_data = field_expanded; } } else { field_data = switch_caller_get_field_by_name(caller_profile, field); } if (!field_data) { field_data = ""; } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); anti_action = SWITCH_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); } } else if (time_match == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Absolute Condition [%s]\n", space, switch_channel_get_name(channel), exten_name); anti_action = SWITCH_FALSE; proceed = 1; } } if (save_re) { re = save_re; save_re = NULL; expression = expression_expanded = save_expression; save_expression = NULL; field_data = field_expanded = save_field_data; field = (char *) field_data; save_field_data = NULL; proceed = save_proceed; } if (anti_action) { for (xaction = switch_xml_child(xcond, "anti-action"); xaction; xaction = xaction->next) { const char *application = switch_xml_attr_soft(xaction, "application"); const char *loop = switch_xml_attr(xaction, "loop"); const char *data; const char *inline_ = switch_xml_attr_soft(xaction, "inline"); int xinline = switch_true(inline_); int loop_count = 1; if (!zstr(xaction->txt)) { data = xaction->txt; } else { data = (char *) switch_xml_attr_soft(xaction, "data"); } if (!*extension) { if ((*extension = switch_caller_extension_new(session, exten_name, caller_profile->destination_number)) == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); proceed = 0; goto done; } } if (loop) { loop_count = atoi(loop); } for (;loop_count > 0; loop_count--) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s ANTI-Action %s(%s) %s\n", space, switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); if (xinline) { exec_app(session, application, data); } else { switch_caller_extension_add_application(session, *extension, application, data); } } proceed = 1; } } else { if (field && strchr(expression, '(')) { switch_channel_set_variable(channel, "DP_MATCH", NULL); switch_capture_regex(re, proceed, field_data, ovector, "DP_MATCH", switch_regex_set_var_callback, session); } for (xaction = switch_xml_child(xcond, "action"); xaction; xaction = xaction->next) { char *application = (char *) switch_xml_attr_soft(xaction, "application"); const char *loop = switch_xml_attr(xaction, "loop"); char *data = NULL; char *substituted = NULL; uint32_t len = 0; char *app_data = NULL; const char *inline_ = switch_xml_attr_soft(xaction, "inline"); int xinline = switch_true(inline_); int loop_count = 1; if (!zstr(xaction->txt)) { data = xaction->txt; } else { data = (char *) switch_xml_attr_soft(xaction, "data"); } if (field && strchr(expression, '(')) { len = (uint32_t) (strlen(data) + strlen(field_data) + 10) * proceed; if (!(substituted = malloc(len))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); proceed = 0; goto done; } memset(substituted, 0, len); switch_perform_substitution(re, proceed, data, field_data, substituted, len, ovector); app_data = substituted; } else { app_data = data; } if (!*extension) { if ((*extension = switch_caller_extension_new(session, exten_name, caller_profile->destination_number)) == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); proceed = 0; goto done; } } if (loop) { loop_count = atoi(loop); } for (;loop_count > 0; loop_count--) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "%sDialplan: %s Action %s(%s) %s\n", space, switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); if (xinline) { exec_app(session, application, app_data); } else { switch_caller_extension_add_application(session, *extension, application, app_data); } } switch_safe_free(substituted); } } switch_regex_safe_free(re); if (((anti_action == SWITCH_FALSE && do_break_i == BREAK_ON_TRUE) || (anti_action == SWITCH_TRUE && do_break_i == BREAK_ON_FALSE)) || do_break_i == BREAK_ALWAYS) { break; } } done: switch_regex_safe_free(re); switch_safe_free(field_expanded); switch_safe_free(expression_expanded); if (!req_nest) proceed = 1; return proceed; }
static int run_session (const char *dbus_daemon, const char *config_file, char *bus_address, char **argv, int prog_arg) { pid_t bus_pid; pid_t app_pid; int bus_address_pipe[2] = { 0, 0 }; if (pipe (bus_address_pipe) < 0) { fprintf (stderr, "%s: failed to create pipe: %s\n", me, strerror (errno)); return 127; } /* Make sure our output buffers aren't redundantly printed by both the * parent and the child */ fflush (stdout); fflush (stderr); bus_pid = fork (); if (bus_pid < 0) { fprintf (stderr, "%s: failed to fork: %s\n", me, strerror (errno)); return 127; } if (bus_pid == 0) { /* child */ exec_dbus_daemon (dbus_daemon, bus_address_pipe, config_file); /* not reached */ return 127; } close (bus_address_pipe[PIPE_WRITE_END]); switch (read_line (bus_address_pipe[PIPE_READ_END], bus_address, MAX_ADDR_LEN)) { case READ_STATUS_OK: break; case READ_STATUS_EOF: fprintf (stderr, "%s: EOF reading address from bus daemon\n", me); return 127; break; case READ_STATUS_ERROR: fprintf (stderr, "%s: error reading address from bus daemon: %s\n", me, strerror (errno)); return 127; break; default: _dbus_assert_not_reached ("invalid read result"); } close (bus_address_pipe[PIPE_READ_END]); if (!dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", bus_address) || !dbus_setenv ("DBUS_SESSION_BUS_PID", NULL) || !dbus_setenv ("DBUS_SESSION_BUS_WINDOWID", NULL) || !dbus_setenv ("DBUS_STARTER_ADDRESS", NULL) || !dbus_setenv ("DBUS_STARTER_BUS_TYPE", NULL)) oom (); fflush (stdout); fflush (stderr); app_pid = fork (); if (app_pid < 0) { fprintf (stderr, "%s: failed to fork: %s\n", me, strerror (errno)); return 127; } if (app_pid == 0) { /* child */ exec_app (prog_arg, argv); /* not reached */ return 127; } while (1) { int child_status; pid_t child_pid = waitpid (-1, &child_status, 0); if (child_pid == (pid_t) -1) { int errsv = errno; if (errsv == EINTR) continue; /* shouldn't happen: the only other documented errors are ECHILD, * which shouldn't happen because we terminate when all our children * have died, and EINVAL, which would indicate programming error */ fprintf (stderr, "%s: waitpid() failed: %s\n", me, strerror (errsv)); return 127; } else if (child_pid == bus_pid) { /* no need to kill it, now */ bus_pid = 0; if (WIFEXITED (child_status)) fprintf (stderr, "%s: dbus-daemon exited with code %d\n", me, WEXITSTATUS (child_status)); else if (WIFSIGNALED (child_status)) fprintf (stderr, "%s: dbus-daemon terminated by signal %d\n", me, WTERMSIG (child_status)); else fprintf (stderr, "%s: dbus-daemon died or something\n", me); } else if (child_pid == app_pid) { if (bus_pid != 0) kill (bus_pid, SIGTERM); if (WIFEXITED (child_status)) return WEXITSTATUS (child_status); /* if it died from a signal, behave like sh(1) */ if (WIFSIGNALED (child_status)) return 128 + WTERMSIG (child_status); /* I give up (this should never be reached) */ fprintf (stderr, "%s: child process died or something\n", me); return 127; } else { fprintf (stderr, "%s: ignoring unknown child process %ld\n", me, (long) child_pid); } } return 0; }
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *session, switch_ivr_menu_t *stack, char *name, void *obj) { int reps = 0, errs = 0, timeouts = 0, match = 0, running = 1; char *greeting_sound = NULL, *aptr = NULL; char arg[512]; switch_ivr_action_t todo = SWITCH_IVR_ACTION_DIE; switch_ivr_menu_action_t *ap; switch_ivr_menu_t *menu; switch_channel_t *channel; switch_status_t status = SWITCH_STATUS_SUCCESS; if (++stack->stack_count > 12) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Too many levels of recursion.\n"); switch_goto_status(SWITCH_STATUS_FALSE, end); } if (!session || !stack || zstr(name)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid menu context\n"); switch_goto_status(SWITCH_STATUS_FALSE, end); } channel = switch_core_session_get_channel(session); if (!(menu = switch_ivr_menu_find(stack, name))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Menu!\n"); switch_goto_status(SWITCH_STATUS_FALSE, end); } if (!zstr(menu->tts_engine) && !zstr(menu->tts_voice)) { switch_channel_set_variable(channel, "tts_engine", menu->tts_engine); switch_channel_set_variable(channel, "tts_voice", menu->tts_voice); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name); switch_channel_set_variable(channel, "ivr_menu_status", "success"); if (!zstr(menu->pin)) { char digit_buffer[128] = ""; char *digits_regex = switch_core_session_sprintf(session, "^%s$", menu->pin); if (switch_play_and_get_digits(session, strlen(menu->pin), strlen(menu->pin), 3, 3000, "#", menu->prompt_pin_file, menu->bad_pin_file, NULL, digit_buffer, sizeof(digit_buffer), digits_regex, 10000, NULL) != SWITCH_STATUS_SUCCESS) { switch_goto_status(SWITCH_STATUS_FALSE, end); } } for (reps = 0; running && status == SWITCH_STATUS_SUCCESS; reps++) { if (!switch_channel_ready(channel)) { break; } if (errs == menu->max_failures) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Maximum failures\n"); switch_channel_set_variable(channel, "ivr_menu_status", "failure"); if (!zstr(menu->exec_on_max_fail)) { exec_app(session, menu->exec_on_max_fail); } break; } if (timeouts == menu->max_timeouts) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Maximum timeouts\n"); switch_channel_set_variable(channel, "ivr_menu_status", "timeout"); if (!zstr(menu->exec_on_max_timeout)) { exec_app(session, menu->exec_on_max_timeout); } break; } if (reps > 0 && menu->short_greeting_sound) { greeting_sound = menu->short_greeting_sound; } else { greeting_sound = menu->greeting_sound; } match = 0; aptr = NULL; memset(arg, 0, sizeof(arg)); memset(menu->buf, 0, menu->inlen + 1); if (play_and_collect(session, menu, greeting_sound, menu->inlen) == SWITCH_STATUS_TIMEOUT && *menu->buf == '\0') { timeouts++; continue; } if (*menu->buf != '\0') { for (ap = menu->actions; ap; ap = ap->next) { int ok = 0; char substituted[1024]; char *use_arg = ap->arg; if (!zstr(menu->tts_engine) && !zstr(menu->tts_voice)) { switch_channel_set_variable(channel, "tts_engine", menu->tts_engine); switch_channel_set_variable(channel, "tts_voice", menu->tts_voice); } if (ap->re) { switch_regex_t *re = NULL; int ovector[30]; if ((ok = switch_regex_perform(menu->buf, ap->bind, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_perform_substitution(re, ok, ap->arg, menu->buf, substituted, sizeof(substituted), ovector); use_arg = substituted; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "action regex [%s] [%s] [%d]\n", menu->buf, ap->bind, ok); switch_regex_safe_free(re); } else { ok = !strcmp(menu->buf, ap->bind); } if (ok) { match++; errs = 0; if (ap->function) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "IVR function on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, use_arg); todo = ap->function(menu, use_arg, arg, sizeof(arg), obj); aptr = arg; } else { todo = ap->ivr_action; aptr = use_arg; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "IVR action on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, aptr); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_menu_execute todo=[%d]\n", todo); switch (todo) { case SWITCH_IVR_ACTION_DIE: status = SWITCH_STATUS_FALSE; break; case SWITCH_IVR_ACTION_PLAYSOUND: status = switch_ivr_play_file(session, NULL, aptr, NULL); break; case SWITCH_IVR_ACTION_EXECMENU: if (!strcmp(aptr, menu->name)) { status = SWITCH_STATUS_SUCCESS; } else { reps = -1; status = switch_ivr_menu_execute(session, stack, aptr, obj); } break; case SWITCH_IVR_ACTION_EXECAPP: { switch_application_interface_t *application_interface; char *app_name; char *app_arg = NULL; status = SWITCH_STATUS_FALSE; if (!zstr(aptr)) { app_name = switch_core_session_strdup(session, aptr); if ((app_arg = strchr(app_name, ' '))) { *app_arg++ = '\0'; } if ((application_interface = switch_loadable_module_get_application_interface(app_name))) { if (!zstr(menu->transfer_sound) && !strcmp(app_name, "transfer")) { status = play_and_collect(session, menu, menu->transfer_sound, 0); } switch_core_session_exec(session, application_interface, app_arg); UNPROTECT_INTERFACE(application_interface); status = SWITCH_STATUS_SUCCESS; } } } break; case SWITCH_IVR_ACTION_BACK: running = 0; status = SWITCH_STATUS_SUCCESS; break; case SWITCH_IVR_ACTION_TOMAIN: switch_set_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN); status = SWITCH_STATUS_BREAK; break; case SWITCH_IVR_ACTION_NOOP: status = SWITCH_STATUS_SUCCESS; break; default: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid TODO!\n"); break; } } } if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) { /* top level */ if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { /* catch the fallback and recover */ switch_clear_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN); status = SWITCH_STATUS_SUCCESS; running = 1; continue; } } } if (!match) { if (*menu->buf) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "IVR menu '%s' caught invalid input '%s'\n", menu->name, menu->buf); if (menu->invalid_sound) { play_and_collect(session, menu, menu->invalid_sound, 0); } } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "IVR menu '%s' no input detected\n", menu->name); } errs++; /* breaks are ok too */ if (SWITCH_STATUS_IS_BREAK(status)) { status = SWITCH_STATUS_SUCCESS; } } } if (stack->stack_count == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "exit-sound '%s'\n", menu->exit_sound); if (!zstr(menu->exit_sound)) { status = play_and_collect(session, menu, menu->exit_sound, 0); } } end: stack->stack_count--; return status; }
static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *caller_profile, switch_xml_t xexten, switch_caller_extension_t **extension) { switch_xml_t xcond, xaction, xexpression; switch_channel_t *channel = switch_core_session_get_channel(session); char *exten_name = (char *) switch_xml_attr(xexten, "name"); int proceed = 0; char *expression_expanded = NULL, *field_expanded = NULL; switch_regex_t *re = NULL; if (!exten_name) { exten_name = "_anon_"; } for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next) { char *field = NULL; char *do_break_a = NULL; char *expression = NULL; const char *field_data = NULL; int ovector[30]; switch_bool_t anti_action = SWITCH_TRUE; break_t do_break_i = BREAK_ON_FALSE; int time_match = switch_xml_std_datetime_check(xcond); switch_safe_free(field_expanded); switch_safe_free(expression_expanded); if (switch_xml_child(xcond, "condition")) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Nested conditions are not allowed!\n"); proceed = 1; goto done; } field = (char *) switch_xml_attr(xcond, "field"); if ((xexpression = switch_xml_child(xcond, "expression"))) { expression = switch_str_nil(xexpression->txt); } else { expression = (char *) switch_xml_attr_soft(xcond, "expression"); } if ((expression_expanded = switch_channel_expand_variables(channel, expression)) == expression) { expression_expanded = NULL; } else { expression = expression_expanded; } if ((do_break_a = (char *) switch_xml_attr(xcond, "break"))) { if (!strcasecmp(do_break_a, "on-true")) { do_break_i = BREAK_ON_TRUE; } else if (!strcasecmp(do_break_a, "on-false")) { do_break_i = BREAK_ON_FALSE; } else if (!strcasecmp(do_break_a, "always")) { do_break_i = BREAK_ALWAYS; } else if (!strcasecmp(do_break_a, "never")) { do_break_i = BREAK_NEVER; } else { do_break_a = NULL; } } if (time_match == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s Date/Time Match (PASS) [%s] break=%s\n", switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); anti_action = SWITCH_FALSE; } else if (time_match == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s Date/Time Match (FAIL) [%s] break=%s\n", switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); } if (field) { if (strchr(field, '$')) { if ((field_expanded = switch_channel_expand_variables(channel, field)) == field) { field_expanded = NULL; field_data = field; } else { field_data = field_expanded; } } else { field_data = switch_caller_get_field_by_name(caller_profile, field); } if (!field_data) { field_data = ""; } if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); anti_action = SWITCH_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); } } else if (time_match == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s Absolute Condition [%s]\n", switch_channel_get_name(channel), exten_name); anti_action = SWITCH_FALSE; } if (anti_action) { for (xaction = switch_xml_child(xcond, "anti-action"); xaction; xaction = xaction->next) { const char *application = switch_xml_attr_soft(xaction, "application"); const char *loop = switch_xml_attr(xaction, "loop"); const char *data; const char *inline_ = switch_xml_attr_soft(xaction, "inline"); int xinline = switch_true(inline_); int loop_count = 1; if (!zstr(xaction->txt)) { data = xaction->txt; } else { data = (char *) switch_xml_attr_soft(xaction, "data"); } if (!*extension) { if ((*extension = switch_caller_extension_new(session, exten_name, caller_profile->destination_number)) == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); proceed = 0; goto done; } } if (loop) { loop_count = atoi(loop); } for (;loop_count > 0; loop_count--) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s ANTI-Action %s(%s) %s\n", switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); if (xinline) { exec_app(session, application, data); } else { switch_caller_extension_add_application(session, *extension, application, data); } } proceed = 1; } } else { for (xaction = switch_xml_child(xcond, "action"); xaction; xaction = xaction->next) { char *application = (char *) switch_xml_attr_soft(xaction, "application"); const char *loop = switch_xml_attr(xaction, "loop"); char *data = NULL; char *substituted = NULL; uint32_t len = 0; char *app_data = NULL; const char *inline_ = switch_xml_attr_soft(xaction, "inline"); int xinline = switch_true(inline_); int loop_count = 1; if (!zstr(xaction->txt)) { data = xaction->txt; } else { data = (char *) switch_xml_attr_soft(xaction, "data"); } if (field && strchr(expression, '(')) { len = (uint32_t) (strlen(data) + strlen(field_data) + 10) * proceed; if (!(substituted = malloc(len))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); proceed = 0; goto done; } memset(substituted, 0, len); switch_perform_substitution(re, proceed, data, field_data, substituted, len, ovector); app_data = substituted; } else { app_data = data; } if (!*extension) { if ((*extension = switch_caller_extension_new(session, exten_name, caller_profile->destination_number)) == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); proceed = 0; goto done; } } if (loop) { loop_count = atoi(loop); } for (;loop_count > 0; loop_count--) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "Dialplan: %s Action %s(%s) %s\n", switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); if (xinline) { exec_app(session, application, app_data); } else { switch_caller_extension_add_application(session, *extension, application, app_data); } } switch_safe_free(substituted); } } switch_regex_safe_free(re); if (((anti_action == SWITCH_FALSE && do_break_i == BREAK_ON_TRUE) || (anti_action == SWITCH_TRUE && do_break_i == BREAK_ON_FALSE)) || do_break_i == BREAK_ALWAYS) { break; } } done: switch_regex_safe_free(re); switch_safe_free(field_expanded); switch_safe_free(expression_expanded); return proceed; }