diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index d7156ee365..5a675f8b8a 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -83,6 +83,7 @@ static cli_profile_t *global_profile; static int running = 1; static int thread_running = 0; static char *filter_uuid; +static char *logfilter; #ifndef WIN32 static EditLine *el; static History *myhistory; @@ -731,6 +732,12 @@ static void *msg_thread_run(esl_thread_t *me, void *obj) DWORD len = (DWORD) strlen(handle->last_event->body); DWORD outbytes = 0; #endif + if (logfilter) { + if (!strstr(handle->last_event->body, logfilter)) { + continue; + } + } + if (lname) { level = atoi(lname); } @@ -806,6 +813,7 @@ static const char *cli_usage = "/log, /nolog \tLog commands.\n" "/uuid \tFilter logs for a single call uuid\n" "/filter \tFilter commands.\n" + "/logfilter \tFilter Log for a single string.\n" "/debug [0-7] \tSet debug level.\n" "\n"; @@ -826,6 +834,18 @@ static int process_command(esl_handle_t *handle, const char *cmd) ) { esl_log(ESL_LOG_INFO, "Goodbye!\nSee you at ClueCon http://www.cluecon.com/\n"); return -1; + } else if (!strncasecmp(cmd, "logfilter", 9)) { + cmd += 9; + while (*cmd && *cmd == ' ') { + cmd++; + } + if (!esl_strlen_zero(cmd)) { + esl_safe_free(logfilter); + logfilter = strdup(cmd); + } else { + esl_safe_free(logfilter); + } + output_printf("Logfilter %s\n", logfilter ? "enabled" : "disabled"); } else if (!strncasecmp(cmd, "uuid", 4)) { cmd += 4; while (*cmd && *cmd == ' ') { diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 1ace3893b3..f7ace52676 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -275,6 +275,7 @@ SWITCH_DECLARE(const char *) switch_channel_get_hold_music(switch_channel_t *cha SWITCH_DECLARE(const char *) switch_channel_get_hold_music_partner(switch_channel_t *channel); SWITCH_DECLARE(uint32_t) switch_channel_del_variable_prefix(switch_channel_t *channel, const char *prefix); +SWITCH_DECLARE(switch_status_t) switch_channel_transfer_variable_prefix(switch_channel_t *orig_channel, switch_channel_t *new_channel, const char *prefix); #define switch_channel_set_variable_safe(_channel, _var, _val) switch_channel_set_variable_var_check(_channel, _var, _val, SWITCH_FALSE) #define switch_channel_set_variable(_channel, _var, _val) switch_channel_set_variable_var_check(_channel, _var, _val, SWITCH_TRUE) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 1bad6377e8..19fe5fc088 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -282,6 +282,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all_function(_In_ s SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream); SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session); +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 *)); + + /*! \brief Read a frame from the bug \param bug the bug to read from diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index daa97cc364..b893fcf076 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -277,6 +277,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_start_input_timers(swit \return SWITCH_STATUS_SUCCESS if all is well */ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, char *file, uint32_t limit, switch_file_handle_t *fh); +SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session); SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_pop_eavesdropper(switch_core_session_t *session, switch_core_session_t **sessionp); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 51a9621142..a0e74ddb99 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -139,6 +139,8 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_TRANSFER_HISTORY_VARIABLE "transfer_history" #define SWITCH_TRANSFER_SOURCE_VARIABLE "transfer_source" #define SWITCH_SENSITIVE_DTMF_VARIABLE "sensitive_dtmf" +#define SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE "record_post_process_exec_app" +#define SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE "record_post_process_exec_api" #define SWITCH_CHANNEL_EXECUTE_ON_ANSWER_VARIABLE "execute_on_answer" #define SWITCH_CHANNEL_EXECUTE_ON_PRE_ANSWER_VARIABLE "execute_on_pre_answer" diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 82c4baf7e2..a6422785a8 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -3776,6 +3776,7 @@ SWITCH_STANDARD_API(session_audio_function) switch_core_session_t *u_session = NULL; char *mycmd = NULL; int fail = 0; + int nochannel = 0; int argc = 0; char *argv[5] = { 0 }; int level; @@ -3794,7 +3795,7 @@ SWITCH_STANDARD_API(session_audio_function) } if (!(u_session = switch_core_session_locate(argv[0]))) { - stream->write_function(stream, "-ERR No such channel!\n"); + nochannel++; goto done; } @@ -3826,7 +3827,9 @@ SWITCH_STANDARD_API(session_audio_function) switch_safe_free(mycmd); - if (fail) { + if (nochannel) { + stream->write_function(stream, "-ERR No such channel!\n"); + } else if (fail) { stream->write_function(stream, "-USAGE: %s\n", AUDIO_SYNTAX); } else { stream->write_function(stream, "+OK\n"); diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index c2052bede6..0990f6e5f0 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -2267,16 +2267,19 @@ SWITCH_STANDARD_APP(att_xfer_function) { switch_core_session_t *peer_session = NULL; switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; - switch_channel_t *channel, *peer_channel = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session), *peer_channel = NULL; const char *bond = NULL; switch_core_session_t *b_session = NULL; + switch_bool_t follow_recording = switch_true(switch_channel_get_variable(channel, "recording_follow_attxfer")); - channel = switch_core_session_get_channel(session); - bond = switch_channel_get_partner_uuid(channel); switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, bond); switch_core_event_hook_add_state_change(session, tmp_hanguphook); + if (follow_recording && (b_session = switch_core_session_locate(bond))) { + switch_ivr_transfer_recordings(b_session, session); + switch_core_session_rwunlock(b_session); + } if (switch_ivr_originate(session, &peer_session, &cause, data, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL) != SWITCH_STATUS_SUCCESS || !peer_session) { @@ -2300,23 +2303,24 @@ SWITCH_STANDARD_APP(att_xfer_function) } if (bond) { - char buf[128] = ""; int br = 0; switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, bond); if (!switch_channel_down(peer_channel)) { if (!switch_channel_ready(channel)) { - switch_status_t status = switch_ivr_uuid_bridge(switch_core_session_get_uuid(peer_session), bond); + switch_status_t status; + + if (follow_recording) { + switch_ivr_transfer_recordings(session, peer_session); + } + status = switch_ivr_uuid_bridge(switch_core_session_get_uuid(peer_session), bond); att_xfer_set_result(peer_channel, status); br++; } else if ((b_session = switch_core_session_locate(bond))) { switch_channel_t *b_channel = switch_core_session_get_channel(b_session); - switch_snprintf(buf, sizeof(buf), "%s %s", switch_core_session_get_uuid(peer_session), switch_core_session_get_uuid(session)); - switch_channel_set_variable(b_channel, "xfer_uuids", buf); - - switch_snprintf(buf, sizeof(buf), "%s %s", switch_core_session_get_uuid(peer_session), bond); - switch_channel_set_variable(channel, "xfer_uuids", buf); + switch_channel_set_variable_printf(b_channel, "xfer_uuids", "%s %s", switch_core_session_get_uuid(peer_session), switch_core_session_get_uuid(session)); + switch_channel_set_variable_printf(channel, "xfer_uuids", "%s %s", switch_core_session_get_uuid(peer_session), bond); switch_core_event_hook_add_state_change(session, hanguphook); switch_core_event_hook_add_state_change(b_session, hanguphook); diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c index a9309db19d..e2ba85d173 100644 --- a/src/mod/applications/mod_voicemail/mod_voicemail.c +++ b/src/mod/applications/mod_voicemail/mod_voicemail.c @@ -2843,6 +2843,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile, switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_file_path", file_path); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_read_flags", read_flags); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_time", date); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_uuid", use_uuid); switch_safe_free(formatted_cid_num); diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 10685f3adf..115de3d616 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -2409,6 +2409,7 @@ static audio_stream_t *create_audio_stream(int indev, int outdev) return NULL; } } + inputParameters.device = indev; if (indev != -1) { inputParameters.channelCount = 1; @@ -2417,10 +2418,13 @@ static audio_stream_t *create_audio_stream(int indev, int outdev) inputParameters.hostApiSpecificStreamInfo = NULL; } outputParameters.device = outdev; - outputParameters.channelCount = 1; - outputParameters.sampleFormat = SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; + + if (outdev != -1) { + outputParameters.channelCount = 1; + outputParameters.sampleFormat = SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + } err = open_audio_stream(&(stream->stream), &inputParameters, &outputParameters); if (err != paNoError) { @@ -2444,13 +2448,19 @@ static audio_stream_t *create_audio_stream(int indev, int outdev) audio_stream_t *get_audio_stream(int indev, int outdev) { - audio_stream_t *stream; + audio_stream_t *stream = NULL; if (outdev == -1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error invalid output audio device\n"); + return NULL; + } + if (indev == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error invalid input audio device\n"); + return NULL; } if (create_codecs(0) != SWITCH_STATUS_SUCCESS) { return NULL; } + stream = find_audio_stream(indev, outdev, 0); if (stream != NULL) { return stream; diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 261cfddc2f..91c6701174 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -3677,9 +3677,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, sstr = switch_mprintf("active;expires=%ld", exp_delta); sql = switch_mprintf("update sip_subscriptions " - "set expires=%ld,contact='%q' " + "set expires=%ld " "where hostname='%q' and profile_name='%q' and call_id='%q' and profile_name='%q'", - (long) switch_epoch_time_now(NULL) + exp_delta, contact_str, mod_sofia_globals.hostname, profile->name, + (long) switch_epoch_time_now(NULL) + exp_delta, mod_sofia_globals.hostname, profile->name, call_id, profile->name); if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) { @@ -4252,6 +4252,10 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n switch_event_t *event; char *sql; char *full_agent = NULL; + char network_ip[80]; + int network_port = 0; + + sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port); pd_dup = strdup(payload->pl_data); @@ -4293,15 +4297,19 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n rpid = note_txt = "Unregistered"; if (sofia_test_pflag(profile, PFLAG_MULTIREG)) { count = sofia_reg_reg_count(profile, from_user, from_host); - sub_count = sofia_presence_contact_count(profile, contact_str); + + if (count != 1) { + /* Don't broadcast offline when there is more than one client or one signing off makes them all appear to sign off on some clients */ + count = 0; + } else { + sub_count = sofia_presence_contact_count(profile, contact_str); + } } } - /* if (count > 1) let's not and say we did or all the clients who subscribe to their own presence will think they selves is offline */ - event_type = sip_header_as_string(nh->nh_home, (void *) sip->sip_event); - if (count != 1) { + if (count) { if ((sql = switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' " " and profile_name='%q' and hostname='%q'", from_user, from_host, profile->name, mod_sofia_globals.hostname))) { @@ -4309,10 +4317,10 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n } if (sub_count > 0 && (sql = switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent," - " profile_name, hostname, open_closed) " - "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')", + " profile_name, hostname, open_closed, network_ip, network_port) " + "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%q','%d')", from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, - mod_sofia_globals.hostname, open_closed))) { + mod_sofia_globals.hostname, open_closed, network_ip, network_port))) { sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } diff --git a/src/switch_channel.c b/src/switch_channel.c index 699ad79610..27a5b24d7d 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1212,6 +1212,26 @@ SWITCH_DECLARE(uint32_t) switch_channel_del_variable_prefix(switch_channel_t *ch return r; } +SWITCH_DECLARE(switch_status_t) switch_channel_transfer_variable_prefix(switch_channel_t *orig_channel, switch_channel_t *new_channel, const char *prefix) +{ + switch_event_header_t *hi = NULL; + int x = 0; + + if ((hi = switch_channel_variable_first(orig_channel))) { + for (; hi; hi = hi->next) { + char *var = hi->name; + char *val = hi->value; + + if (zstr(prefix) || !strncasecmp(var, prefix, strlen(prefix))) { + x++; + switch_channel_set_variable(new_channel, var, val); + } + } + switch_channel_variable_last(orig_channel); + } + + return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; +} SWITCH_DECLARE(void) switch_channel_set_presence_data_vals(switch_channel_t *channel, const char *presence_data_cols) { diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index c340b71e63..c70dbd6579 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -618,6 +618,50 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } + +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; +} + + SWITCH_DECLARE(switch_status_t) switch_core_media_bug_pop(switch_core_session_t *orig_session, const char *function, switch_media_bug_t **pop) { switch_media_bug_t *bp; diff --git a/src/switch_cpp.cpp b/src/switch_cpp.cpp index 1c42eb1378..18738adde4 100644 --- a/src/switch_cpp.cpp +++ b/src/switch_cpp.cpp @@ -57,12 +57,11 @@ SWITCH_DECLARE_CONSTRUCTOR EventConsumer::EventConsumer(const char *event_name, switch_core_new_memory_pool(&pool); switch_queue_create(&events, len, pool); node_index = 0; + ready = 1; if (!zstr(event_name)) { bind(event_name, subclass_name); } - - ready = 1; } SWITCH_DECLARE(int) EventConsumer::bind(const char *event_name, const char *subclass_name) diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index ddb6d8c801..5e34c464c4 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1184,9 +1184,9 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch_event_fire(&event); } - switch_channel_execute_on(channel, "record_post_process_exec_app"); + switch_channel_execute_on(channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE); - if ((var = switch_channel_get_variable(channel, "record_post_process_exec_api"))) { + if ((var = switch_channel_get_variable(channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE))) { char *cmd = switch_core_session_strdup(session, var); char *data, *expanded = NULL; switch_stream_handle_t stream = { 0 }; @@ -1260,6 +1260,31 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_sessi return SWITCH_STATUS_FALSE; } +static void* switch_ivr_record_user_data_dup(switch_core_session_t *session, void *user_data) +{ + struct record_helper *rh = (struct record_helper *) user_data, *dup = NULL; + + dup = switch_core_session_alloc(session, sizeof(*dup)); + memcpy(dup, rh, sizeof(*rh)); + dup->file = switch_core_session_strdup(session, rh->file); + + return dup; +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session) +{ + const char *var = NULL; + switch_channel_t *orig_channel = switch_core_session_get_channel(orig_session); + switch_channel_t *new_channel = switch_core_session_get_channel(new_session); + + if ((var = switch_channel_get_variable(orig_channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE))) { + switch_channel_set_variable(new_channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE, var); + } + switch_channel_transfer_variable_prefix(orig_channel, new_channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE); + + return switch_core_media_bug_transfer_callback(orig_session, new_session, record_callback, switch_ivr_record_user_data_dup); +} + struct eavesdrop_pvt { switch_buffer_t *buffer; switch_mutex_t *mutex;