SWITCH_DECLARE(int) CoreSession::speak(char *text) { switch_status_t status; this_check(-1); sanity_check(-1); if (!tts_name) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No TTS engine specified\n"); return SWITCH_STATUS_FALSE; } if (!voice_name) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No TTS voice specified\n"); return SWITCH_STATUS_FALSE; } begin_allow_threads(); status = switch_ivr_speak_text(session, tts_name, voice_name, text, ap); end_allow_threads(); return status == SWITCH_STATUS_SUCCESS ? 1 : 0; }
SWITCH_DECLARE(void) CoreSession::sayPhrase(const char *phrase_name, const char *phrase_data, const char *phrase_lang) { this_check_void(); sanity_check_noreturn; if (!(phrase_name)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! invalid args.\n"); return; } begin_allow_threads(); switch_ivr_phrase_macro(session, phrase_name, phrase_data, phrase_lang, ap); end_allow_threads(); }
static switch_status_t channel_on_hangup(switch_core_session_t *session) { switch_channel_t *channel = NULL; loopback_private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); switch_channel_set_variable(channel, "is_loopback", "1"); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); switch_clear_flag_locked(tech_pvt, TFLAG_LINKED); switch_mutex_lock(tech_pvt->mutex); if (tech_pvt->other_tech_pvt) { switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_LINKED); if (tech_pvt->other_tech_pvt->session && tech_pvt->other_tech_pvt->session != tech_pvt->other_session) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "OTHER SESSION MISMATCH????\n"); tech_pvt->other_session = tech_pvt->other_tech_pvt->session; } tech_pvt->other_tech_pvt = NULL; } if (tech_pvt->other_session) { switch_channel_hangup(tech_pvt->other_channel, switch_channel_get_cause(channel)); switch_core_session_rwunlock(tech_pvt->other_session); tech_pvt->other_channel = NULL; tech_pvt->other_session = NULL; } switch_mutex_unlock(tech_pvt->mutex); return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_limit_incr(const char *backend, switch_core_session_t *session, const char *realm, const char *resource, const int max, const int interval) { switch_limit_interface_t *limit = NULL; switch_channel_t *channel = NULL; int status = SWITCH_STATUS_SUCCESS; assert(session); channel = switch_core_session_get_channel(session); /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); switch_goto_status(SWITCH_STATUS_GENERR, end); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "incr called: %s_%s max:%d, interval:%d\n", realm, resource, max, interval); if ((status = limit->incr(session, realm, resource, max, interval)) == SWITCH_STATUS_SUCCESS) { /* race condition? what if another leg is doing the same thing? */ const char *existing = switch_channel_get_variable(channel, LIMIT_BACKEND_VARIABLE); if (existing) { if (!strstr(existing, backend)) { switch_channel_set_variable_printf(channel, LIMIT_BACKEND_VARIABLE, "%s,%s", existing, backend); } } else { switch_channel_set_variable(channel, LIMIT_BACKEND_VARIABLE, backend); switch_core_event_hook_add_state_change(session, limit_state_handler); } } release_backend(limit); end: return status; }
static switch_status_t channel_on_execute(switch_core_session_t *session) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); return SWITCH_STATUS_SUCCESS; }
static switch_status_t channel_on_consume_media(switch_core_session_t *session) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL CONSUME_MEDIA\n"); return SWITCH_STATUS_SUCCESS; }
static switch_status_t channel_on_exchange_media(switch_core_session_t *session) { switch_channel_t *channel = NULL; loopback_private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n"); return SWITCH_STATUS_SUCCESS; }
static void switch_core_standard_on_init(switch_core_session_t *session) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard INIT\n", switch_channel_get_name(session->channel)); if (switch_channel_test_flag(session->channel, CF_RECOVERING_BRIDGE)) { switch_channel_set_state(session->channel, CS_RESET); } else { if (switch_channel_test_flag(session->channel, CF_RECOVERING)) { switch_channel_set_state(session->channel, CS_EXECUTE); } else { switch_channel_set_state(session->channel, CS_ROUTING); } } switch_channel_clear_flag(session->channel, CF_RECOVERING); }
SWITCH_DECLARE(switch_status_t) switch_limit_release(const char *backend, switch_core_session_t *session, const char *realm, const char *resource) { switch_limit_interface_t *limit = NULL; int status = SWITCH_STATUS_SUCCESS; /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); switch_goto_status(SWITCH_STATUS_GENERR, end); } status = limit->release(session, realm, resource); end: release_backend(limit); return status; }
static switch_status_t channel_on_hangup(switch_core_session_t *session) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_HANGUP); return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(const char *) API::execute(const char *cmd, const char *arg) { switch_stream_handle_t stream = { 0 }; this_check(""); SWITCH_STANDARD_STREAM(stream); if (zstr(cmd)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No application specified\n"); stream.write_function(&stream, "-ERR No application specified"); } else { switch_api_execute(cmd, arg, session, &stream); } return (char *) stream.data; }
void eventpipe_events_on_dtmf(switch_core_session_t *session, switch_event_t *event) { char args[8192]; const char *dtmf_digit = switch_str_nil(switch_event_get_header(event, "dtmf-digit")); switch_channel_t *channel = switch_core_session_get_channel(session); const char *hangup_on_star = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_hangup_on_star")); const char *conf_room = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_room")); const char *conf_member_id = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_member_id")); /* handle conference kick if channel is in conference and digit '*' was pressed */ if ((!strcmp(hangup_on_star, "true")) && (!strcmp(dtmf_digit, "*")) && (!zstr(conf_room)) && (!zstr(conf_member_id))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Conference, dtmf '*' pressed, kick member %s from room %s\n", conf_member_id, conf_room); switch_snprintf(args, sizeof(args), "%s kick %s", conf_room, conf_member_id); eventpipe_execute_api(session, "conference", args); } }
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session) { switch_media_bug_t *bp; char *list[100] = { 0 }; int stop_times[100] = { 0 }; int i = 0, x = 0; if (orig_session->bugs) { switch_channel_t *new_channel = switch_core_session_get_channel(new_session); switch_channel_t *orig_channel = switch_core_session_get_channel(orig_session); const char *save_append = switch_channel_get_variable(new_channel, "record_append"); const char *save_stereo = switch_channel_get_variable(new_channel, "record_stereo"); const char *orig_stereo = switch_channel_get_variable(orig_channel, "record_stereo"); const char *new_stereo = orig_stereo; switch_thread_rwlock_wrlock(orig_session->bug_rwlock); switch_channel_set_variable(new_channel, "RECORD_MIN_SEC", "0"); switch_channel_set_variable(new_channel, "record_append", "true"); switch_channel_set_variable(new_channel, "record_stereo", new_stereo); for (bp = orig_session->bugs; bp; bp = bp->next) { if (!strcmp(bp->function, "session_record")) { list[x] = switch_core_session_strdup(new_session, bp->target); if (bp->stop_time > 0) { stop_times[x] = (int)(bp->stop_time - switch_epoch_time_now(NULL)); } x++; } } switch_thread_rwlock_unlock(orig_session->bug_rwlock); for(i = 0; i < x; i++) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", list[i], switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session)); switch_ivr_stop_record_session(orig_session, list[i]); switch_ivr_record_session(new_session, list[i], stop_times[i], NULL); } switch_channel_set_variable(new_channel, "record_append", save_append); switch_channel_set_variable(new_channel, "record_stereo", save_stereo); } return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; }
static void switch_core_standard_on_hangup(switch_core_session_t *session) { switch_caller_extension_t *extension; int rec; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard HANGUP, cause: %s\n", switch_channel_get_name(session->channel), switch_channel_cause2str(switch_channel_get_cause(session->channel))); rec = switch_channel_test_flag(session->channel, CF_RECOVERING); switch_channel_clear_flag(session->channel, CF_RECOVERING); if (!rec) { switch_core_recovery_untrack(session, SWITCH_TRUE); } if (!switch_channel_test_flag(session->channel, CF_ZOMBIE_EXEC)) { return; } if ((extension = switch_channel_get_caller_extension(session->channel)) == 0) { return; } while(extension->current_application) { switch_caller_application_t *current_application = extension->current_application; switch_status_t status; extension->current_application = extension->current_application->next; status = switch_core_session_execute_application(session, current_application->application_name, current_application->application_data); if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_IGNORE) { return; } } }
void eventpipe_events_on_conference(switch_core_session_t *session, switch_event_t *event) { char args[8192]; char record_args[8192]; const char *action = switch_str_nil(switch_event_get_header(event, "action")); const char *member_id = switch_str_nil(switch_event_get_header(event, "member-id")); const char *conf_room = switch_str_nil(switch_event_get_header(event, "conference-name")); const char *calluuid = switch_core_session_get_uuid(session); switch_channel_t *channel = switch_core_session_get_channel(session); if (!channel) { return; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Event-Name: %s, Event-Subclass: %s, Conference-Name: %s, Action: %s, Member-ID: %s, Unique-ID: %s\n", switch_str_nil(switch_event_get_header(event, "event-name")), switch_str_nil(switch_event_get_header(event, "event-subclass")), conf_room, action, member_id, calluuid); if (!strcmp(action, "add-member")) { const char *enter_sound = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_enter_sound")); const char *record_file = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_record_file")); switch_channel_set_variable(channel, "eventpipe_conference_member_id", member_id); switch_channel_set_variable(channel, "eventpipe_conference_room", conf_room); if (!zstr(enter_sound)) { switch_snprintf(args, sizeof(args), "%s play %s async", conf_room, enter_sound); eventpipe_execute_api(session, "conference", args); } if (!zstr(record_file)) { switch_snprintf(record_args, sizeof(record_args), "%s record %s", conf_room, record_file); eventpipe_execute_api(session, "conference", record_args); } } else if (!strcmp(action, "del-member")) { const char *exit_sound = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_exit_sound")); switch_channel_set_variable(channel, "eventpipe_conference_member_id", ""); switch_channel_set_variable(channel, "eventpipe_conference_room", ""); switch_channel_set_variable(channel, "eventpipe_conference_record_file", ""); if (!zstr(exit_sound)) { switch_snprintf(args, sizeof(args), "conference %s play %s async", conf_room, exit_sound); eventpipe_execute_api(session, "conference", args); } } }
static void switch_core_standard_on_reset(switch_core_session_t *session) { switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session)); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard RESET\n", switch_channel_get_name(session->channel)); if (switch_channel_test_flag(session->channel, CF_RECOVERING_BRIDGE)) { switch_core_session_t *other_session = NULL; const char *uuid = switch_core_session_get_uuid(session); if (switch_channel_test_flag(session->channel, CF_BRIDGE_ORIGINATOR)) { const char *other_uuid = switch_channel_get_partner_uuid(session->channel); int x = 0; if (other_uuid) { for (x = 0; other_session == NULL && x < 20; x++) { if (!switch_channel_up(session->channel)) { break; } other_session = switch_core_session_locate(other_uuid); switch_yield(100000); } } if (other_session) { switch_channel_t *other_channel = switch_core_session_get_channel(other_session); switch_channel_clear_flag(session->channel, CF_BRIDGE_ORIGINATOR); switch_channel_wait_for_state_timeout(other_channel, CS_RESET, 5000); switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 2000, NULL); if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) && switch_channel_test_flag(other_channel, CF_PROXY_MODE)) { switch_ivr_signal_bridge(session, other_session); } else { switch_ivr_uuid_bridge(uuid, other_uuid); } switch_core_session_rwunlock(other_session); } } switch_channel_clear_flag(session->channel, CF_RECOVERING_BRIDGE); } }
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_callback(switch_core_session_t *orig_session, switch_core_session_t *new_session, switch_media_bug_callback_t callback, void * (*user_data_dup_func) (switch_core_session_t *, void *)) { switch_media_bug_t *new_bug = NULL, *cur = NULL, *bp = NULL, *last = NULL; int total = 0; switch_thread_rwlock_wrlock(orig_session->bug_rwlock); bp = orig_session->bugs; while (bp) { cur = bp; bp = bp->next; if (cur->callback == callback) { if (last) { last->next = cur->next; } else { orig_session->bugs = cur->next; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", cur->target, switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session)); switch_core_media_bug_add(new_session, cur->function, cur->target, cur->callback, user_data_dup_func(new_session, cur->user_data), cur->stop_time, cur->flags, &new_bug); switch_core_media_bug_destroy(cur); total++; } else { last = cur; } } if (!orig_session->bugs && switch_core_codec_ready(&orig_session->bug_codec)) { switch_core_codec_destroy(&orig_session->bug_codec); } switch_thread_rwlock_unlock(orig_session->bug_rwlock); return total ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; }
static void put_text_msg(void *user_data, const uint8_t *msg, int len) { switch_tdd_t *pvt = (switch_tdd_t *) user_data; switch_event_t *event, *clone; switch_channel_t *channel = switch_core_session_get_channel(pvt->session); switch_core_session_t *other_session; switch_channel_add_variable_var_check(channel, "tdd_messages", (char *)msg, SWITCH_FALSE, SWITCH_STACK_PUSH); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_TDD_RECV_MESSAGE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", "mod_spandsp"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "tdd"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "TDD MESSAGE"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "TDD-Data", (char *)msg); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(pvt->session)); switch_event_add_body(event, "%s\n\n", (char *)msg); if (switch_core_session_get_partner(pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) { switch_core_session_receive_event(other_session, &clone); } if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) { switch_core_session_queue_event(other_session, &clone); } switch_core_session_rwunlock(other_session); } switch_event_fire(&event); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "%s got TDD Message [%s]\n", switch_channel_get_name(channel), (char *)msg); }
static switch_status_t channel_on_routing(switch_core_session_t *session) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; const char *app, *arg; channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); do_reset(tech_pvt); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel)); if (switch_test_flag(tech_pvt, TFLAG_RUNNING_APP)) { switch_clear_flag(tech_pvt, TFLAG_RUNNING_APP); } if (switch_test_flag(tech_pvt, TFLAG_APP) && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && (app = switch_channel_get_variable(channel, "loopback_app"))) { switch_caller_extension_t *extension = NULL; switch_clear_flag(tech_pvt, TFLAG_APP); switch_set_flag(tech_pvt, TFLAG_RUNNING_APP); arg = switch_channel_get_variable(channel, "loopback_app_arg"); extension = switch_caller_extension_new(session, app, app); switch_caller_extension_add_application(session, extension, "pre_answer", NULL); switch_caller_extension_add_application(session, extension, app, arg); switch_channel_set_caller_extension(channel, extension); switch_channel_set_state(channel, CS_EXECUTE); return SWITCH_STATUS_FALSE; } return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_read_codec(switch_core_session_t *session, switch_codec_t *codec) { switch_event_t *event; switch_channel_t *channel = switch_core_session_get_channel(session); char tmp[30]; switch_status_t status = SWITCH_STATUS_SUCCESS; if (!codec || !codec->implementation || !switch_core_codec_ready(codec)) { if (session->video_read_codec) { session->video_read_codec = NULL; status = SWITCH_STATUS_SUCCESS; goto end; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot set NULL codec!\n"); status = SWITCH_STATUS_FALSE; goto end; } if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-video-read-codec-name", codec->implementation->iananame); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-video-read-codec-rate", "%d", codec->implementation->actual_samples_per_second); switch_event_fire(&event); } switch_channel_set_variable(channel, "video_read_codec", codec->implementation->iananame); switch_snprintf(tmp, sizeof(tmp), "%d", codec->implementation->actual_samples_per_second); switch_channel_set_variable(channel, "video_read_rate", tmp); session->video_read_codec = codec; if (codec->implementation) { session->video_read_impl = *codec->implementation; } else { memset(&session->video_read_impl, 0, sizeof(session->video_read_impl)); } end: return status; }
/** * Select a URL for replacement and remove it from the cache. * Currently implemented with the clock replacement algorithm. It's not * great, but is better than least recently used and is simple to implement. * * @param cache the cache * @param session the (optional) session * @return SWITCH_STATUS_SUCCESS if successful */ static switch_status_t url_cache_replace(url_cache_t *cache, switch_core_session_t *session) { switch_status_t status = SWITCH_STATUS_FALSE; int i = 0; simple_queue_t *queue = &cache->queue; if (queue->size < queue->max_size || queue->size == 0) { return SWITCH_STATUS_FALSE; } for (i = 0; i < queue->max_size * 2; i++) { cached_url_t *to_replace = (cached_url_t *)queue->data[queue->pos]; /* check for queue corruption */ if (to_replace == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Unexpected empty URL at cache index %d\n", queue->pos); status = SWITCH_STATUS_SUCCESS; break; } /* check if available for replacement */ if (!to_replace->used && !to_replace->waiters) { /* remove from cache and destroy it */ url_cache_remove(cache, session, to_replace); cached_url_destroy(to_replace, cache->pool); status = SWITCH_STATUS_SUCCESS; break; } /* not available for replacement. Mark as not used and move to back of queue */ if (to_replace->status == CACHED_URL_AVAILABLE) { to_replace->used = 0; } queue->pos = (queue->pos + 1) % queue->max_size; } return status; }
static void api_hook(switch_core_session_t *session, const char *hook_var, int use_session) { if (!zstr(hook_var)) { switch_stream_handle_t stream = { 0 }; char *cmd = strdup(hook_var); char *arg = NULL; char *expanded = NULL; if ((arg = strchr(cmd, ':')) && *(arg + 1) == ':') { *arg++ = '\0'; *arg++ = '\0'; } else { if ((arg = strchr(cmd, ' '))) { *arg++ = '\0'; } } SWITCH_STANDARD_STREAM(stream); switch_channel_get_variables(session->channel, &stream.param_event); switch_channel_event_set_data(session->channel, stream.param_event); expanded = switch_event_expand_headers(stream.param_event, arg); switch_api_execute(cmd, expanded, use_session ? session : NULL, &stream); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Hangup Command %s %s(%s):\n%s\n", use_session ? "with Session" : "with no Session", cmd, switch_str_nil(expanded), switch_str_nil((char *) stream.data) ); if (expanded != arg) { switch_safe_free(expanded); } switch_safe_free(cmd); switch_safe_free(stream.data); } }
SWITCH_DECLARE(char *) CoreSession::getDigits(int maxdigits, char *terminators, int timeout, int interdigit) { this_check((char *)""); sanity_check((char *)""); begin_allow_threads(); char terminator; memset(dtmf_buf, 0, sizeof(dtmf_buf)); switch_ivr_collect_digits_count(session, dtmf_buf, sizeof(dtmf_buf), maxdigits, terminators, &terminator, (uint32_t) timeout, (uint32_t)interdigit, 0); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "getDigits dtmf_buf: %s\n", dtmf_buf); end_allow_threads(); return dtmf_buf; }
SWITCH_DECLARE(void) switch_caller_extension_add_application_printf(switch_core_session_t *session, switch_caller_extension_t *caller_extension, const char *application_name, const char *fmt, ...) { va_list ap; char *data = NULL; va_start(ap, fmt); switch_vasprintf(&data, fmt, ap); va_end(ap); if (data) { char *p; if ((p = strstr(data, "\\'"))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "App not added, Invalid character sequence in data string [%s]\n", data); free(data); return; } switch_caller_extension_add_application(session, caller_extension, application_name, data); free(data); } }
SWITCH_DECLARE(void) CoreSession::destroy(void) { this_check_void(); if (!allocated) { return; } allocated = 0; switch_safe_free(xml_cdr_text); switch_safe_free(uuid); switch_safe_free(tts_name); switch_safe_free(voice_name); if (session) { if (!channel) { channel = switch_core_session_get_channel(session); } if (channel) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s destroy/unlink session from object\n", switch_channel_get_name(channel)); switch_channel_set_private(channel, "CoreSession", NULL); if (switch_channel_up(channel) && switch_test_flag(this, S_HUP) && !switch_channel_test_flag(channel, CF_TRANSFER)) { switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); } } switch_core_session_rwunlock(session); session = NULL; channel = NULL; } init_vars(); }
static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig) { switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); switch (sig) { case SWITCH_SIG_BREAK: switch_set_flag_locked(tech_pvt, TFLAG_CNG); switch_mutex_lock(tech_pvt->mutex); if (tech_pvt->other_tech_pvt) { switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_CNG); } switch_mutex_unlock(tech_pvt->mutex); break; case SWITCH_SIG_KILL: switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); switch_clear_flag_locked(tech_pvt, TFLAG_LINKED); switch_mutex_lock(tech_pvt->mutex); if (tech_pvt->other_tech_pvt) { switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_LINKED); } switch_mutex_unlock(tech_pvt->mutex); break; default: break; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel)); return SWITCH_STATUS_SUCCESS; }
/** * Get a URL from the cache, add it if it does not exist * @param cache The cache * @param session the (optional) session requesting the URL * @param url The URL * @param download If true, the file will be downloaded if it does not exist in the cache. * @param pool The pool to use for allocating the filename * @return The filename or NULL if there is an error */ static char *url_cache_get(url_cache_t *cache, switch_core_session_t *session, const char *url, int download, switch_memory_pool_t *pool) { char *filename = NULL; cached_url_t *u = NULL; if (zstr(url)) { return NULL; } url_cache_lock(cache, session); u = switch_core_hash_find(cache->map, url); if (u && u->status == CACHED_URL_AVAILABLE) { if (switch_time_now() >= (u->download_time + u->max_age)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Cached URL has expired.\n"); url_cache_remove_soft(cache, session, u); /* will get permanently deleted upon replacement */ u = NULL; } else if (switch_file_exists(u->filename, pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Cached URL file is missing.\n"); url_cache_remove_soft(cache, session, u); /* will get permanently deleted upon replacement */ u = NULL; } } if (!u && download) { /* URL is not cached, let's add it.*/ /* Set up URL entry and add to map to prevent simultaneous downloads */ cache->misses++; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Cache MISS: size = %zu (%zu MB), hit ratio = %d/%d\n", cache->queue.size, cache->size / 1000000, cache->hits, cache->hits + cache->misses); u = cached_url_create(cache, url); if (url_cache_add(cache, session, u) != SWITCH_STATUS_SUCCESS) { /* This error should never happen */ url_cache_unlock(cache, session); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to add URL to cache!\n"); cached_url_destroy(u, cache->pool); return NULL; } /* download the file */ url_cache_unlock(cache, session); if (http_get(cache, u, session) == SWITCH_STATUS_SUCCESS) { /* Got the file, let the waiters know it is available */ url_cache_lock(cache, session); u->status = CACHED_URL_AVAILABLE; filename = switch_core_strdup(pool, u->filename); cache->size += u->size; } else { /* Did not get the file, flag for replacement */ url_cache_lock(cache, session); url_cache_remove_soft(cache, session, u); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Failed to download URL %s\n", url); cache->errors++; } } else if (!u) { filename = DOWNLOAD_NEEDED; } else { /* Wait until file is downloaded */ if (u->status == CACHED_URL_RX_IN_PROGRESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Waiting for URL %s to be available\n", url); u->waiters++; url_cache_unlock(cache, session); while(u->status == CACHED_URL_RX_IN_PROGRESS) { switch_sleep(10 * 1000); /* 10 ms */ } url_cache_lock(cache, session); u->waiters--; } /* grab filename if everything is OK */ if (u->status == CACHED_URL_AVAILABLE) { filename = switch_core_strdup(pool, u->filename); cache->hits++; u->used = 1; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Cache HIT: size = %zu (%zu MB), hit ratio = %d/%d\n", cache->queue.size, cache->size / 1000000, cache->hits, cache->hits + cache->misses); } } url_cache_unlock(cache, session); return filename; }
/** * Relinquish exclusive access to the cache * @param cache The cache * @param session The session relinquishing the cache */ static void url_cache_unlock(url_cache_t *cache, switch_core_session_t *session) { switch_mutex_unlock(cache->mutex); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Unlocked cache\n"); }
/** * Put a file to the URL * @param cache the cache * @param session the (optional) session uploading the file * @param url The URL * @param filename The file to upload * @return SWITCH_STATUS_SUCCESS if successful */ static switch_status_t http_put(url_cache_t *cache, switch_core_session_t *session, const char *url, const char *filename) { switch_status_t status = SWITCH_STATUS_SUCCESS; CURL *curl_handle = NULL; long httpRes = 0; struct stat file_info = {0}; FILE *file_to_put = NULL; int fd; /* open file and get the file size */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "opening %s for upload to %s\n", filename, url); fd = open(filename, O_RDONLY); if (fd == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "open() error: %s\n", strerror(errno)); status = SWITCH_STATUS_FALSE; goto done; } if (fstat(fd, &file_info) == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "fstat() error: %s\n", strerror(errno)); } close(fd); /* libcurl requires FILE* */ file_to_put = fopen(filename, "rb"); if (!file_to_put) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "fopen() error: %s\n", strerror(errno)); status = SWITCH_STATUS_FALSE; goto done; } curl_handle = switch_curl_easy_init(); if (!curl_handle) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_curl_easy_init() failure\n"); status = SWITCH_STATUS_FALSE; goto done; } switch_curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_PUT, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url); switch_curl_easy_setopt(curl_handle, CURLOPT_READDATA, file_to_put); switch_curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-http-cache/1.0"); if (!cache->ssl_verifypeer) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); } else { /* this is the file with all the trusted certificate authorities */ if (!zstr(cache->ssl_cacert)) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, cache->ssl_cacert); } /* verify that the host name matches the cert */ if (!cache->ssl_verifyhost) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); } } switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); switch_curl_easy_cleanup(curl_handle); if (httpRes == 200 || httpRes == 201 || httpRes == 204) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s saved to %s\n", filename, url); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received HTTP error %ld trying to save %s to %s\n", httpRes, filename, url); status = SWITCH_STATUS_GENERR; } done: if (file_to_put) { fclose(file_to_put); } return status; }
/* 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; }