mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 12:42:02 +00:00
Merge branch 'smgmaster' into releases.3.4.experimental_head
Conflicts: libs/freetdm/mod_freetdm/mod_freetdm.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c src/mod/endpoints/mod_sofia/mod_sofia.c src/mod/endpoints/mod_sofia/sofia_glue.c
This commit is contained in:
@@ -169,7 +169,7 @@ struct switch_core_session {
|
||||
uint32_t track_id;
|
||||
switch_log_level_t loglevel;
|
||||
uint32_t soft_lock;
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
switch_ivr_dmachine_t *dmachine[2];
|
||||
plc_state_t *plc;
|
||||
};
|
||||
|
||||
@@ -253,8 +253,7 @@ struct switch_runtime {
|
||||
int multiple_registrations;
|
||||
uint32_t max_db_handles;
|
||||
uint32_t db_handle_timeout;
|
||||
int curl_count;
|
||||
int ssl_count;
|
||||
int cpu_count;
|
||||
};
|
||||
|
||||
extern struct switch_runtime runtime;
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
#include "switch_platform.h"
|
||||
#include "switch_types.h"
|
||||
#include "switch_apr.h"
|
||||
#include "switch_curl.h"
|
||||
#include "switch_mprintf.h"
|
||||
#include "switch_core_db.h"
|
||||
#include "switch_dso.h"
|
||||
|
||||
@@ -120,6 +120,9 @@ typedef struct profile_node_s {
|
||||
struct switch_caller_profile *next;
|
||||
switch_call_direction_t direction;
|
||||
profile_node_t *soft;
|
||||
char *uuid_str;
|
||||
char *clone_of;
|
||||
char *transfer_source;
|
||||
};
|
||||
|
||||
/*! \brief An Abstract Representation of a dialplan Application */
|
||||
|
||||
@@ -87,6 +87,10 @@ SWITCH_DECLARE(int) switch_channel_test_ready(switch_channel_t *channel, switch_
|
||||
|
||||
#define switch_channel_up(_channel) (switch_channel_check_signal(_channel, SWITCH_TRUE) || switch_channel_get_state(_channel) < CS_HANGUP)
|
||||
#define switch_channel_down(_channel) (switch_channel_check_signal(_channel, SWITCH_TRUE) || switch_channel_get_state(_channel) >= CS_HANGUP)
|
||||
|
||||
#define switch_channel_up_nosig(_channel) (switch_channel_get_state(_channel) < CS_HANGUP)
|
||||
#define switch_channel_down_nosig(_channel) (switch_channel_get_state(_channel) >= CS_HANGUP)
|
||||
|
||||
#define switch_channel_media_ack(_channel) (!switch_channel_test_cap(_channel, CC_MEDIA_ACK) || switch_channel_test_flag(_channel, CF_MEDIA_ACK))
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_wait_for_state(switch_channel_t *channel, switch_channel_t *other_channel, switch_channel_state_t want_state);
|
||||
@@ -267,6 +271,8 @@ SWITCH_DECLARE(const char *) switch_channel_get_variable_partner(switch_channel_
|
||||
SWITCH_DECLARE(const char *) switch_channel_get_hold_music(switch_channel_t *channel);
|
||||
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);
|
||||
|
||||
#define switch_channel_set_variable(_channel, _var, _val) switch_channel_set_variable_var_check(_channel, _var, _val, SWITCH_TRUE)
|
||||
#define switch_channel_set_variable_partner(_channel, _var, _val) switch_channel_set_variable_partner_var_check(_channel, _var, _val, SWITCH_TRUE)
|
||||
|
||||
@@ -383,6 +389,7 @@ SWITCH_DECLARE(uint32_t) switch_channel_test_flag_partner(switch_channel_t *chan
|
||||
\param flag flag to set
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_channel_set_state_flag(switch_channel_t *channel, switch_channel_flag_t flag);
|
||||
SWITCH_DECLARE(void) switch_channel_clear_state_flag(switch_channel_t *channel, switch_channel_flag_t flag);
|
||||
|
||||
/*!
|
||||
\brief Clear given flag(s) from a channel
|
||||
@@ -625,7 +632,10 @@ SWITCH_DECLARE(void) switch_channel_mark_hold(switch_channel_t *channel, switch_
|
||||
/** @} */
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_execute_on(switch_channel_t *channel, const char *variable_prefix);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_api_on(switch_channel_t *channel, const char *variable_prefix);
|
||||
|
||||
SWITCH_DECLARE(switch_caller_extension_t *) switch_channel_get_queued_extension(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(void) switch_channel_transfer_to_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
+31
-13
@@ -25,7 +25,7 @@
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
|
||||
*
|
||||
* Joseph Sullivan <jossulli@amazon.com>
|
||||
*
|
||||
* switch_core.h -- Core Library
|
||||
*
|
||||
@@ -436,9 +436,6 @@ SWITCH_DECLARE(void) switch_core_session_rwunlock(_In_ switch_core_session_t *se
|
||||
*/
|
||||
SWITCH_DECLARE(int) switch_core_add_state_handler(_In_ const switch_state_handler_table_t *state_handler);
|
||||
|
||||
SWITCH_DECLARE(int) switch_core_curl_count(int *val);
|
||||
SWITCH_DECLARE(int) switch_core_ssl_count(int *val);
|
||||
|
||||
/*!
|
||||
\brief Remove a global state handler
|
||||
\param state_handler the state handler to remove
|
||||
@@ -467,6 +464,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_new_memory_pool(_Out_ switch
|
||||
*/
|
||||
#define switch_core_new_memory_pool(p) switch_core_perform_new_memory_pool(p, __FILE__, __SWITCH_FUNC__, __LINE__)
|
||||
|
||||
SWITCH_DECLARE(int) switch_core_session_sync_clock(void);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_perform_destroy_memory_pool(_Inout_ switch_memory_pool_t **pool,
|
||||
_In_z_ const char *file, _In_z_ const char *func, _In_ int line);
|
||||
/*!
|
||||
@@ -687,7 +685,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(_In_ switch_co
|
||||
/*!
|
||||
\brief Signal a session's state machine thread that a state change has occured
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_core_session_wake_session_thread(_In_ switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_wake_session_thread(_In_ switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_session_signal_state_change(_In_ switch_core_session_t *session);
|
||||
|
||||
/*!
|
||||
@@ -712,12 +710,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_loglevel(switch_core_ses
|
||||
\return the log level
|
||||
*/
|
||||
SWITCH_DECLARE(switch_log_level_t) switch_core_session_get_loglevel(switch_core_session_t *session);
|
||||
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_session_soft_lock(switch_core_session_t *session, uint32_t sec);
|
||||
SWITCH_DECLARE(void) switch_core_session_soft_unlock(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine);
|
||||
SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target);
|
||||
SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session, switch_digit_action_target_t target);
|
||||
SWITCH_DECLARE(switch_digit_action_target_t) switch_ivr_dmachine_get_target(switch_ivr_dmachine_t *dmachine);
|
||||
SWITCH_DECLARE(void) switch_ivr_dmachine_set_target(switch_ivr_dmachine_t *dmachine, switch_digit_action_target_t target);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_set_codec_slin(switch_core_session_t *session, switch_slin_data_t *data);
|
||||
|
||||
/*!
|
||||
@@ -1304,11 +1305,11 @@ SWITCH_DECLARE(void *) switch_core_hash_find_rdlock(_In_ switch_hash_t *hash, _I
|
||||
|
||||
/*!
|
||||
\brief Gets the first element of a hashtable
|
||||
\param depricate_me [deprecated] NULL
|
||||
\param deprecate_me [deprecated] NULL
|
||||
\param hash the hashtable to use
|
||||
\return The element, or NULL if it wasn't found
|
||||
*/
|
||||
SWITCH_DECLARE(switch_hash_index_t *) switch_hash_first(char *depricate_me, _In_ switch_hash_t *hash);
|
||||
SWITCH_DECLARE(switch_hash_index_t *) switch_hash_first(char *deprecate_me, _In_ switch_hash_t *hash);
|
||||
|
||||
/*!
|
||||
\brief Gets the next element of a hashtable
|
||||
@@ -1954,6 +1955,18 @@ SWITCH_DECLARE(FILE *) switch_core_data_channel(switch_text_channel_t channel);
|
||||
*/
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_ready(void);
|
||||
|
||||
/*!
|
||||
\brief Determines if the core is ready to take inbound calls
|
||||
\return SWITCH_TRUE or SWITCH_FALSE
|
||||
*/
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_ready_inbound(void);
|
||||
|
||||
/*!
|
||||
\brief Determines if the core is ready to place outbound calls
|
||||
\return SWITCH_TRUE or SWITCH_FALSE
|
||||
*/
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_ready_outbound(void);
|
||||
|
||||
/*!
|
||||
\brief return core flags
|
||||
\return core flags
|
||||
@@ -1975,8 +1988,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
|
||||
\brief Set the maximum priority the process can obtain
|
||||
\return 0 on success
|
||||
*/
|
||||
SWITCH_DECLARE(int32_t) set_high_priority(void);
|
||||
|
||||
SWITCH_DECLARE(int32_t) set_normal_priority(void);
|
||||
SWITCH_DECLARE(int32_t) set_auto_priority(void);
|
||||
SWITCH_DECLARE(int32_t) set_realtime_priority(void);
|
||||
SWITCH_DECLARE(int32_t) set_low_priority(void);
|
||||
|
||||
/*!
|
||||
\brief Change user and/or group of the running process
|
||||
@@ -2101,8 +2117,10 @@ SWITCH_DECLARE(switch_status_t) switch_console_set_alias(const char *string);
|
||||
SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait);
|
||||
SWITCH_DECLARE(void) switch_cond_yield(switch_interval_time_t t);
|
||||
SWITCH_DECLARE(void) switch_cond_next(void);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_chat_send(const char *name, const char *proto, const char *from, const char *to,
|
||||
const char *subject, const char *body, const char *type, const char *hint);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_chat_send_args(const char *dest_proto, const char *proto, const char *from, const char *to,
|
||||
const char *subject, const char *body, const char *type, const char *hint);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_chat_send(const char *dest_proto, switch_event_t *message_event);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_chat_deliver(const char *dest_proto, switch_event_t **message_event);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_preprocess_session(switch_core_session_t *session, const char *cmds);
|
||||
|
||||
|
||||
@@ -540,6 +540,8 @@ SWITCH_DECLARE(int) switch_core_db_changes(switch_core_db_t *db);
|
||||
* literal.
|
||||
*/
|
||||
|
||||
SWITCH_DECLARE(char*)switch_sql_concat(void);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
||||
@@ -65,6 +65,10 @@ Note that the first parameter to the new operator is implicitly handled by c++..
|
||||
|
||||
*/
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) setGlobalVariable(char *var_name, char *var_val);
|
||||
SWITCH_DECLARE(char *) getGlobalVariable(char *var_name);
|
||||
|
||||
SWITCH_DECLARE(void) consoleLog(char *level_str, char *msg);
|
||||
SWITCH_DECLARE(void) consoleCleanLog(char *msg);
|
||||
|
||||
@@ -156,6 +160,8 @@ SWITCH_DECLARE(bool) email(char *to, char *from, char *headers = NULL, char *bod
|
||||
SWITCH_DECLARE_CONSTRUCTOR Event(const char *type, const char *subclass_name = NULL);
|
||||
SWITCH_DECLARE_CONSTRUCTOR Event(switch_event_t *wrap_me, int free_me = 0);
|
||||
virtual SWITCH_DECLARE_CONSTRUCTOR ~ Event();
|
||||
SWITCH_DECLARE(int) chat_execute(const char *app, const char *data = NULL);
|
||||
SWITCH_DECLARE(int) chat_send(const char *dest_proto = NULL);
|
||||
SWITCH_DECLARE(const char *) serialize(const char *format = NULL);
|
||||
SWITCH_DECLARE(bool) setPriority(switch_priority_t priority = SWITCH_PRIORITY_NORMAL);
|
||||
SWITCH_DECLARE(const char *) getHeader(const char *header_name);
|
||||
@@ -183,7 +189,7 @@ SWITCH_DECLARE(bool) email(char *to, char *from, char *headers = NULL, char *bod
|
||||
SWITCH_DECLARE_CONSTRUCTOR EventConsumer(const char *event_name = NULL, const char *subclass_name = "");
|
||||
SWITCH_DECLARE_CONSTRUCTOR ~ EventConsumer();
|
||||
SWITCH_DECLARE(int) bind(const char *event_name, const char *subclass_name = "");
|
||||
SWITCH_DECLARE(Event *) pop(int block = 0);
|
||||
SWITCH_DECLARE(Event *) pop(int block = 0, int timeout = 0);
|
||||
};
|
||||
|
||||
#ifdef SWIG
|
||||
@@ -312,7 +318,8 @@ SWITCH_DECLARE(bool) email(char *to, char *from, char *headers = NULL, char *bod
|
||||
int max_digits,
|
||||
int max_tries,
|
||||
int timeout, char *terminators, char *audio_files, char *bad_input_audio_files,
|
||||
char *digits_regex, const char *var_name = NULL, int digit_timeout = 0);
|
||||
char *digits_regex, const char *var_name = NULL, int digit_timeout = 0,
|
||||
const char *transfer_on_failure = NULL);
|
||||
|
||||
/** \brief Play a file that resides on disk into the channel
|
||||
*
|
||||
|
||||
+17
-24
@@ -30,34 +30,27 @@
|
||||
|
||||
#ifndef __SWITCH_CURL_H
|
||||
#define __SWITCH_CURL_H
|
||||
#include "curl/curl.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <switch_ssl.h>
|
||||
|
||||
static inline void switch_curl_init(void)
|
||||
{
|
||||
int curl_count = switch_core_curl_count(NULL);
|
||||
typedef void switch_CURL;
|
||||
typedef struct curl_slist switch_curl_slist_t;
|
||||
typedef int switch_CURLINFO;
|
||||
typedef int switch_CURLcode;
|
||||
typedef int switch_CURLoption;
|
||||
|
||||
if (curl_count == 0) {
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
}
|
||||
|
||||
curl_count++;
|
||||
switch_core_curl_count(&curl_count);
|
||||
}
|
||||
|
||||
static inline void switch_curl_destroy()
|
||||
{
|
||||
int curl_count = switch_core_curl_count(NULL);
|
||||
|
||||
curl_count--;
|
||||
|
||||
if (curl_count == 0) {
|
||||
curl_global_cleanup();
|
||||
}
|
||||
switch_core_curl_count(&curl_count);
|
||||
}
|
||||
SWITCH_DECLARE(switch_CURL *) switch_curl_easy_init(void);
|
||||
SWITCH_DECLARE(switch_CURLcode) switch_curl_easy_perform(switch_CURL *handle);
|
||||
SWITCH_DECLARE(switch_CURLcode) switch_curl_easy_getinfo(switch_CURL *curl, switch_CURLINFO info, ... );
|
||||
SWITCH_DECLARE(void) switch_curl_easy_cleanup(switch_CURL *handle);
|
||||
SWITCH_DECLARE(switch_curl_slist_t *) switch_curl_slist_append(switch_curl_slist_t * list, const char * string );
|
||||
SWITCH_DECLARE(void) switch_curl_slist_free_all(switch_curl_slist_t * list);
|
||||
SWITCH_DECLARE(switch_CURLcode) switch_curl_easy_setopt(CURL *handle, switch_CURLoption option, ...);
|
||||
SWITCH_DECLARE(const char *) switch_curl_easy_strerror(switch_CURLcode errornum );
|
||||
SWITCH_DECLARE(void) switch_curl_init(void);
|
||||
SWITCH_DECLARE(void) switch_curl_destroy(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -103,7 +103,8 @@ struct switch_event {
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
EF_UNIQ_HEADERS = (1 << 0)
|
||||
EF_UNIQ_HEADERS = (1 << 0),
|
||||
EF_NO_CHAT_EXEC = (1 << 1)
|
||||
} switch_event_flag_t;
|
||||
|
||||
|
||||
@@ -157,6 +158,8 @@ _Ret_opt_z_ SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t *e
|
||||
|
||||
#define switch_event_get_header_nil(e, h) switch_str_nil(switch_event_get_header(e,h))
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_rename_header(switch_event_t *event, const char *header_name, const char *new_header_name);
|
||||
|
||||
/*!
|
||||
\brief Retrieve the body value from an event
|
||||
\param event the event to read the body from
|
||||
@@ -207,6 +210,8 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event);
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_event_t *todup);
|
||||
SWITCH_DECLARE(void) switch_event_merge(switch_event_t *event, switch_event_t *tomerge);
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_dup_reply(switch_event_t **event, switch_event_t *todup);
|
||||
|
||||
/*!
|
||||
\brief Fire an event with full arguement list
|
||||
\param file the calling file
|
||||
@@ -321,6 +326,9 @@ SWITCH_DECLARE(switch_status_t) switch_event_running(void);
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_add_body(switch_event_t *event, const char *fmt, ...) PRINTF_FUNCTION(2, 3);
|
||||
#endif
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_set_body(switch_event_t *event, const char *body);
|
||||
|
||||
SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const char *in);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_create_pres_in_detailed(_In_z_ char *file, _In_z_ char *func, _In_ int line,
|
||||
|
||||
@@ -111,6 +111,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_next_event(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_messages(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_signal_data(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_process_indications(switch_core_session_t *session, switch_core_session_message_t *message);
|
||||
|
||||
/*!
|
||||
\brief Wait for time to pass for a specified number of milliseconds
|
||||
\param session the session to wait for.
|
||||
@@ -153,6 +155,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_sess
|
||||
const char *terminators, char *terminator,
|
||||
uint32_t first_timeout, uint32_t digit_timeout, uint32_t abs_timeout);
|
||||
|
||||
/*!
|
||||
\brief play a file to the session while doing speech recognition.
|
||||
\param session the session to play and detect on
|
||||
\param file the path to the file
|
||||
\param mod_name the module name of the ASR library
|
||||
\param grammar the grammar text, URI, or local file name
|
||||
\param result of speech recognition, allocated from the session pool
|
||||
\return SWITCH_STATUS_SUCCESS if all is well
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_play_and_detect_speech(switch_core_session_t *session,
|
||||
const char *file,
|
||||
const char *mod_name,
|
||||
const char *grammar,
|
||||
char **result);
|
||||
|
||||
/*!
|
||||
\brief Engage background Speech detection on a session
|
||||
\param session the session to attach
|
||||
@@ -407,7 +424,8 @@ SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t
|
||||
const char *bad_input_audio_file,
|
||||
const char *var_name, char *digit_buffer, uint32_t digit_buffer_length,
|
||||
const char *digits_regex,
|
||||
uint32_t digit_timeout);
|
||||
uint32_t digit_timeout,
|
||||
const char *transfer_on_failure);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session,
|
||||
switch_speech_handle_t *sh,
|
||||
@@ -461,7 +479,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
|
||||
const char *cid_name_override,
|
||||
const char *cid_num_override,
|
||||
switch_caller_profile_t *caller_profile_override,
|
||||
switch_event_t *ovars, switch_originate_flag_t flags);
|
||||
switch_event_t *ovars, switch_originate_flag_t flags,
|
||||
switch_call_cause_t *cancel_cause);
|
||||
|
||||
SWITCH_DECLARE(void) switch_ivr_bridge_display(switch_core_session_t *session, switch_core_session_t *peer_session);
|
||||
|
||||
@@ -892,6 +911,7 @@ SWITCH_DECLARE(switch_bool_t) switch_ivr_uuid_exists(const char *uuid);
|
||||
|
||||
|
||||
|
||||
SWITCH_DECLARE(const char *) switch_ivr_dmachine_get_name(switch_ivr_dmachine_t *dmachine);
|
||||
SWITCH_DECLARE(void) switch_ivr_dmachine_set_match_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t match_callback);
|
||||
SWITCH_DECLARE(void) switch_ivr_dmachine_set_nonmatch_callback(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_callback_t nonmatch_callback);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_create(switch_ivr_dmachine_t **dmachine_p,
|
||||
@@ -927,6 +947,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_sessi
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_insert_file(switch_core_session_t *session, const char *file, const char *insert_file, switch_size_t sample_point);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_create_message_reply(switch_event_t **reply, switch_event_t *message, const char *new_proto);
|
||||
SWITCH_DECLARE(char *) switch_ivr_check_presence_mapping(const char *exten_name, const char *domain_name);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_kill_uuid(const char *uuid, switch_call_cause_t cause);
|
||||
|
||||
/** @} */
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
||||
@@ -55,33 +55,35 @@ SWITCH_BEGIN_EXTERN_C
|
||||
struct switch_loadable_module_interface {
|
||||
/*! the name of the module */
|
||||
const char *module_name;
|
||||
/*! the table of endpoints the module has implmented */
|
||||
/*! the table of endpoints the module has implemented */
|
||||
switch_endpoint_interface_t *endpoint_interface;
|
||||
/*! the table of timers the module has implmented */
|
||||
/*! the table of timers the module has implemented */
|
||||
switch_timer_interface_t *timer_interface;
|
||||
/*! the table of dialplans the module has implmented */
|
||||
/*! the table of dialplans the module has implemented */
|
||||
switch_dialplan_interface_t *dialplan_interface;
|
||||
/*! the table of codecs the module has implmented */
|
||||
/*! the table of codecs the module has implemented */
|
||||
switch_codec_interface_t *codec_interface;
|
||||
/*! the table of applications the module has implmented */
|
||||
/*! the table of applications the module has implemented */
|
||||
switch_application_interface_t *application_interface;
|
||||
/*! the table of api functions the module has implmented */
|
||||
/*! the table of chat applications the module has implemented */
|
||||
switch_chat_application_interface_t *chat_application_interface;
|
||||
/*! the table of api functions the module has implemented */
|
||||
switch_api_interface_t *api_interface;
|
||||
/*! the table of file formats the module has implmented */
|
||||
/*! the table of file formats the module has implemented */
|
||||
switch_file_interface_t *file_interface;
|
||||
/*! the table of speech interfaces the module has implmented */
|
||||
/*! the table of speech interfaces the module has implemented */
|
||||
switch_speech_interface_t *speech_interface;
|
||||
/*! the table of directory interfaces the module has implmented */
|
||||
/*! the table of directory interfaces the module has implemented */
|
||||
switch_directory_interface_t *directory_interface;
|
||||
/*! the table of chat interfaces the module has implmented */
|
||||
/*! the table of chat interfaces the module has implemented */
|
||||
switch_chat_interface_t *chat_interface;
|
||||
/*! the table of say interfaces the module has implmented */
|
||||
/*! the table of say interfaces the module has implemented */
|
||||
switch_say_interface_t *say_interface;
|
||||
/*! the table of asr interfaces the module has implmented */
|
||||
/*! the table of asr interfaces the module has implemented */
|
||||
switch_asr_interface_t *asr_interface;
|
||||
/*! the table of management interfaces the module has implmented */
|
||||
/*! the table of management interfaces the module has implemented */
|
||||
switch_management_interface_t *management_interface;
|
||||
/*! the table of limit interfaces the module has implmented */
|
||||
/*! the table of limit interfaces the module has implemented */
|
||||
switch_limit_interface_t *limit_interface;
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
int refs;
|
||||
@@ -169,6 +171,15 @@ SWITCH_DECLARE(switch_timer_interface_t *) switch_loadable_module_get_timer_inte
|
||||
*/
|
||||
SWITCH_DECLARE(switch_application_interface_t *) switch_loadable_module_get_application_interface(const char *name);
|
||||
|
||||
/*!
|
||||
\brief Retrieve the chat application interface by it's registered name
|
||||
\param name the name of the chat application
|
||||
\return the desired chat application interface
|
||||
*/
|
||||
SWITCH_DECLARE(switch_chat_application_interface_t *) switch_loadable_module_get_chat_application_interface(const char *name);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_execute_chat_app(switch_event_t *message, const char *app, const char *data);
|
||||
|
||||
/*!
|
||||
\brief Retrieve the API interface by it's registered name
|
||||
\param name the name of the API
|
||||
@@ -335,6 +346,18 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void);
|
||||
break; \
|
||||
}
|
||||
|
||||
#define SWITCH_ADD_CHAT_APP(app_int, int_name, short_descript, long_descript, funcptr, syntax_string, app_flags) \
|
||||
for (;;) { \
|
||||
app_int = (switch_chat_application_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_CHAT_APPLICATION_INTERFACE); \
|
||||
app_int->interface_name = int_name; \
|
||||
app_int->chat_application_function = funcptr; \
|
||||
app_int->short_desc = short_descript; \
|
||||
app_int->long_desc = long_descript; \
|
||||
app_int->syntax = syntax_string; \
|
||||
app_int->flags = app_flags; \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define SWITCH_ADD_DIALPLAN(dp_int, int_name, funcptr) \
|
||||
for (;;) { \
|
||||
dp_int = (switch_dialplan_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_DIALPLAN_INTERFACE); \
|
||||
|
||||
@@ -483,8 +483,8 @@ struct switch_chat_interface {
|
||||
/*! the name of the interface */
|
||||
const char *interface_name;
|
||||
/*! function to open the directory interface */
|
||||
switch_status_t (*chat_send) (const char *proto, const char *from, const char *to,
|
||||
const char *subject, const char *body, const char *type, const char *hint);
|
||||
switch_status_t (*chat_send) (switch_event_t *message_event);
|
||||
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
int refs;
|
||||
switch_mutex_t *reflock;
|
||||
@@ -681,6 +681,27 @@ struct switch_application_interface {
|
||||
struct switch_application_interface *next;
|
||||
};
|
||||
|
||||
/*! \brief A module interface to implement a chat application */
|
||||
struct switch_chat_application_interface {
|
||||
/*! the name of the interface */
|
||||
const char *interface_name;
|
||||
/*! function the application implements */
|
||||
switch_chat_application_function_t chat_application_function;
|
||||
/*! the long winded description of the application */
|
||||
const char *long_desc;
|
||||
/*! the short and sweet description of the application */
|
||||
const char *short_desc;
|
||||
/*! an example of the application syntax */
|
||||
const char *syntax;
|
||||
/*! flags to control behaviour */
|
||||
uint32_t flags;
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
int refs;
|
||||
switch_mutex_t *reflock;
|
||||
switch_loadable_module_interface_t *parent;
|
||||
struct switch_chat_application_interface *next;
|
||||
};
|
||||
|
||||
/*! \brief A module interface to implement an api function */
|
||||
struct switch_api_interface {
|
||||
/*! the name of the interface */
|
||||
|
||||
@@ -74,6 +74,7 @@ SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, c
|
||||
int *ovector, const char *var, switch_cap_callback_t callback, void *user_data);
|
||||
|
||||
SWITCH_DECLARE_NONSTD(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data);
|
||||
SWITCH_DECLARE_NONSTD(void) switch_regex_set_event_header_callback(const char *var, const char *val, void *user_data);
|
||||
|
||||
#define switch_regex_safe_free(re) if (re) {\
|
||||
switch_regex_free(re);\
|
||||
|
||||
@@ -38,7 +38,20 @@
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#define MAX_REPORT_BLOCKS 5
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
struct switch_rtcp_report_block_frame {
|
||||
uint32_t ssrc; /* The SSRC identifier of the source to which the information in this reception report block pertains. */
|
||||
uint8_t fraction; /* The fraction of RTP data packets from source SSRC_n lost since the previous SR or RR packet was sent */
|
||||
uint32_t lost; /* The total number of RTP data packets from source SSRC_n that have been lost since the beginning of reception */
|
||||
uint32_t highest_sequence_number_received;
|
||||
uint32_t jitter; /* An estimate of the statistical variance of the RTP data packet interarrival time, measured in timestamp units and expressed as an unsigned integer. */
|
||||
uint32_t lsr; /* The middle 32 bits out of 64 in the NTP timestamp */
|
||||
uint32_t dlsr; /* The delay, expressed in units of 1/65536 seconds, between receiving the last SR packet from source SSRC_n and sending this reception report block */
|
||||
};
|
||||
|
||||
/*! \brief An abstraction of a rtcp frame */
|
||||
struct switch_rtcp_frame {
|
||||
|
||||
@@ -58,6 +71,10 @@ SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
uint32_t octect_count;
|
||||
|
||||
uint32_t nb_reports;
|
||||
|
||||
struct switch_rtcp_report_block_frame reports[MAX_REPORT_BLOCKS];
|
||||
|
||||
};
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
static switch_mutex_t **ssl_mutexes;
|
||||
static switch_memory_pool_t *ssl_pool = NULL;
|
||||
|
||||
static int ssl_count = 0;
|
||||
|
||||
static inline void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line)
|
||||
{
|
||||
@@ -56,7 +56,6 @@ static inline unsigned long switch_ssl_ssl_thread_id(void)
|
||||
static inline void switch_ssl_init_ssl_locks(void)
|
||||
{
|
||||
|
||||
int ssl_count = switch_core_ssl_count(NULL);
|
||||
int i, num;
|
||||
|
||||
if (ssl_count == 0) {
|
||||
@@ -77,17 +76,13 @@ static inline void switch_ssl_init_ssl_locks(void)
|
||||
}
|
||||
|
||||
ssl_count++;
|
||||
switch_core_ssl_count(&ssl_count);
|
||||
}
|
||||
|
||||
static inline void switch_ssl_destroy_ssl_locks()
|
||||
{
|
||||
int i;
|
||||
int ssl_count = switch_core_ssl_count(NULL);
|
||||
|
||||
ssl_count--;
|
||||
|
||||
if (ssl_count == 0) {
|
||||
if (ssl_count == 1) {
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
if (ssl_mutexes[i]) {
|
||||
@@ -96,10 +91,8 @@ static inline void switch_ssl_destroy_ssl_locks()
|
||||
}
|
||||
|
||||
OPENSSL_free(ssl_mutexes);
|
||||
ssl_count--;
|
||||
}
|
||||
|
||||
switch_core_ssl_count(&ssl_count);
|
||||
|
||||
}
|
||||
#else
|
||||
static inline void switch_ssl_init_ssl_locks(void) { return; }
|
||||
|
||||
+135
-26
@@ -25,6 +25,7 @@
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Bret McDanel <trixter AT 0xdecafbad dot com>
|
||||
* Joseph Sullivan <jossulli@amazon.com>
|
||||
*
|
||||
* switch_types.h -- Data Types
|
||||
*
|
||||
@@ -131,12 +132,23 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_COPY_XML_CDR_VARIABLE "copy_xml_cdr"
|
||||
#define SWITCH_CURRENT_APPLICATION_VARIABLE "current_application"
|
||||
#define SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE "proto_specific_hangup_cause"
|
||||
#define SWITCH_TRANSFER_HISTORY_VARIABLE "transfer_history"
|
||||
#define SWITCH_TRANSFER_SOURCE_VARIABLE "transfer_source"
|
||||
|
||||
#define SWITCH_CHANNEL_EXECUTE_ON_ANSWER_VARIABLE "execute_on_answer"
|
||||
#define SWITCH_CHANNEL_EXECUTE_ON_PRE_ANSWER_VARIABLE "execute_on_pre_answer"
|
||||
#define SWITCH_CHANNEL_EXECUTE_ON_MEDIA_VARIABLE "execute_on_media"
|
||||
#define SWITCH_CHANNEL_API_ON_ANSWER_VARIABLE "api_on_answer"
|
||||
#define SWITCH_CHANNEL_EXECUTE_ON_RING_VARIABLE "execute_on_ring"
|
||||
#define SWITCH_CHANNEL_EXECUTE_ON_TONE_DETECT_VARIABLE "execute_on_tone_detect"
|
||||
#define SWITCH_CHANNEL_EXECUTE_ON_ORIGINATE_VARIABLE "execute_on_originate"
|
||||
|
||||
#define SWITCH_CHANNEL_API_ON_ANSWER_VARIABLE "api_on_answer"
|
||||
#define SWITCH_CHANNEL_API_ON_PRE_ANSWER_VARIABLE "api_on_pre_answer"
|
||||
#define SWITCH_CHANNEL_API_ON_MEDIA_VARIABLE "api_on_media"
|
||||
#define SWITCH_CHANNEL_API_ON_RING_VARIABLE "api_on_ring"
|
||||
#define SWITCH_CHANNEL_API_ON_TONE_DETECT_VARIABLE "api_on_tone_detect"
|
||||
#define SWITCH_CHANNEL_API_ON_ORIGINATE_VARIABLE "api_on_originate"
|
||||
|
||||
#define SWITCH_CALL_TIMEOUT_VARIABLE "call_timeout"
|
||||
#define SWITCH_HOLDING_UUID_VARIABLE "holding_uuid"
|
||||
#define SWITCH_SOFT_HOLDING_UUID_VARIABLE "soft_holding_uuid"
|
||||
@@ -173,6 +185,7 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_ORIGINATOR_VIDEO_CODEC_VARIABLE "originator_video_codec"
|
||||
#define SWITCH_LOCAL_MEDIA_IP_VARIABLE "local_media_ip"
|
||||
#define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "local_media_port"
|
||||
#define SWITCH_ADVERTISED_MEDIA_IP_VARIABLE "advertised_media_ip"
|
||||
#define SWITCH_REMOTE_MEDIA_IP_VARIABLE "remote_media_ip"
|
||||
#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "remote_media_port"
|
||||
#define SWITCH_REMOTE_VIDEO_IP_VARIABLE "remote_video_ip"
|
||||
@@ -193,6 +206,33 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_DTMF_LOG_LEN 1000
|
||||
typedef uint8_t switch_byte_t;
|
||||
|
||||
/*!
|
||||
\enum switch_dtmf_source_t
|
||||
\brief DTMF sources
|
||||
<pre>
|
||||
SWITCH_DTMF_UNKNOWN - Unknown source
|
||||
SWITCH_DTMF_INBAND_AUDIO - From audio
|
||||
SWITCH_DTMF_RTP - From RTP as a telephone event
|
||||
SWITCH_DTMF_ENDPOINT - From endpoint signaling
|
||||
SWITCH_DTMF_APP - From application
|
||||
</pre>
|
||||
*/
|
||||
typedef enum {
|
||||
SWITCH_DTMF_UNKNOWN,
|
||||
SWITCH_DTMF_INBAND_AUDIO,
|
||||
SWITCH_DTMF_RTP,
|
||||
SWITCH_DTMF_ENDPOINT,
|
||||
SWITCH_DTMF_APP
|
||||
} switch_dtmf_source_t;
|
||||
|
||||
typedef enum {
|
||||
DIGIT_TARGET_SELF,
|
||||
DIGIT_TARGET_PEER,
|
||||
DIGIT_TARGET_BOTH
|
||||
} switch_digit_action_target_t;
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
DTMF_FLAG_SKIP_PROCESS = (1 << 0)
|
||||
} dtmf_flag_t;
|
||||
@@ -201,6 +241,7 @@ typedef struct {
|
||||
char digit;
|
||||
uint32_t duration;
|
||||
int32_t flags;
|
||||
switch_dtmf_source_t source;
|
||||
} switch_dtmf_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -253,21 +294,27 @@ typedef uint32_t switch_eavesdrop_flag_t;
|
||||
typedef enum {
|
||||
SCF_NONE = 0,
|
||||
SCF_USE_SQL = (1 << 0),
|
||||
SCF_NO_NEW_SESSIONS = (1 << 1),
|
||||
SCF_SHUTTING_DOWN = (1 << 2),
|
||||
SCF_VG = (1 << 3),
|
||||
SCF_RESTART = (1 << 4),
|
||||
SCF_SHUTDOWN_REQUESTED = (1 << 5),
|
||||
SCF_USE_AUTO_NAT = (1 << 6),
|
||||
SCF_EARLY_HANGUP = (1 << 7),
|
||||
SCF_CALIBRATE_CLOCK = (1 << 8),
|
||||
SCF_USE_HEAVY_TIMING = (1 << 9),
|
||||
SCF_USE_CLOCK_RT = (1 << 10),
|
||||
SCF_VERBOSE_EVENTS = (1 << 11),
|
||||
SCF_USE_WIN32_MONOTONIC = (1 << 12),
|
||||
SCF_AUTO_SCHEMAS = (1 << 13),
|
||||
SCF_MINIMAL = (1 << 14),
|
||||
SCF_USE_NAT_MAPPING = (1 << 15)
|
||||
SCF_NO_NEW_OUTBOUND_SESSIONS = (1 << 1),
|
||||
SCF_NO_NEW_INBOUND_SESSIONS = (1 << 2),
|
||||
SCF_NO_NEW_SESSIONS = (SCF_NO_NEW_OUTBOUND_SESSIONS | SCF_NO_NEW_INBOUND_SESSIONS),
|
||||
SCF_SHUTTING_DOWN = (1 << 3),
|
||||
SCF_VG = (1 << 4),
|
||||
SCF_RESTART = (1 << 5),
|
||||
SCF_SHUTDOWN_REQUESTED = (1 << 6),
|
||||
SCF_USE_AUTO_NAT = (1 << 7),
|
||||
SCF_EARLY_HANGUP = (1 << 8),
|
||||
SCF_CALIBRATE_CLOCK = (1 << 9),
|
||||
SCF_USE_HEAVY_TIMING = (1 << 10),
|
||||
SCF_USE_CLOCK_RT = (1 << 11),
|
||||
SCF_VERBOSE_EVENTS = (1 << 12),
|
||||
SCF_USE_WIN32_MONOTONIC = (1 << 13),
|
||||
SCF_AUTO_SCHEMAS = (1 << 14),
|
||||
SCF_MINIMAL = (1 << 15),
|
||||
SCF_USE_NAT_MAPPING = (1 << 16),
|
||||
SCF_CLEAR_SQL = (1 << 17),
|
||||
SCF_THREADED_SYSTEM_EXEC = (1 << 18),
|
||||
SCF_SYNC_CLOCK_REQUESTED = (1 << 19),
|
||||
SCF_CORE_ODBC_REQ = (1 << 20)
|
||||
} switch_core_flag_enum_t;
|
||||
typedef uint32_t switch_core_flag_t;
|
||||
|
||||
@@ -285,7 +332,8 @@ typedef enum {
|
||||
SWITCH_SAY_INTERFACE,
|
||||
SWITCH_ASR_INTERFACE,
|
||||
SWITCH_MANAGEMENT_INTERFACE,
|
||||
SWITCH_LIMIT_INTERFACE
|
||||
SWITCH_LIMIT_INTERFACE,
|
||||
SWITCH_CHAT_APPLICATION_INTERFACE
|
||||
} switch_module_interface_name_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -306,7 +354,8 @@ typedef enum {
|
||||
SSM_NA,
|
||||
SSM_PRONOUNCED,
|
||||
SSM_ITERATED,
|
||||
SSM_COUNTED
|
||||
SSM_COUNTED,
|
||||
SSM_PRONOUNCED_YEAR
|
||||
} switch_say_method_t;
|
||||
|
||||
/* WARNING, Do not forget to update *SAY_TYPE_NAMES[] in src/switch_ivr_say.c */
|
||||
@@ -455,6 +504,7 @@ typedef enum {
|
||||
SWITCH_XML_SECTION_DIRECTORY = (1 << 1),
|
||||
SWITCH_XML_SECTION_DIALPLAN = (1 << 2),
|
||||
SWITCH_XML_SECTION_PHRASES = (1 << 3),
|
||||
SWITCH_XML_SECTION_CHATPLAN = (1 << 4),
|
||||
|
||||
/* Nothing after this line */
|
||||
SWITCH_XML_SECTION_MAX = (1 << 4)
|
||||
@@ -634,7 +684,7 @@ typedef enum {
|
||||
This flag will never send any. Sheesh....
|
||||
*/
|
||||
|
||||
RTP_BUG_IGNORE_DTMF_DURATION = (1 << 6)
|
||||
RTP_BUG_IGNORE_DTMF_DURATION = (1 << 6),
|
||||
|
||||
/*
|
||||
Guess Who? ... Yep, Sonus (and who know's who else) likes to interweave DTMF with the audio stream making it take
|
||||
@@ -642,6 +692,31 @@ typedef enum {
|
||||
This flag will treat every dtmf as if it were 50ms and queue it on recipt of the leading packet rather than at the end.
|
||||
*/
|
||||
|
||||
|
||||
RTP_BUG_ACCEPT_ANY_PACKETS = (1 << 7),
|
||||
|
||||
/*
|
||||
Oracle's Contact Center Anywhere (CCA) likes to use a single RTP socket to send all its outbound audio.
|
||||
This messes up our ability to auto adjust to NATTED RTP and causes us to ignore its audio packets.
|
||||
This flag will allow compatibility with this dying product.
|
||||
*/
|
||||
|
||||
|
||||
RTP_BUG_GEN_ONE_GEN_ALL = (1 << 8)
|
||||
|
||||
/*
|
||||
Some RTP endpoints (and by some we mean *cough* _SONUS_!) do not like it when the timestamps jump forward or backwards in time.
|
||||
So say you are generating a file that says "please wait for me to complete your call, or generating ringback"
|
||||
Now you place and outbound call and you are bridging. Well, while you were playing the file, you were generating your own RTP timestamps.
|
||||
But, now that you have a remote RTP stream, you'd rather send those timestamps as-is in case they will be fed to a remote jitter buffer......
|
||||
Ok, so this causes the audio to completely fade out despite the fact that we send the mark bit which should give them heads up its happening.
|
||||
|
||||
Sigh, This flag will tell FreeSWITCH that if it ever generates even one RTP packet itself, to continue to generate all of them and ignore the
|
||||
actual timestamps in the frames.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
} switch_rtp_bug_flag_t;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -800,6 +875,8 @@ typedef enum {
|
||||
SWITCH_MESSAGE_INDICATE_JITTER_BUFFER,
|
||||
SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH,
|
||||
SWITCH_MESSAGE_INDICATE_SIGNAL_DATA,
|
||||
SWITCH_MESSAGE_INDICATE_INFO,
|
||||
SWITCH_MESSAGE_INDICATE_AUDIO_DATA,
|
||||
SWITCH_MESSAGE_INVALID
|
||||
} switch_core_session_message_types_t;
|
||||
|
||||
@@ -818,6 +895,7 @@ typedef struct {
|
||||
uint16_t remote_port;
|
||||
const char *local_ip;
|
||||
uint16_t local_port;
|
||||
const char *sdp_o_line;
|
||||
} switch_t38_options_t;
|
||||
|
||||
/*!
|
||||
@@ -1048,6 +1126,7 @@ typedef enum {
|
||||
CC_PROXY_MEDIA,
|
||||
CC_JITTERBUFFER,
|
||||
CC_FS_RTP,
|
||||
CC_QUEUEABLE_DTMF_DELAY,
|
||||
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
|
||||
CC_FLAG_MAX
|
||||
} switch_channel_cap_t;
|
||||
@@ -1109,6 +1188,7 @@ typedef enum {
|
||||
CF_BRIDGE_NOWRITE,
|
||||
CF_RECOVERED,
|
||||
CF_JITTERBUFFER,
|
||||
CF_JITTERBUFFER_PLC,
|
||||
CF_DIALPLAN,
|
||||
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
|
||||
CF_CNG_PLC,
|
||||
@@ -1116,7 +1196,11 @@ typedef enum {
|
||||
CF_LAZY_ATTENDED_TRANSFER,
|
||||
CF_SIGNAL_DATA,
|
||||
CF_SIMPLIFY,
|
||||
CF_ZOMBIE_EXEC,
|
||||
CF_INTERCEPT,
|
||||
CF_INTERCEPTED,
|
||||
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
|
||||
/* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
|
||||
CF_FLAG_MAX
|
||||
} switch_channel_flag_t;
|
||||
|
||||
@@ -1125,7 +1209,8 @@ typedef enum {
|
||||
CF_APP_TAGGED = (1 << 0),
|
||||
CF_APP_T38 = (1 << 1),
|
||||
CF_APP_T38_REQ = (1 << 2),
|
||||
CF_APP_T38_FAIL = (1 << 3)
|
||||
CF_APP_T38_FAIL = (1 << 3),
|
||||
CF_APP_T38_NEGOTIATED = (1 << 4)
|
||||
} switch_channel_app_flag_t;
|
||||
|
||||
|
||||
@@ -1152,7 +1237,8 @@ typedef enum {
|
||||
SFF_PROXY_PACKET = (1 << 5),
|
||||
SFF_DYNAMIC = (1 << 6),
|
||||
SFF_ZRTP = (1 << 7),
|
||||
SFF_UDPTL_PACKET = (1 << 8)
|
||||
SFF_UDPTL_PACKET = (1 << 8),
|
||||
SFF_NOT_AUDIO = (1 << 9)
|
||||
} switch_frame_flag_enum_t;
|
||||
typedef uint32_t switch_frame_flag_t;
|
||||
|
||||
@@ -1161,10 +1247,17 @@ typedef enum {
|
||||
SAF_NONE = 0,
|
||||
SAF_SUPPORT_NOMEDIA = (1 << 0),
|
||||
SAF_ROUTING_EXEC = (1 << 1),
|
||||
SAF_MEDIA_TAP = (1 << 2)
|
||||
SAF_MEDIA_TAP = (1 << 2),
|
||||
SAF_ZOMBIE_EXEC = (1 << 3)
|
||||
} switch_application_flag_enum_t;
|
||||
typedef uint32_t switch_application_flag_t;
|
||||
|
||||
typedef enum {
|
||||
SCAF_NONE = 0
|
||||
} switch_chat_application_flag_enum_t;
|
||||
typedef uint32_t switch_chat_application_flag_t;
|
||||
|
||||
|
||||
/*!
|
||||
\enum switch_signal_t
|
||||
\brief Signals to send to channels
|
||||
@@ -1309,6 +1402,9 @@ SMBF_READ_REPLACE - Replace the Read Stream
|
||||
SMBF_STEREO - Record in stereo
|
||||
SMBF_ANSWER_RECORD_REQ - Don't record until the channel is answered
|
||||
SMBF_THREAD_LOCK - Only let the same thread who created the bug remove it.
|
||||
SMBF_PRUNE -
|
||||
SMBF_NO_PAUSE -
|
||||
SMBF_STEREO_SWAP - Record in stereo: Write Stream - left channel, Read Stream - right channel
|
||||
</pre>
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -1322,7 +1418,8 @@ typedef enum {
|
||||
SMBF_ANSWER_REQ = (1 << 6),
|
||||
SMBF_THREAD_LOCK = (1 << 7),
|
||||
SMBF_PRUNE = (1 << 8),
|
||||
SMBF_NO_PAUSE = (1 << 9)
|
||||
SMBF_NO_PAUSE = (1 << 9),
|
||||
SMBF_STEREO_SWAP = (1 << 10)
|
||||
} switch_media_bug_flag_enum_t;
|
||||
typedef uint32_t switch_media_bug_flag_t;
|
||||
|
||||
@@ -1594,11 +1691,17 @@ typedef enum {
|
||||
SWITCH_CAUSE_MEDIA_TIMEOUT = 604,
|
||||
SWITCH_CAUSE_PICKED_OFF = 605,
|
||||
SWITCH_CAUSE_USER_NOT_REGISTERED = 606,
|
||||
SWITCH_CAUSE_PROGRESS_TIMEOUT = 607
|
||||
SWITCH_CAUSE_PROGRESS_TIMEOUT = 607,
|
||||
SWITCH_CAUSE_INVALID_GATEWAY = 608,
|
||||
SWITCH_CAUSE_GATEWAY_DOWN = 609,
|
||||
SWITCH_CAUSE_INVALID_URL = 610,
|
||||
SWITCH_CAUSE_INVALID_PROFILE = 611
|
||||
} switch_call_cause_t;
|
||||
|
||||
typedef enum {
|
||||
SCSC_PAUSE_INBOUND,
|
||||
SCSC_PAUSE_OUTBOUND,
|
||||
SCSC_PAUSE_ALL,
|
||||
SCSC_HUPALL,
|
||||
SCSC_SHUTDOWN,
|
||||
SCSC_CHECK_RUNNING,
|
||||
@@ -1624,8 +1727,12 @@ typedef enum {
|
||||
SCSC_MIN_IDLE_CPU,
|
||||
SCSC_VERBOSE_EVENTS,
|
||||
SCSC_SHUTDOWN_CHECK,
|
||||
SCSC_PAUSE_INBOUND_CHECK,
|
||||
SCSC_PAUSE_OUTBOUND_CHECK,
|
||||
SCSC_PAUSE_CHECK,
|
||||
SCSC_READY_CHECK
|
||||
SCSC_READY_CHECK,
|
||||
SCSC_THREADED_SYSTEM_EXEC,
|
||||
SCSC_SYNC_CLOCK_WHEN_IDLE
|
||||
} switch_session_ctl_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -1672,6 +1779,7 @@ typedef struct switch_timer_interface switch_timer_interface_t;
|
||||
typedef struct switch_dialplan_interface switch_dialplan_interface_t;
|
||||
typedef struct switch_codec_interface switch_codec_interface_t;
|
||||
typedef struct switch_application_interface switch_application_interface_t;
|
||||
typedef struct switch_chat_application_interface switch_chat_application_interface_t;
|
||||
typedef struct switch_api_interface switch_api_interface_t;
|
||||
typedef struct switch_file_interface switch_file_interface_t;
|
||||
typedef struct switch_speech_interface switch_speech_interface_t;
|
||||
@@ -1723,7 +1831,8 @@ typedef switch_status_t (*switch_core_codec_fmtp_parse_func_t) (const char *fmtp
|
||||
typedef switch_status_t (*switch_core_codec_destroy_func_t) (switch_codec_t *);
|
||||
|
||||
|
||||
|
||||
typedef switch_status_t (*switch_chat_application_function_t) (switch_event_t *, const char *);
|
||||
#define SWITCH_STANDARD_CHAT_APP(name) static switch_status_t name (switch_event_t *message, const char *data)
|
||||
|
||||
typedef void (*switch_application_function_t) (switch_core_session_t *, const char *);
|
||||
#define SWITCH_STANDARD_APP(name) static void name (switch_core_session_t *session, const char *data)
|
||||
|
||||
@@ -240,6 +240,7 @@ SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switc
|
||||
SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone);
|
||||
SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
|
||||
SWITCH_DECLARE(char *) switch_find_parameter(const char *str, const char *param, switch_memory_pool_t *pool);
|
||||
|
||||
/*!
|
||||
\brief Evaluate the truthfullness of a string expression
|
||||
@@ -426,6 +427,8 @@ static inline char *switch_sanitize_number(char *number)
|
||||
char warp[] = "/:";
|
||||
int i;
|
||||
|
||||
switch_assert(number);
|
||||
|
||||
if (!(strchr(p, '/') || strchr(p, ':') || strchr(p, '@'))) {
|
||||
return number;
|
||||
}
|
||||
@@ -523,6 +526,18 @@ static inline char *switch_clean_name_string(char *s)
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief Turn a string into a number (default if NULL)
|
||||
\param nptr the string
|
||||
\param dft the default
|
||||
\return the number version of the string or the default
|
||||
*/
|
||||
static inline int switch_safe_atoi(const char *nptr, int dft)
|
||||
{
|
||||
return nptr ? atoi(nptr) : dft;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Free a pointer and set it to NULL unless it already is NULL
|
||||
\param it the pointer
|
||||
@@ -816,6 +831,9 @@ SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domai
|
||||
SWITCH_DECLARE(const char *) switch_inet_ntop(int af, void const *src, char *dst, size_t size);
|
||||
#endif
|
||||
|
||||
SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len);
|
||||
SWITCH_DECLARE(char *) switch_format_number(const char *num);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
||||
@@ -421,7 +421,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_unbind_search_function_ptr(_In_ switc
|
||||
///\return the section mask
|
||||
SWITCH_DECLARE(switch_xml_section_t) switch_xml_parse_section_string(_In_opt_z_ const char *str);
|
||||
|
||||
SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond);
|
||||
SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond, int *offset);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_xml_locate_language(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language);
|
||||
|
||||
|
||||
+15
-12
@@ -1,10 +1,6 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/applications/mod_fax/Makefile
|
||||
/applications/mod_fax/Makefile.in
|
||||
/applications/mod_spandsp/Makefile
|
||||
/applications/mod_spandsp/Makefile.in
|
||||
/applications/mod_spandsp/mod_spandsp.log
|
||||
/applications/mod_blacklist/Makefile
|
||||
/applications/mod_commands/Makefile
|
||||
/applications/mod_conference/Makefile
|
||||
/applications/mod_db/Makefile
|
||||
@@ -13,25 +9,35 @@
|
||||
/applications/mod_expr/Makefile
|
||||
/applications/mod_expr/Makefile.in
|
||||
/applications/mod_expr/mod_expr.log
|
||||
/applications/mod_fax/Makefile
|
||||
/applications/mod_fax/Makefile.in
|
||||
/applications/mod_fax/mod_fax.log
|
||||
/applications/mod_fifo/Makefile
|
||||
/applications/mod_fsv/Makefile
|
||||
/applications/mod_limit/Makefile
|
||||
/applications/mod_sms/Makefile
|
||||
/applications/mod_spandsp/Makefile
|
||||
/applications/mod_spandsp/Makefile.in
|
||||
/applications/mod_spandsp/mod_spandsp.log
|
||||
/applications/mod_stress/Makefile
|
||||
/applications/mod_stress/Makefile.in
|
||||
/applications/mod_stress/mod_stress.log
|
||||
/applications/mod_valet_parking/Makefile
|
||||
/applications/mod_voicemail/Makefile
|
||||
/asr_tts/mod_unimrcp/Makefile
|
||||
/asr_tts/mod_unimrcp/Makefile.in
|
||||
/asr_tts/mod_unimrcp/mod_unimrcp.log
|
||||
/dialplans/mod_dialplan_asterisk/Makefile
|
||||
/dialplans/mod_dialplan_xml/Makefile
|
||||
/endpoints/mod_portaudio/Makefile
|
||||
/endpoints/mod_portaudio/Makefile.in
|
||||
/endpoints/mod_portaudio/mod_portaudio.log
|
||||
/endpoints/mod_skinny/Makefile
|
||||
/endpoints/mod_skinny/Makefile.in
|
||||
/endpoints/mod_skinny/mod_skinny.log
|
||||
/endpoints/mod_skypopen/Makefile
|
||||
/endpoints/mod_skypopen/Makefile.in
|
||||
/endpoints/mod_skypopen/mod_skypopen.log
|
||||
/endpoints/mod_sofia/Makefile
|
||||
/endpoints/mod_sofia/Makefile.in
|
||||
/endpoints/mod_sofia/mod_sofia.log
|
||||
@@ -40,11 +46,14 @@
|
||||
/formats/mod_native_file/Makefile
|
||||
/formats/mod_portaudio_stream/Makefile
|
||||
/formats/mod_portaudio_stream/Makefile.in
|
||||
/formats/mod_portaudio_stream/mod_portaudio_stream.log
|
||||
/formats/mod_tone_stream/Makefile
|
||||
/languages/mod_java/freeswitch.jar
|
||||
/languages/mod_java/Makefile
|
||||
/languages/mod_lua/Makefile
|
||||
/languages/mod_lua/Makefile.in
|
||||
/languages/mod_lua/mod_lua.log
|
||||
/languages/mod_managed/freeswitch_wrap.cpp
|
||||
/languages/mod_python/Makefile
|
||||
/languages/mod_spidermonkey/Makefile
|
||||
/languages/mod_spidermonkey/Makefile.in
|
||||
@@ -54,10 +63,4 @@
|
||||
/loggers/mod_syslog/Makefile
|
||||
/say/mod_say_en/Makefile
|
||||
/say/mod_say_ru/Makefile
|
||||
/applications/mod_stress/mod_stress.log
|
||||
/asr_tts/mod_unimrcp/mod_unimrcp.log
|
||||
/endpoints/mod_portaudio/mod_portaudio.log
|
||||
/endpoints/mod_skypopen/mod_skypopen.log
|
||||
/formats/mod_portaudio_stream/mod_portaudio_stream.log
|
||||
/languages/mod_java/freeswitch.jar
|
||||
/languages/mod_managed/freeswitch_wrap.cpp
|
||||
/timers/mod_timerfd/Makefile
|
||||
|
||||
+1
-1
@@ -39,6 +39,6 @@ mod_com_g729-activate:
|
||||
cd $(switch_builddir)/src/mod/codecs/mod_com_g729 && $(MAKE) $(AM_MAKEFLAGS) activate
|
||||
|
||||
.DEFAULT:
|
||||
@if test -z "`echo $@ | grep all`"; then $(MAKE) $(AM_MAKEFLAGS) $@-all ; else echo Unknown target `echo $@ | sed -e 's|-all||'`; exit 1; fi
|
||||
@if test -z "`echo $@ | grep '\-all$$'`"; then $(MAKE) $(AM_MAKEFLAGS) $@-all ; else echo Unknown target `echo $@ | sed -e 's|-all||'`; exit 1; fi
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_blacklist</ProjectName>
|
||||
<ProjectGuid>{50AAC2CE-BFC9-4912-87CC-C6381850D735}</ProjectGuid>
|
||||
<RootNamespace>mod_blacklist</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_blacklist.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Mathieu Rene <mrene@avgs.ca>
|
||||
* Raymond Chandler <intralanman@freeswitch.org>
|
||||
*
|
||||
* mod_blacklist.c -- Blacklist module
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_blacklist_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_blacklist_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_blacklist_load);
|
||||
|
||||
|
||||
SWITCH_MODULE_DEFINITION(mod_blacklist, mod_blacklist_load, mod_blacklist_shutdown, NULL);
|
||||
|
||||
typedef struct {
|
||||
switch_hash_t *list;
|
||||
switch_mutex_t *list_mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
} blacklist_t;
|
||||
|
||||
static struct {
|
||||
switch_hash_t *files;
|
||||
switch_hash_t *lists;
|
||||
switch_mutex_t *files_mutex;
|
||||
switch_mutex_t *lists_mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
} globals;
|
||||
|
||||
blacklist_t *blacklist_create(const char *name)
|
||||
{
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
blacklist_t *bl = NULL;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
bl = switch_core_alloc(pool, sizeof(*bl));
|
||||
switch_assert(bl);
|
||||
bl->pool = pool;
|
||||
|
||||
switch_core_hash_init(&bl->list, pool);
|
||||
switch_mutex_init(&bl->list_mutex, SWITCH_MUTEX_NESTED, pool);
|
||||
|
||||
return bl;
|
||||
}
|
||||
|
||||
void blacklist_free(blacklist_t *bl)
|
||||
{
|
||||
switch_core_destroy_memory_pool(&bl->pool);
|
||||
}
|
||||
|
||||
|
||||
void trim(char *string)
|
||||
{
|
||||
char *p;
|
||||
if ((p = strchr(string, '\n'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
if ((p = strchr(string, '\r'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t load_list(const char *name, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(filename, "r"))) {
|
||||
char buf[1024] = {0};
|
||||
blacklist_t *bl = blacklist_create(name); /* Create a hashtable + mutex for that list */
|
||||
|
||||
while (fgets(buf, 1024, f)) {
|
||||
trim(buf);
|
||||
switch_core_hash_insert(bl->list, buf, (void *)SWITCH_TRUE);
|
||||
}
|
||||
|
||||
switch_core_hash_insert(globals.files, name, filename);
|
||||
switch_core_hash_insert(globals.lists, name, bl);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Loaded list [%s]\n", name);
|
||||
|
||||
fclose(f);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open [%s] to load list [%s]\n", filename, name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t do_config(switch_bool_t reload)
|
||||
{
|
||||
/* Load up blacklists */
|
||||
switch_xml_t xml, cfg, lists, list;
|
||||
switch_hash_index_t *hi;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg("mod_blacklist.conf", &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load configuration section\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.lists_mutex);
|
||||
|
||||
/* Destroy any active lists */
|
||||
while ((hi = switch_hash_first(NULL, globals.lists))) {
|
||||
const void *key;
|
||||
void *val;
|
||||
switch_hash_this(hi, &key, NULL, &val);
|
||||
blacklist_free((blacklist_t*)val);
|
||||
switch_core_hash_delete(globals.lists, (const char*)key);
|
||||
}
|
||||
|
||||
if ((lists = switch_xml_child(cfg, "lists"))) {
|
||||
for (list = switch_xml_child(lists, "list"); list; list = list->next) {
|
||||
const char *name = switch_xml_attr_soft(list, "name");
|
||||
const char *filename = switch_xml_attr_soft(list, "filename");
|
||||
|
||||
if (zstr(name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "list has no name\n");
|
||||
continue;
|
||||
}
|
||||
if (zstr(filename)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "list [%s] has no filename\n", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
load_list(name, filename);
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_unlock(globals.lists_mutex);
|
||||
|
||||
if (xml) {
|
||||
switch_xml_free(xml);
|
||||
xml = NULL;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BLACKLIST_API_SYNTAX \
|
||||
"blacklist check <listname> <item>\n" \
|
||||
"blacklist add <listname> <item>\n" \
|
||||
"blacklist del <listname> <item>\n" \
|
||||
"blacklist save <listname>\n" \
|
||||
"blacklist reload\n" \
|
||||
"blacklist help\n"
|
||||
|
||||
SWITCH_STANDARD_API(blacklist_api_function)
|
||||
{
|
||||
char *data;
|
||||
int argc;
|
||||
char *argv[3];
|
||||
|
||||
data = strdup(cmd);
|
||||
trim(data);
|
||||
if (!(argc = switch_separate_string(data, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid usage\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0], "check")) {
|
||||
blacklist_t *bl = NULL;
|
||||
switch_bool_t result;
|
||||
|
||||
if (argc < 2 || zstr(argv[1]) || zstr(argv[2])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Wrong syntax");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.lists_mutex);
|
||||
bl = switch_core_hash_find(globals.lists, argv[1]);
|
||||
switch_mutex_unlock(globals.lists_mutex);
|
||||
|
||||
if (!bl) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown blacklist [%s]\n", argv[1]);
|
||||
stream->write_function(stream, "false");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(bl->list_mutex);
|
||||
result = (switch_bool_t)(intptr_t)switch_core_hash_find(bl->list, argv[2]);
|
||||
stream->write_function(stream, "%s", result ? "true" : "false");
|
||||
switch_mutex_unlock(bl->list_mutex);
|
||||
} else if (!strcasecmp(argv[0], "add")) {
|
||||
blacklist_t *bl = NULL;
|
||||
if (argc < 2 || zstr(argv[1]) || zstr(argv[2])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Wrong syntax");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.lists_mutex);
|
||||
bl = switch_core_hash_find(globals.lists, argv[1]);
|
||||
switch_mutex_unlock(globals.lists_mutex);
|
||||
|
||||
if (!bl) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown blacklist [%s]\n", argv[1]);
|
||||
stream->write_function(stream, "-ERR Unknown blacklist\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(bl->list_mutex);
|
||||
switch_core_hash_insert(bl->list, argv[2], (void*)SWITCH_TRUE);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added [%s] to list [%s]\n", argv[2], argv[1]);
|
||||
switch_mutex_unlock(bl->list_mutex);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "del")) {
|
||||
blacklist_t *bl = NULL;
|
||||
if (argc < 2 || zstr(argv[1]) || zstr(argv[2])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Wrong syntax");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.lists_mutex);
|
||||
bl = switch_core_hash_find(globals.lists, argv[1]);
|
||||
switch_mutex_unlock(globals.lists_mutex);
|
||||
|
||||
if (!bl) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown blacklist [%s]\n", argv[1]);
|
||||
stream->write_function(stream, "-ERR Unknown blacklist\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(bl->list_mutex);
|
||||
switch_core_hash_insert(bl->list, argv[2], NULL);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Removed [%s] from list [%s]\n", argv[2], argv[1]);
|
||||
switch_mutex_unlock(bl->list_mutex);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "save")) {
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
const void *var;
|
||||
blacklist_t *bl = NULL;
|
||||
char *filename = NULL;
|
||||
switch_file_t *fd;
|
||||
|
||||
if (argc < 1 || zstr(argv[1])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing blacklist name");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.lists_mutex);
|
||||
bl = switch_core_hash_find(globals.lists, argv[1]);
|
||||
switch_mutex_unlock(globals.lists_mutex);
|
||||
|
||||
switch_mutex_lock(globals.files_mutex);
|
||||
filename = switch_core_hash_find(globals.files, argv[1]);
|
||||
switch_mutex_unlock(globals.files_mutex);
|
||||
|
||||
if (!bl) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown blacklist [%s]\n", argv[1]);
|
||||
stream->write_function(stream, "-ERR Unknown blacklist\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Saving %s to %s\n", argv[1], filename);
|
||||
|
||||
switch_mutex_lock(globals.lists_mutex);
|
||||
if (switch_file_open(&fd, filename, SWITCH_FOPEN_WRITE | SWITCH_FOPEN_TRUNCATE | SWITCH_FOPEN_CREATE, SWITCH_FPROT_OS_DEFAULT, globals.pool)
|
||||
== SWITCH_STATUS_SUCCESS) {
|
||||
for (hi = switch_hash_first(NULL, bl->list); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
switch_file_printf(fd, "%s\n", (char *)var);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "adding %s to the dump file\n", (char *)var);
|
||||
}
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "couldn't open %s for writing\n", filename);
|
||||
}
|
||||
switch_mutex_unlock(globals.lists_mutex);
|
||||
} else if (!strcasecmp(argv[0], "reload")) {
|
||||
do_config(SWITCH_TRUE);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "help")) {
|
||||
stream->write_function(stream, BLACKLIST_API_SYNTAX "+OK\n");
|
||||
} else if (!zstr(argv[0])) {
|
||||
stream->write_function(stream, "-ERR: No such command: %s (see 'blacklist help')\n", argv[0]);
|
||||
}
|
||||
|
||||
done:
|
||||
switch_safe_free(data);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_blacklist_load)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
//switch_application_interface_t *app_interface;
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
globals.pool = pool;
|
||||
|
||||
switch_core_hash_init(&globals.files, globals.pool);
|
||||
switch_mutex_init(&globals.files_mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
switch_core_hash_init(&globals.lists, globals.pool);
|
||||
switch_mutex_init(&globals.lists_mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
do_config(SWITCH_FALSE);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "blacklist", "Control blacklists", blacklist_api_function, "");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_blacklist_shutdown)
|
||||
{
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -850,7 +850,7 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
|
||||
switch_event_t *event;
|
||||
char res[256];
|
||||
|
||||
/* Check to see if agent already exist */
|
||||
/* Check to see if agent already exists */
|
||||
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
|
||||
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
|
||||
switch_safe_free(sql);
|
||||
@@ -860,8 +860,8 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcasecmp(key, "status") ) {
|
||||
/* Check to see if agent already exist */
|
||||
if (!strcasecmp(key, "status") || !strcasecmp(key, "state") || !strcasecmp(key, "uuid") ) {
|
||||
/* Check to see if agent already exists */
|
||||
sql = switch_mprintf("SELECT %q FROM agents WHERE name = '%q'", key, agent);
|
||||
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
|
||||
switch_safe_free(sql);
|
||||
@@ -869,9 +869,15 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
|
||||
result = CC_STATUS_SUCCESS;
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
char tmpname[256];
|
||||
if (!strcasecmp(key, "uuid")) {
|
||||
switch_snprintf(tmpname, sizeof(tmpname), "CC-Agent-UUID");
|
||||
} else {
|
||||
switch_snprintf(tmpname, sizeof(tmpname), "CC-Agent-%c%s", (char) switch_toupper(key[0]), key+1);
|
||||
}
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-get");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", res);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-%s-get", key);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, tmpname, res);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
@@ -1400,6 +1406,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
|
||||
/* Proceed contact the agent to offer the member */
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
|
||||
switch_caller_profile_t *member_profile = switch_channel_get_caller_profile(member_channel);
|
||||
const char *member_dnis = member_profile->rdnis;
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-offering");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
|
||||
@@ -1409,6 +1419,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Number", h->member_cid_number);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-DNIS", member_dnis);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
@@ -1422,6 +1433,8 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent_type", "%s", h->agent_type);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_side", "%s", "agent");
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout", "false");
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout_on_execute", "false");
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true");
|
||||
|
||||
t_agent_called = local_epoch_time_now(NULL);
|
||||
@@ -1485,8 +1498,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
|
||||
if ((other_loopback_session = switch_core_session_locate(other_loopback_leg_uuid))) {
|
||||
switch_channel_t *other_loopback_channel = switch_core_session_get_channel(other_loopback_session);
|
||||
const char *real_uuid = switch_channel_get_variable(other_loopback_channel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
const char *real_uuid = NULL;
|
||||
|
||||
/* Wait for the real channel to be fully bridged */
|
||||
switch_channel_wait_for_flag(other_loopback_channel, CF_BRIDGED, SWITCH_TRUE, 5000, member_channel);
|
||||
|
||||
real_uuid = switch_channel_get_variable(other_loopback_channel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
switch_channel_set_variable(other_loopback_channel, "cc_member_pre_answer_uuid", NULL);
|
||||
|
||||
/* Switch the agent session */
|
||||
@@ -1496,9 +1513,6 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
agent_uuid = switch_core_session_get_uuid(agent_session);
|
||||
agent_channel = switch_core_session_get_channel(agent_session);
|
||||
|
||||
/* Wait for the real channel to be fully bridged */
|
||||
switch_channel_wait_for_flag(agent_channel, CF_BRIDGED, SWITCH_TRUE, 5000, member_channel);
|
||||
|
||||
if (!switch_channel_test_flag(agent_channel, CF_BRIDGED)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Timeout waiting for real channel to be bridged (agent '%s')\n", h->agent_name);
|
||||
} else {
|
||||
@@ -1548,6 +1562,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
t_agent_answered = local_epoch_time_now(NULL);
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_caller_profile_t *member_profile = switch_channel_get_caller_profile(member_channel);
|
||||
const char *member_dnis = member_profile->rdnis;
|
||||
|
||||
switch_channel_event_set_data(agent_channel, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-start");
|
||||
@@ -1561,6 +1578,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Number", h->member_cid_number);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-DNIS", member_dnis);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
/* for xml_cdr needs */
|
||||
@@ -2266,9 +2284,20 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
|
||||
}
|
||||
|
||||
/* Will drop the caller if no agent was found for more than X seconds */
|
||||
if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - queue->max_wait_time_with_no_agent_time_reached &&
|
||||
queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> in queue '%s' reached max wait with no agent time\n", m->member_cid_name, m->member_cid_number, m->queue_name);
|
||||
if (queue->max_wait_time_with_no_agent > 0 &&
|
||||
(queue->last_agent_exist >= m->t_member_called || queue->max_wait_time_with_no_agent_time_reached == 0) &&
|
||||
queue->last_agent_exist_check - queue->last_agent_exist > queue->max_wait_time_with_no_agent) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> in queue '%s' reached max wait of %d sec. with no agent\n", m->member_cid_name, m->member_cid_number, m->queue_name, queue->max_wait_time_with_no_agent);
|
||||
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT;
|
||||
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
|
||||
}
|
||||
|
||||
/* Will drop the NEW caller if no agent was found for more than X seconds once they join */
|
||||
if (queue->max_wait_time_with_no_agent_time_reached > 0 &&
|
||||
queue->last_agent_exist < m->t_member_called &&
|
||||
queue->last_agent_exist_check - queue->last_agent_exist > queue->max_wait_time_with_no_agent &&
|
||||
queue->last_agent_exist_check - m->t_member_called >= queue->max_wait_time_with_no_agent_time_reached) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> in queue '%s' reached max wait of %d sec. with no agent plus join grace period of %d sec.\n", m->member_cid_name, m->member_cid_number, m->queue_name, queue->max_wait_time_with_no_agent, queue->max_wait_time_with_no_agent_time_reached);
|
||||
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT;
|
||||
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
|
||||
}
|
||||
@@ -2676,7 +2705,9 @@ static int list_result_callback(void *pArg, int argc, char **argv, char **column
|
||||
"\tcallcenter_config agent set busy_delay_time [agent_name] [wait second] | \n"\
|
||||
"\tcallcenter_config agent set no_answer_delay_time [agent_name] [wait second] | \n"\
|
||||
"\tcallcenter_config agent get status [agent_name] | \n" \
|
||||
"\tcallcenter_config agent list | \n" \
|
||||
"\tcallcenter_config agent get state [agent_name] | \n" \
|
||||
"\tcallcenter_config agent get uuid [agent_name] | \n" \
|
||||
"\tcallcenter_config agent list [[agent_name]] | \n" \
|
||||
"\tcallcenter_config tier add [queue_name] [agent_name] [level] [position] | \n" \
|
||||
"\tcallcenter_config tier set state [queue_name] [agent_name] [state] | \n" \
|
||||
"\tcallcenter_config tier set level [queue_name] [agent_name] [level] | \n" \
|
||||
@@ -2832,7 +2863,14 @@ SWITCH_STANDARD_API(cc_config_api_function)
|
||||
struct list_result cbt;
|
||||
cbt.row_process = 0;
|
||||
cbt.stream = stream;
|
||||
sql = switch_mprintf("SELECT * FROM agents");
|
||||
if ( argc-initial_argc > 1 ) {
|
||||
stream->write_function(stream, "%s", "-ERR Invalid!\n");
|
||||
goto done;
|
||||
} else if ( argc-initial_argc == 1 ) {
|
||||
sql = switch_mprintf("SELECT * FROM agents WHERE name='%q'", argv[0 + initial_argc]);
|
||||
} else {
|
||||
sql = switch_mprintf("SELECT * FROM agents");
|
||||
}
|
||||
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
|
||||
switch_safe_free(sql);
|
||||
stream->write_function(stream, "%s", "+OK\n");
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
WANT_CURL=yes
|
||||
BASE=../../../..
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <curl/curl.h>
|
||||
#include <switch_curl.h>
|
||||
|
||||
#define SWITCH_REWIND_STREAM(s) s.end = s.data
|
||||
|
||||
@@ -360,7 +360,7 @@ static size_t file_callback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
}
|
||||
|
||||
static long do_lookup_url(switch_memory_pool_t *pool, switch_event_t *event, char **response, const char *query, struct curl_httppost *post,
|
||||
struct curl_slist *headers, int timeout)
|
||||
switch_curl_slist_t *headers, int timeout)
|
||||
{
|
||||
switch_time_t start_time = switch_micro_time_now();
|
||||
switch_time_t time_diff = 0;
|
||||
@@ -375,49 +375,49 @@ static long do_lookup_url(switch_memory_pool_t *pool, switch_event_t *event, cha
|
||||
SWITCH_STANDARD_STREAM(http_data.stream);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "url: %s\n", query);
|
||||
curl_handle = curl_easy_init();
|
||||
curl_handle = switch_curl_easy_init();
|
||||
|
||||
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
|
||||
|
||||
if (!strncasecmp(query, "https", 5)) {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
}
|
||||
if (post) {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, post);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, post);
|
||||
} else {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1);
|
||||
}
|
||||
if (headers) {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10);
|
||||
/*
|
||||
TIMEOUT_MS is introduced in 7.16.2, we have 7.16.0 in tree
|
||||
*/
|
||||
#ifdef CURLOPT_TIMEOUT_MS
|
||||
if (timeout > 0) {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
|
||||
} else {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, globals.curl_timeout);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, globals.curl_timeout);
|
||||
}
|
||||
#else
|
||||
if (timeout > 0) {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
|
||||
} else {
|
||||
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, globals.curl_timeout / 1000);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, globals.curl_timeout / 1000);
|
||||
}
|
||||
#endif
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, query);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &http_data);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-cidlookup/1.0");
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_URL, query);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &http_data);
|
||||
switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-cidlookup/1.0");
|
||||
|
||||
curl_easy_perform(curl_handle);
|
||||
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes);
|
||||
curl_easy_cleanup(curl_handle);
|
||||
switch_curl_easy_perform(curl_handle);
|
||||
switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes);
|
||||
switch_curl_easy_cleanup(curl_handle);
|
||||
|
||||
if (http_data.stream.data && !zstr((char *) http_data.stream.data) && strcmp(" ", http_data.stream.data)) {
|
||||
|
||||
@@ -852,7 +852,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_cidlookup_load)
|
||||
Macro expands to: switch_status_t mod_cidlookup_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_cidlookup_shutdown)
|
||||
{
|
||||
|
||||
switch_event_unbind(&reload_xml_event);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
* Cesar Cepeda <cesar@auronix.com>
|
||||
* Massimo Cetra <devel@navynet.it>
|
||||
* Rupa Schomaker <rupa@rupa.com>
|
||||
* Joseph Sullivan <jossulli@amazon.com>
|
||||
*
|
||||
*
|
||||
* mod_commands.c -- Misc. Command Module
|
||||
@@ -45,6 +46,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_commands, mod_commands_load, mod_commands_shutdown, NULL);
|
||||
|
||||
static switch_mutex_t *reload_mutex = NULL;
|
||||
|
||||
struct cb_helper {
|
||||
uint32_t row_process;
|
||||
@@ -1791,7 +1793,7 @@ SWITCH_STANDARD_API(status_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define CTL_SYNTAX "[send_sighup|hupall|pause|resume|shutdown [cancel|elegant|asap|now|restart]|sps|sync_clock|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|min_idle_cpu|loglevel [level]|debug_level [level]]"
|
||||
#define CTL_SYNTAX "[send_sighup|hupall|pause [inbound|outbound]|resume [inbound|outbound]|shutdown [cancel|elegant|asap|now|restart]|sps|sync_clock|sync_clock_when_idle|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|min_idle_cpu|loglevel [level]|debug_level [level]]"
|
||||
SWITCH_STANDARD_API(ctl_function)
|
||||
{
|
||||
int argc;
|
||||
@@ -1814,16 +1816,32 @@ SWITCH_STANDARD_API(ctl_function)
|
||||
switch_core_session_ctl(SCSC_FLUSH_DB_HANDLES, NULL);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "pause")) {
|
||||
switch_session_ctl_t command = SCSC_PAUSE_ALL;
|
||||
arg = 1;
|
||||
switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
|
||||
if (argv[1]) {
|
||||
if (!strcasecmp(argv[1], "inbound")) {
|
||||
command = SCSC_PAUSE_INBOUND;
|
||||
} else if (!strcasecmp(argv[1], "outbound")) {
|
||||
command = SCSC_PAUSE_OUTBOUND;
|
||||
}
|
||||
}
|
||||
switch_core_session_ctl(command, &arg);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "send_sighup")) {
|
||||
arg = 1;
|
||||
switch_core_session_ctl(SCSC_SEND_SIGHUP, &arg);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "resume")) {
|
||||
switch_session_ctl_t command = SCSC_PAUSE_ALL;
|
||||
arg = 0;
|
||||
switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
|
||||
if (argv[1]) {
|
||||
if (!strcasecmp(argv[1], "inbound")) {
|
||||
command = SCSC_PAUSE_INBOUND;
|
||||
} else if (!strcasecmp(argv[1], "outbound")) {
|
||||
command = SCSC_PAUSE_OUTBOUND;
|
||||
}
|
||||
}
|
||||
switch_core_session_ctl(command, &arg);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "calibrate_clock")) {
|
||||
switch_core_session_ctl(SCSC_CALIBRATE_CLOCK, NULL);
|
||||
@@ -1840,12 +1858,29 @@ SWITCH_STANDARD_API(ctl_function)
|
||||
switch_core_session_ctl(SCSC_VERBOSE_EVENTS, &arg);
|
||||
|
||||
stream->write_function(stream, "+OK verbose_events is %s \n", arg ? "on" : "off");
|
||||
} else if (!strcasecmp(argv[0], "threaded_system_exec")) {
|
||||
arg = -1;
|
||||
if (argv[1]) {
|
||||
arg = switch_true(argv[1]);
|
||||
}
|
||||
|
||||
switch_core_session_ctl(SCSC_THREADED_SYSTEM_EXEC, &arg);
|
||||
|
||||
stream->write_function(stream, "+OK threaded_system_exec is %s \n", arg ? "true" : "false");
|
||||
|
||||
} else if (!strcasecmp(argv[0], "save_history")) {
|
||||
switch_core_session_ctl(SCSC_SAVE_HISTORY, NULL);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else if (!strcasecmp(argv[0], "pause_check")) {
|
||||
switch_core_session_ctl(SCSC_PAUSE_CHECK, &arg);
|
||||
switch_session_ctl_t command = SCSC_PAUSE_CHECK;
|
||||
if (argv[1]) {
|
||||
if (!strcasecmp(argv[1], "inbound")) {
|
||||
command = SCSC_PAUSE_INBOUND_CHECK;
|
||||
} else if (!strcasecmp(argv[1], "outbound")) {
|
||||
command = SCSC_PAUSE_OUTBOUND_CHECK;
|
||||
}
|
||||
}
|
||||
switch_core_session_ctl(command, &arg);
|
||||
stream->write_function(stream, arg ? "true" : "false");
|
||||
} else if (!strcasecmp(argv[0], "ready_check")) {
|
||||
switch_core_session_ctl(SCSC_READY_CHECK, &arg);
|
||||
@@ -1963,6 +1998,14 @@ SWITCH_STANDARD_API(ctl_function)
|
||||
arg = 0;
|
||||
switch_core_session_ctl(SCSC_SYNC_CLOCK, &arg);
|
||||
stream->write_function(stream, "+OK clock synchronized\n");
|
||||
} else if (!strcasecmp(argv[0], "sync_clock_when_idle")) {
|
||||
arg = 0;
|
||||
switch_core_session_ctl(SCSC_SYNC_CLOCK_WHEN_IDLE, &arg);
|
||||
if (arg) {
|
||||
stream->write_function(stream, "+OK clock synchronized\n");
|
||||
} else {
|
||||
stream->write_function(stream, "+OK clock will synchronize when there are no more calls\n");
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR INVALID COMMAND\nUSAGE: fsctl %s", CTL_SYNTAX);
|
||||
goto end;
|
||||
@@ -1987,6 +2030,8 @@ SWITCH_STANDARD_API(load_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_mutex_lock(reload_mutex);
|
||||
|
||||
if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "+OK Reloading XML\n");
|
||||
}
|
||||
@@ -1997,6 +2042,8 @@ SWITCH_STANDARD_API(load_function)
|
||||
stream->write_function(stream, "-ERR [%s]\n", err);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(reload_mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2036,12 +2083,16 @@ SWITCH_STANDARD_API(unload_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_mutex_lock(reload_mutex);
|
||||
|
||||
if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, force, &err) == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR [%s]\n", err);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(reload_mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2079,6 +2130,8 @@ SWITCH_STANDARD_API(reload_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_mutex_lock(reload_mutex);
|
||||
|
||||
if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, force, &err) == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "+OK module unloaded\n");
|
||||
} else {
|
||||
@@ -2095,6 +2148,8 @@ SWITCH_STANDARD_API(reload_function)
|
||||
stream->write_function(stream, "-ERR loading module [%s]\n", err);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(reload_mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2111,7 +2166,6 @@ SWITCH_STANDARD_API(reload_xml_function)
|
||||
#define KILL_SYNTAX "<uuid> [cause]"
|
||||
SWITCH_STANDARD_API(kill_function)
|
||||
{
|
||||
switch_core_session_t *ksession = NULL;
|
||||
char *mycmd = NULL, *kcause = NULL;
|
||||
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
||||
|
||||
@@ -2122,17 +2176,14 @@ SWITCH_STANDARD_API(kill_function)
|
||||
|
||||
if ((kcause = strchr(mycmd, ' '))) {
|
||||
*kcause++ = '\0';
|
||||
}
|
||||
|
||||
if (zstr(mycmd) || !(ksession = switch_core_session_locate(mycmd))) {
|
||||
stream->write_function(stream, "-ERR No Such Channel!\n");
|
||||
} else {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(ksession);
|
||||
if (!zstr(kcause)) {
|
||||
cause = switch_channel_str2cause(kcause);
|
||||
}
|
||||
switch_channel_hangup(channel, cause);
|
||||
switch_core_session_rwunlock(ksession);
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_ivr_kill_uuid(mycmd, cause) != SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR No Such Channel!\n");
|
||||
} else {
|
||||
stream->write_function(stream, "+OK\n");
|
||||
}
|
||||
|
||||
@@ -2426,12 +2477,11 @@ SWITCH_STANDARD_API(tone_detect_session_function)
|
||||
|
||||
SWITCH_STANDARD_API(uuid_function)
|
||||
{
|
||||
switch_uuid_t uuid;
|
||||
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
|
||||
switch_uuid_get(&uuid);
|
||||
switch_uuid_format(uuid_str, &uuid);
|
||||
stream->write_function(stream, "%s", uuid_str);
|
||||
switch_uuid_str(uuid_str, sizeof(uuid_str));
|
||||
|
||||
stream->write_function(stream, "%s", uuid_str);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2997,6 +3047,44 @@ SWITCH_STANDARD_API(uuid_phone_event_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define INFO_SYNTAX "<uuid>"
|
||||
SWITCH_STANDARD_API(uuid_send_info_function)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
char *mycmd = NULL, *argv[2] = { 0 };
|
||||
int argc = 0;
|
||||
|
||||
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
stream->write_function(stream, "-USAGE: %s\n", INFO_SYNTAX);
|
||||
} else {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
switch_core_session_t *lsession = NULL;
|
||||
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_INFO;
|
||||
msg.string_array_arg[2] = argv[1];
|
||||
msg.from = __FILE__;
|
||||
|
||||
if ((lsession = switch_core_session_locate(argv[0]))) {
|
||||
status = switch_core_session_receive_message(lsession, &msg);
|
||||
switch_core_session_rwunlock(lsession);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "+OK Success\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Operation Failed\n");
|
||||
}
|
||||
|
||||
switch_safe_free(mycmd);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#define DEBUG_AUDIO_SYNTAX "<uuid> <read|write|both> <on|off>"
|
||||
SWITCH_STANDARD_API(uuid_debug_audio_function)
|
||||
@@ -3403,11 +3491,16 @@ SWITCH_STANDARD_API(originate_function)
|
||||
uint8_t machine = 1;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if (session || zstr(cmd)) {
|
||||
if (zstr(cmd)) {
|
||||
stream->write_function(stream, "-USAGE %s\n", ORIGINATE_SYNTAX);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* log warning if part of ongoing session, as we'll block the session */
|
||||
if (session){
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Originate can take 60 seconds to complete, and blocks the existing session. Do not confuse with a lockup.\n");
|
||||
}
|
||||
|
||||
mycmd = strdup(cmd);
|
||||
switch_assert(mycmd);
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
@@ -4020,12 +4113,12 @@ SWITCH_STANDARD_API(show_function)
|
||||
}
|
||||
if (strchr(argv[2], '%')) {
|
||||
sprintf(sql,
|
||||
"select * from channels where hostname='%s' and uuid like '%s' or name like '%s' or cid_name like '%s' or cid_num like '%s' order by created_epoch",
|
||||
hostname, argv[2], argv[2], argv[2], argv[2]);
|
||||
"select * from channels where hostname='%s' and uuid like '%s' or name like '%s' or cid_name like '%s' or cid_num like '%s' or presence_data like '%s' order by created_epoch",
|
||||
hostname, argv[2], argv[2], argv[2], argv[2], argv[2]);
|
||||
} else {
|
||||
sprintf(sql,
|
||||
"select * from channels where hostname='%s' and uuid like '%%%s%%' or name like '%%%s%%' or cid_name like '%%%s%%' or cid_num like '%%%s%%' order by created_epoch",
|
||||
hostname, argv[2], argv[2], argv[2], argv[2]);
|
||||
"select * from channels where hostname='%s' and uuid like '%%%s%%' or name like '%%%s%%' or cid_name like '%%%s%%' or cid_num like '%%%s%%' or presence_data like '%%%s%%' order by created_epoch",
|
||||
hostname, argv[2], argv[2], argv[2], argv[2], argv[2]);
|
||||
|
||||
}
|
||||
|
||||
@@ -4069,11 +4162,11 @@ SWITCH_STANDARD_API(show_function)
|
||||
holder.print_title = 0;
|
||||
if ((cmdname = strchr(command, ' ')) && strcasecmp(cmdname, "as")) {
|
||||
*cmdname++ = '\0';
|
||||
switch_snprintf(sql, sizeof(sql) - 1,
|
||||
"select name, syntax, description, ikey from interfaces where hostname='%s' and type = 'api' and name = '%s' order by name",
|
||||
switch_snprintfv(sql, sizeof(sql),
|
||||
"select name, syntax, description, ikey from interfaces where hostname='%s' and type = 'api' and name = '%q' order by name",
|
||||
hostname, cmdname);
|
||||
} else {
|
||||
switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description, ikey from interfaces where hostname='%s' and type = 'api' order by name", hostname);
|
||||
switch_snprintfv(sql, sizeof(sql), "select name, syntax, description, ikey from interfaces where hostname='%q' and type = 'api' order by name", hostname);
|
||||
}
|
||||
} else if (!strcasecmp(command, "nat_map")) {
|
||||
switch_snprintf(sql, sizeof(sql) - 1,
|
||||
@@ -4262,6 +4355,21 @@ SWITCH_STANDARD_API(uuid_flush_dtmf_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(uuid_zombie_exec_function)
|
||||
{
|
||||
switch_core_session_t *fsession;
|
||||
|
||||
if (!zstr(cmd) && (fsession = switch_core_session_locate(cmd))) {
|
||||
switch_channel_set_flag(switch_core_session_get_channel(fsession), CF_ZOMBIE_EXEC);
|
||||
switch_core_session_rwunlock(fsession);
|
||||
stream->write_function(stream, "+OK MMM Brains...\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR no such session\n");
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define SETVAR_SYNTAX "<uuid> <var> [value]"
|
||||
SWITCH_STANDARD_API(uuid_setvar_function)
|
||||
{
|
||||
@@ -5211,6 +5319,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
switch_thread_rwlock_create(&bgapi_rwlock, pool);
|
||||
switch_mutex_init(&reload_mutex, SWITCH_MUTEX_NESTED, pool);
|
||||
|
||||
|
||||
SWITCH_ADD_API(commands_api_interface, "acl", "compare an ip to an acl list", acl_function, "<ip> <list_name>");
|
||||
SWITCH_ADD_API(commands_api_interface, "alias", "Alias", alias_function, ALIAS_SYNTAX);
|
||||
@@ -5302,6 +5412,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_getvar", "uuid_getvar", uuid_getvar_function, GETVAR_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_hold", "hold", uuid_hold_function, HOLD_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill Channel", kill_function, KILL_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_send_info", "Send info to the endpoint", uuid_send_info_function, INFO_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_outgoing_answer", "Answer Outgoing Channel", outgoing_answer_function, OUTGOING_ANSWER_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_limit", "Increase limit resource", uuid_limit_function, LIMIT_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_limit_release", "Release limit resource", uuid_limit_release_function, LIMIT_RELEASE_SYNTAX);
|
||||
@@ -5322,6 +5433,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_simplify", "Try to cut out of a call path / attended xfer", uuid_simplify_function, SIMPLIFY_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_jitterbuffer", "Try to cut out of a call path / attended xfer",
|
||||
uuid_jitterbuffer_function, JITTERBUFFER_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_zombie_exec", "Set zombie_exec flag on the specified uuid", uuid_zombie_exec_function, "<uuid>");
|
||||
SWITCH_ADD_API(commands_api_interface, "xml_flush_cache", "clear xml cache", xml_flush_function, "<id> <key> <val>");
|
||||
SWITCH_ADD_API(commands_api_interface, "xml_locate", "find some xml", xml_locate_function, "[root | <section> <tag> <tag_attr_name> <tag_attr_val>]");
|
||||
SWITCH_ADD_API(commands_api_interface, "xml_wrap", "Wrap another api command in xml", xml_wrap_api_function, "<command> <args>");
|
||||
@@ -5349,13 +5461,19 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add fsctl max_sessions");
|
||||
switch_console_set_complete("add fsctl min_dtmf_duration");
|
||||
switch_console_set_complete("add fsctl pause");
|
||||
switch_console_set_complete("add fsctl pause inbound");
|
||||
switch_console_set_complete("add fsctl pause outbound");
|
||||
switch_console_set_complete("add fsctl reclaim_mem");
|
||||
switch_console_set_complete("add fsctl resume");
|
||||
switch_console_set_complete("add fsctl resume inbound");
|
||||
switch_console_set_complete("add fsctl resume outbound");
|
||||
switch_console_set_complete("add fsctl calibrate_clock");
|
||||
switch_console_set_complete("add fsctl crash");
|
||||
switch_console_set_complete("add fsctl verbose_events");
|
||||
switch_console_set_complete("add fsctl save_history");
|
||||
switch_console_set_complete("add fsctl pause_check");
|
||||
switch_console_set_complete("add fsctl pause_check inbound");
|
||||
switch_console_set_complete("add fsctl pause_check outbound");
|
||||
switch_console_set_complete("add fsctl ready_check");
|
||||
switch_console_set_complete("add fsctl shutdown_check");
|
||||
switch_console_set_complete("add fsctl shutdown");
|
||||
@@ -5389,7 +5507,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add show codec");
|
||||
switch_console_set_complete("add show complete");
|
||||
switch_console_set_complete("add show dialplan");
|
||||
switch_console_set_complete("add show distinct_channels");
|
||||
switch_console_set_complete("add show detailed_calls");
|
||||
switch_console_set_complete("add show bridged_calls");
|
||||
switch_console_set_complete("add show detailed_bridged_calls");
|
||||
switch_console_set_complete("add show endpoint");
|
||||
switch_console_set_complete("add show file");
|
||||
switch_console_set_complete("add show interfaces");
|
||||
@@ -5425,6 +5545,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_getvar ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_hold ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_send_info ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_jitterbuffer ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_kill ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_outgoing_answer ::console::list_uuid");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
json-c=json-c-0.9
|
||||
BASE=../../../..
|
||||
WANT_CURL=yes
|
||||
|
||||
JSON_DIR=$(switch_srcdir)/libs/$(json-c)
|
||||
JSON_BUILDDIR=$(switch_builddir)/libs/$(json-c)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <curl/curl.h>
|
||||
#include <switch_curl.h>
|
||||
#include <json.h>
|
||||
|
||||
/* Prototypes */
|
||||
@@ -57,7 +57,7 @@ struct http_data_obj {
|
||||
int err;
|
||||
long http_response_code;
|
||||
char *http_response;
|
||||
struct curl_slist *headers;
|
||||
switch_curl_slist_t *headers;
|
||||
};
|
||||
typedef struct http_data_obj http_data_t;
|
||||
|
||||
@@ -94,7 +94,7 @@ static size_t header_callback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
switch_copy_string(header, ptr, realsize);
|
||||
header[realsize] = '\0';
|
||||
|
||||
http_data->headers = curl_slist_append(http_data->headers, header);
|
||||
http_data->headers = switch_curl_slist_append(http_data->headers, header);
|
||||
|
||||
return realsize;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ static size_t header_callback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, const char *method, const char *data)
|
||||
{
|
||||
|
||||
CURL *curl_handle = NULL;
|
||||
switch_CURL *curl_handle = NULL;
|
||||
long httpRes = 0;
|
||||
|
||||
http_data_t *http_data = NULL;
|
||||
@@ -165,7 +165,7 @@ static char *print_json(switch_memory_pool_t *pool, http_data_t *http_data)
|
||||
struct json_object *top = NULL;
|
||||
struct json_object *headers = NULL;
|
||||
char *data = NULL;
|
||||
struct curl_slist *header = http_data->headers;
|
||||
switch_curl_slist_t *header = http_data->headers;
|
||||
|
||||
top = json_object_new_object();
|
||||
headers = json_object_new_array();
|
||||
@@ -240,7 +240,7 @@ SWITCH_STANDARD_APP(curl_app_function)
|
||||
switch_bool_t do_headers = SWITCH_FALSE;
|
||||
switch_bool_t do_json = SWITCH_FALSE;
|
||||
http_data_t *http_data = NULL;
|
||||
struct curl_slist *slist = NULL;
|
||||
switch_curl_slist_t *slist = NULL;
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
int i = 0;
|
||||
|
||||
@@ -308,7 +308,7 @@ SWITCH_STANDARD_APP(curl_app_function)
|
||||
done:
|
||||
switch_safe_free(stream.data);
|
||||
if (http_data && http_data->headers) {
|
||||
curl_slist_free_all(http_data->headers);
|
||||
switch_curl_slist_free_all(http_data->headers);
|
||||
}
|
||||
if (!session && pool) {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
@@ -326,7 +326,7 @@ SWITCH_STANDARD_API(curl_function)
|
||||
char *postdata = NULL;
|
||||
switch_bool_t do_headers = SWITCH_FALSE;
|
||||
switch_bool_t do_json = SWITCH_FALSE;
|
||||
struct curl_slist *slist = NULL;
|
||||
switch_curl_slist_t *slist = NULL;
|
||||
http_data_t *http_data = NULL;
|
||||
int i = 0;
|
||||
|
||||
@@ -391,7 +391,7 @@ SWITCH_STANDARD_API(curl_function)
|
||||
|
||||
done:
|
||||
if (http_data && http_data->headers) {
|
||||
curl_slist_free_all(http_data->headers);
|
||||
switch_curl_slist_free_all(http_data->headers);
|
||||
}
|
||||
switch_safe_free(mydata);
|
||||
if (!session && pool) {
|
||||
@@ -426,7 +426,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_curl_load)
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_curl_shutdown)
|
||||
{
|
||||
/* Cleanup dynamically allocated config settings */
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -622,8 +622,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_db_load)
|
||||
/* register limit interfaces */
|
||||
SWITCH_ADD_LIMIT(limit_interface, "db", limit_incr_db, limit_release_db, limit_usage_db, limit_reset_db, limit_status_db, NULL);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "db", "Insert to the db", DB_DESC, db_function, DB_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "group", "Manage a group", GROUP_DESC, group_function, GROUP_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "db", "Insert to the db", DB_DESC, db_function, DB_USAGE, SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "group", "Manage a group", GROUP_DESC, group_function, GROUP_USAGE, SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_API(commands_api_interface, "db", "db get/set", db_api_function, "[insert|delete|select]/<realm>/<key>/<value>");
|
||||
switch_console_set_complete("add db insert");
|
||||
switch_console_set_complete("add db delete");
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
* Bret McDanel <trixter AT 0xdecafbad dot com>
|
||||
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
|
||||
* Cesar Cepeda <cesar@auronix.com>
|
||||
* Chris Rienzo <chris@rienzo.net>
|
||||
*
|
||||
* mod_dptools.c -- Raw Audio File Streaming Application Module
|
||||
*
|
||||
@@ -102,37 +103,50 @@ struct action_binding {
|
||||
char *input;
|
||||
char *string;
|
||||
char *value;
|
||||
switch_digit_action_target_t target;
|
||||
switch_core_session_t *session;
|
||||
};
|
||||
|
||||
static switch_status_t digit_nomatch_action_callback(switch_ivr_dmachine_match_t *match)
|
||||
{
|
||||
switch_core_session_t *session = (switch_core_session_t *) match->user_data;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
char str[DMACHINE_MAX_DIGIT_LEN + 2];
|
||||
switch_channel_t *channel;
|
||||
switch_event_t *event;
|
||||
switch_status_t status;
|
||||
switch_core_session_t *use_session = session;
|
||||
|
||||
if (switch_ivr_dmachine_get_target(match->dmachine) == DIGIT_TARGET_PEER) {
|
||||
if (switch_core_session_get_partner(session, &use_session) != SWITCH_STATUS_SUCCESS) {
|
||||
use_session = session;
|
||||
}
|
||||
}
|
||||
|
||||
channel = switch_core_session_get_channel(use_session);
|
||||
|
||||
|
||||
switch_channel_set_variable(channel, "last_non_matching_digits", match->match_digits);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Digit NOT match binding [%s]\n",
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(use_session), SWITCH_LOG_DEBUG, "%s Digit NOT match binding [%s]\n",
|
||||
switch_channel_get_name(channel), match->match_digits);
|
||||
|
||||
if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "digits", match->match_digits);
|
||||
|
||||
if ((status = switch_core_session_queue_event(session, &event)) != SWITCH_STATUS_SUCCESS) {
|
||||
if ((status = switch_core_session_queue_event(use_session, &event)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&event);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s event queue faiure.\n",
|
||||
switch_core_session_get_name(session));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(use_session), SWITCH_LOG_WARNING, "%s event queue failure.\n",
|
||||
switch_core_session_get_name(use_session));
|
||||
}
|
||||
}
|
||||
|
||||
/* send it back around flagged to skip the dmachine */
|
||||
switch_snprintf(str, sizeof(str), "!%s", match->match_digits);
|
||||
|
||||
switch_channel_queue_dtmf_string(channel, str);
|
||||
/* send it back around and skip the dmachine */
|
||||
switch_channel_queue_dtmf_string(channel, match->match_digits);
|
||||
|
||||
if (use_session != session) {
|
||||
switch_core_session_rwunlock(use_session);
|
||||
}
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -142,52 +156,145 @@ static switch_status_t digit_action_callback(switch_ivr_dmachine_match_t *match)
|
||||
switch_event_t *event;
|
||||
switch_status_t status;
|
||||
int exec = 0;
|
||||
int api = 0;
|
||||
char *string = act->string;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(act->session);
|
||||
switch_channel_t *channel;
|
||||
switch_core_session_t *use_session = act->session;
|
||||
int x = 0;
|
||||
char *flags = "";
|
||||
|
||||
if (switch_ivr_dmachine_get_target(match->dmachine) == DIGIT_TARGET_PEER || act->target == DIGIT_TARGET_PEER || act->target == DIGIT_TARGET_BOTH) {
|
||||
if (switch_core_session_get_partner(act->session, &use_session) != SWITCH_STATUS_SUCCESS) {
|
||||
use_session = act->session;
|
||||
}
|
||||
}
|
||||
|
||||
top:
|
||||
x++;
|
||||
|
||||
string = switch_core_session_strdup(use_session, act->string);
|
||||
exec = 0;
|
||||
api = 0;
|
||||
|
||||
channel = switch_core_session_get_channel(use_session);
|
||||
|
||||
switch_channel_set_variable(channel, "last_matching_digits", match->match_digits);
|
||||
|
||||
|
||||
if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_DEBUG, "%s Digit match binding [%s][%s]\n",
|
||||
switch_channel_get_name(channel), act->string, act->value);
|
||||
|
||||
if (!strncasecmp(string, "exec:", 5)) {
|
||||
string += 5;
|
||||
exec = 1;
|
||||
if (!strncasecmp(string, "exec", 4)) {
|
||||
char *e;
|
||||
|
||||
string += 4;
|
||||
if (*string == ':') {
|
||||
string++;
|
||||
exec = 1;
|
||||
} else if (*string == '[') {
|
||||
flags = string;
|
||||
if ((e = switch_find_end_paren(flags, '[', ']'))) {
|
||||
if (e && *++e == ':') {
|
||||
flags++;
|
||||
*e++ = '\0';
|
||||
string = e;
|
||||
exec = strchr(flags, 'i') ? 2 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!strncasecmp(string, "api:", 4)) {
|
||||
string += 4;
|
||||
api = 1;
|
||||
}
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, string, act->value);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "digits", match->match_digits);
|
||||
|
||||
if (exec) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute", exec == 2 ? "non-blocking" : "blocking");
|
||||
}
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute", exec == 1 ? "non-blocking" : "blocking");
|
||||
}
|
||||
|
||||
if ((status = switch_core_session_queue_event(act->session, &event)) != SWITCH_STATUS_SUCCESS) {
|
||||
if ((status = switch_core_session_queue_event(use_session, &event)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&event);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_WARNING, "%s event queue faiure.\n",
|
||||
switch_core_session_get_name(act->session));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(use_session), SWITCH_LOG_WARNING, "%s event queue failure.\n",
|
||||
switch_core_session_get_name(use_session));
|
||||
}
|
||||
}
|
||||
|
||||
if (exec) {
|
||||
char *cmd = switch_core_session_sprintf(act->session, "%s::%s", string, act->value);
|
||||
switch_ivr_broadcast_in_thread(act->session, cmd, SMF_ECHO_ALEG|SMF_HOLD_BLEG);
|
||||
if (exec == 2) {
|
||||
switch_core_session_execute_application(use_session, string, act->value);
|
||||
} else {
|
||||
char *cmd = switch_core_session_sprintf(use_session, "%s::%s", string, act->value);
|
||||
switch_media_flag_enum_t exec_flags = SMF_ECHO_ALEG;
|
||||
|
||||
if (act->target != DIGIT_TARGET_BOTH && !strchr(flags, 'H')) {
|
||||
exec_flags |= SMF_HOLD_BLEG;
|
||||
}
|
||||
|
||||
switch_ivr_broadcast_in_thread(use_session, cmd, exec_flags);
|
||||
}
|
||||
} else if (api) {
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute(string, act->value, NULL, &stream);
|
||||
if (stream.data) {
|
||||
switch_channel_set_variable(channel, "bind_digit_action_api_result", (char *)stream.data);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_DEBUG, "%s Digit match binding [%s][%s] api executed, %s\n",
|
||||
switch_core_session_get_name(use_session), act->string, act->value, (char *)stream.data);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_DEBUG, "%s Digit match binding [%s][%s] api executed\n",
|
||||
switch_core_session_get_name(use_session), act->string, act->value);
|
||||
}
|
||||
switch_safe_free(stream.data);
|
||||
}
|
||||
|
||||
|
||||
if (use_session != act->session) {
|
||||
switch_core_session_rwunlock(use_session);
|
||||
|
||||
if (act->target == DIGIT_TARGET_BOTH) {
|
||||
use_session = act->session;
|
||||
goto top;
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define CLEAR_DIGIT_ACTION_USAGE "<realm>|all"
|
||||
static switch_digit_action_target_t str2target(const char *target_str)
|
||||
{
|
||||
if (!strcasecmp(target_str, "peer")) {
|
||||
return DIGIT_TARGET_PEER;
|
||||
}
|
||||
|
||||
if (!strcasecmp(target_str, "both")) {
|
||||
return DIGIT_TARGET_BOTH;
|
||||
}
|
||||
|
||||
return DIGIT_TARGET_SELF;
|
||||
}
|
||||
|
||||
#define CLEAR_DIGIT_ACTION_USAGE "<realm>|all[,target]"
|
||||
SWITCH_STANDARD_APP(clear_digit_action_function)
|
||||
{
|
||||
//switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
char *realm = (char *) data;
|
||||
char *realm = switch_core_session_strdup(session, data);
|
||||
char *target_str;
|
||||
switch_digit_action_target_t target = DIGIT_TARGET_SELF;
|
||||
|
||||
if ((dmachine = switch_core_session_get_dmachine(session))) {
|
||||
if ((target_str = strchr(realm, ','))) {
|
||||
*target_str++ = '\0';
|
||||
target = str2target(target_str);
|
||||
}
|
||||
|
||||
|
||||
if ((dmachine = switch_core_session_get_dmachine(session, target))) {
|
||||
if (zstr(realm) || !strcasecmp(realm, "all")) {
|
||||
switch_core_session_set_dmachine(session, NULL);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: Clearing all realms\n", switch_ivr_dmachine_get_name(dmachine));
|
||||
switch_core_session_set_dmachine(session, NULL, target);
|
||||
switch_ivr_dmachine_destroy(&dmachine);
|
||||
} else {
|
||||
switch_ivr_dmachine_clear_realm(dmachine, realm);
|
||||
@@ -195,49 +302,41 @@ SWITCH_STANDARD_APP(clear_digit_action_function)
|
||||
}
|
||||
}
|
||||
|
||||
#define DIGIT_ACTION_SET_REALM_USAGE "<realm>"
|
||||
#define DIGIT_ACTION_SET_REALM_USAGE "<realm>[,<target>]"
|
||||
SWITCH_STANDARD_APP(digit_action_set_realm_function)
|
||||
{
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
char *realm = (char *) data;
|
||||
char *realm = switch_core_session_strdup(session, data);
|
||||
char *target_str;
|
||||
switch_digit_action_target_t target = DIGIT_TARGET_SELF;
|
||||
|
||||
if ((target_str = strchr(realm, ','))) {
|
||||
*target_str++ = '\0';
|
||||
target = str2target(target_str);
|
||||
}
|
||||
|
||||
if (zstr(data)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", DIGIT_ACTION_SET_REALM_USAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((dmachine = switch_core_session_get_dmachine(session))) {
|
||||
if ((dmachine = switch_core_session_get_dmachine(session, target))) {
|
||||
switch_ivr_dmachine_set_realm(dmachine, realm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define BIND_DIGIT_ACTION_USAGE "<realm>,<digits|~regex>,<string>,<value>"
|
||||
SWITCH_STANDARD_APP(bind_digit_action_function)
|
||||
|
||||
static void bind_to_session(switch_core_session_t *session,
|
||||
const char *arg0, const char *arg1, const char *arg2, const char *arg3,
|
||||
switch_digit_action_target_t target, switch_digit_action_target_t bind_target)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
char *mydata;
|
||||
int argc = 0;
|
||||
char *argv[4] = { 0 };
|
||||
struct action_binding *act;
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (zstr(data)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
|
||||
argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
|
||||
if (argc < 4 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2]) || zstr(argv[3])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!(dmachine = switch_core_session_get_dmachine(session))) {
|
||||
if (!(dmachine = switch_core_session_get_dmachine(session, target))) {
|
||||
uint32_t digit_timeout = 1500;
|
||||
uint32_t input_timeout = 0;
|
||||
const char *var;
|
||||
@@ -256,20 +355,74 @@ SWITCH_STANDARD_APP(bind_digit_action_function)
|
||||
}
|
||||
|
||||
switch_ivr_dmachine_create(&dmachine, "DPTOOLS", NULL, digit_timeout, input_timeout, NULL, digit_nomatch_action_callback, session);
|
||||
switch_core_session_set_dmachine(session, dmachine);
|
||||
switch_core_session_set_dmachine(session, dmachine, target);
|
||||
}
|
||||
|
||||
|
||||
act = switch_core_session_alloc(session, sizeof(*act));
|
||||
act->realm = argv[0];
|
||||
act->input = argv[1];
|
||||
act->string = argv[2];
|
||||
act->value = argv[3];
|
||||
act->realm = switch_core_session_strdup(session, arg0);
|
||||
act->input = switch_core_session_strdup(session, arg1);
|
||||
act->string = switch_core_session_strdup(session, arg2);
|
||||
act->value = switch_core_session_strdup(session, arg3);
|
||||
act->target = bind_target;
|
||||
act->session = session;
|
||||
|
||||
switch_ivr_dmachine_bind(dmachine, act->realm, act->input, 0, digit_action_callback, act);
|
||||
}
|
||||
|
||||
#define BIND_DIGIT_ACTION_USAGE "<realm>,<digits|~regex>,<string>[,<value>][,<dtmf target leg>][,<event target leg>]"
|
||||
SWITCH_STANDARD_APP(bind_digit_action_function)
|
||||
{
|
||||
|
||||
char *mydata;
|
||||
int argc = 0;
|
||||
char *argv[6] = { 0 };
|
||||
switch_digit_action_target_t target, bind_target;
|
||||
char *target_str = "self", *bind_target_str = "self";
|
||||
char *value = "";
|
||||
|
||||
if (zstr(data)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
|
||||
argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
|
||||
if (argc < 3 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argv[3]) {
|
||||
value = argv[3];
|
||||
}
|
||||
|
||||
if (argv[4]) {
|
||||
target_str = argv[4];
|
||||
}
|
||||
|
||||
if (argv[5]) {
|
||||
bind_target_str = argv[5];
|
||||
}
|
||||
|
||||
target = str2target(target_str);
|
||||
bind_target = str2target(bind_target_str);
|
||||
|
||||
|
||||
switch(target) {
|
||||
case DIGIT_TARGET_PEER:
|
||||
bind_to_session(session, argv[0], argv[1], argv[2], value, DIGIT_TARGET_PEER, bind_target);
|
||||
break;
|
||||
case DIGIT_TARGET_BOTH:
|
||||
bind_to_session(session, argv[0], argv[1], argv[2], value, DIGIT_TARGET_PEER, bind_target);
|
||||
bind_to_session(session, argv[0], argv[1], argv[2], value, DIGIT_TARGET_SELF, bind_target);
|
||||
break;
|
||||
default:
|
||||
bind_to_session(session, argv[0], argv[1], argv[2], value, DIGIT_TARGET_SELF, bind_target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define DETECT_SPEECH_SYNTAX "<mod_name> <gram_name> <gram_path> [<addr>] OR grammar <gram_name> [<path>] OR nogrammar <gram_name> OR grammaron/grammaroff <gram_name> OR grammarsalloff OR pause OR resume OR start_input_timers OR stop OR param <name> <value>"
|
||||
SWITCH_STANDARD_APP(detect_speech_function)
|
||||
@@ -308,6 +461,51 @@ SWITCH_STANDARD_APP(detect_speech_function)
|
||||
}
|
||||
}
|
||||
|
||||
#define PLAY_AND_DETECT_SPEECH_SYNTAX "<file> detect:<engine> {param1=val1,param2=val2}<grammar>"
|
||||
SWITCH_STANDARD_APP(play_and_detect_speech_function)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
char *argv[2];
|
||||
char *lbuf = NULL;
|
||||
const char *response = "DONE";
|
||||
char *detect = NULL;
|
||||
|
||||
switch_channel_set_variable(channel, "detect_speech_result", "");
|
||||
|
||||
if (zstr(data) || !(lbuf = switch_core_session_strdup(session, data)) || !(detect = strstr(lbuf, "detect:"))) {
|
||||
/* bad input */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", PLAY_AND_DETECT_SPEECH_SYNTAX);
|
||||
response = "USAGE ERROR";
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* split input at "detect:" */
|
||||
detect[0] = '\0';
|
||||
detect += 7;
|
||||
if (zstr(detect)) {
|
||||
/* bad input */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", PLAY_AND_DETECT_SPEECH_SYNTAX);
|
||||
response = "USAGE ERROR";
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* need to have at 2 parameters for detect */
|
||||
if (switch_separate_string(detect, ' ', argv, (sizeof(argv) / sizeof(argv[0]))) == 2) {
|
||||
char *file = lbuf;
|
||||
char *engine = argv[0];
|
||||
char *grammar = argv[1];
|
||||
char *result = NULL;
|
||||
switch_ivr_play_and_detect_speech(session, file, engine, grammar, &result);
|
||||
switch_channel_set_variable(channel, "detect_speech_result", result);
|
||||
} else {
|
||||
/* bad input */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", PLAY_AND_DETECT_SPEECH_SYNTAX);
|
||||
response = "USAGE ERROR";
|
||||
}
|
||||
|
||||
done:
|
||||
switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, response);
|
||||
}
|
||||
|
||||
#define SCHED_HEARTBEAT_SYNTAX "[0|<seconds>]"
|
||||
SWITCH_STANDARD_APP(sched_heartbeat_function)
|
||||
@@ -904,6 +1102,18 @@ SWITCH_STANDARD_APP(eval_function)
|
||||
return;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(zombie_function)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_up(channel)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s MMM Brains....\n", switch_channel_get_name(channel));
|
||||
switch_channel_set_flag(channel, CF_ZOMBIE_EXEC);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(hangup_function)
|
||||
{
|
||||
@@ -967,6 +1177,19 @@ SWITCH_STANDARD_APP(redirect_function)
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(send_info_function)
|
||||
{
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
/* Tell the channel to send info */
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = data;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_INFO;
|
||||
msg.string_array_arg[2] = data;
|
||||
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(jitterbuffer_function)
|
||||
{
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
@@ -1271,6 +1494,7 @@ SWITCH_STANDARD_APP(event_function)
|
||||
switch_assert(new);
|
||||
memcpy(new, val, len);
|
||||
event->subclass_name = new;
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, var, val);
|
||||
} else {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, var, val);
|
||||
}
|
||||
@@ -1447,7 +1671,7 @@ SWITCH_STANDARD_API(chat_api_function)
|
||||
if (!zstr(cmd) && (lbuf = strdup(cmd))
|
||||
&& (argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])))) >= 4) {
|
||||
|
||||
if (switch_core_chat_send(argv[0], "dp", argv[1], argv[2], "", argv[3], !zstr(argv[4]) ? argv[4] : NULL, "") == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_core_chat_send_args(argv[0], "global", argv[1], argv[2], "", argv[3], !zstr(argv[4]) ? argv[4] : NULL, "") == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "Sent");
|
||||
} else {
|
||||
stream->write_function(stream, "Error! Message Not Sent");
|
||||
@@ -2022,7 +2246,7 @@ SWITCH_STANDARD_APP(read_function)
|
||||
SWITCH_STANDARD_APP(play_and_get_digits_function)
|
||||
{
|
||||
char *mydata;
|
||||
char *argv[10] = { 0 };
|
||||
char *argv[11] = { 0 };
|
||||
int argc;
|
||||
int32_t min_digits = 0;
|
||||
int32_t max_digits = 0;
|
||||
@@ -2035,6 +2259,7 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
|
||||
const char *var_name = NULL;
|
||||
const char *valid_terminators = NULL;
|
||||
const char *digits_regex = NULL;
|
||||
const char *transfer_on_failure = NULL;
|
||||
|
||||
if (!zstr(data) && (mydata = switch_core_session_strdup(session, data))) {
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
@@ -2084,6 +2309,10 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 10) {
|
||||
transfer_on_failure = argv[10];
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer on failure = [%s].\n", transfer_on_failure);
|
||||
}
|
||||
|
||||
if (min_digits <= 1) {
|
||||
min_digits = 1;
|
||||
@@ -2102,7 +2331,8 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
|
||||
}
|
||||
|
||||
switch_play_and_get_digits(session, min_digits, max_digits, max_tries, timeout, valid_terminators,
|
||||
prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer), digits_regex, digit_timeout);
|
||||
prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer),
|
||||
digits_regex, digit_timeout, transfer_on_failure);
|
||||
}
|
||||
|
||||
#define SAY_SYNTAX "<module_name>[:<lang>] <say_type> <say_method> [<say_gender>] <text>"
|
||||
@@ -3013,7 +3243,7 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
|
||||
switch_call_cause_t *cancel_cause)
|
||||
{
|
||||
switch_xml_t xml = NULL, x_user = NULL, x_param, x_params;
|
||||
switch_xml_t x_user = NULL, x_param, x_params;
|
||||
char *user = NULL, *domain = NULL, *dup_domain = NULL;
|
||||
const char *dest = NULL;
|
||||
switch_call_cause_t cause = SWITCH_CAUSE_NONE;
|
||||
@@ -3084,8 +3314,10 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
}
|
||||
}
|
||||
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", user);
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain);
|
||||
if (var_event) {
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", user);
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain);
|
||||
}
|
||||
|
||||
if (!dest) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No dial-string available, please check your user directory.\n");
|
||||
@@ -3176,8 +3408,8 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
switch_safe_free(d_dest);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_channel && xml) {
|
||||
|
||||
if (new_channel && x_user) {
|
||||
if ((x_params = switch_xml_child(x_user, "variables"))) {
|
||||
for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) {
|
||||
const char *pvar = switch_xml_attr(x_param, "name");
|
||||
@@ -3189,7 +3421,9 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
|
||||
done:
|
||||
|
||||
switch_xml_free(xml);
|
||||
if (x_user) {
|
||||
switch_xml_free(x_user);
|
||||
}
|
||||
|
||||
if (params) {
|
||||
switch_event_destroy(¶ms);
|
||||
@@ -3262,44 +3496,51 @@ SWITCH_STANDARD_APP(wait_for_silence_function)
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Usage: %s\n", WAIT_FOR_SILENCE_SYNTAX);
|
||||
}
|
||||
|
||||
static switch_status_t event_chat_send(const char *proto, const char *from, const char *to, const char *subject,
|
||||
const char *body, const char *type, const char *hint)
|
||||
static switch_status_t event_chat_send(switch_event_t *message_event)
|
||||
|
||||
{
|
||||
switch_event_t *event;
|
||||
const char *to;
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_RECV_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
if (proto)
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Proto", proto);
|
||||
if (from)
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "From", from);
|
||||
if (subject)
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Subject", subject);
|
||||
if (hint)
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Hint", hint);
|
||||
if (body)
|
||||
switch_event_add_body(event, "%s", body);
|
||||
if (to) {
|
||||
char *v;
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "To", to);
|
||||
if ((v = switch_core_get_variable_dup(to))) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Command", v);
|
||||
free(v);
|
||||
}
|
||||
switch_event_dup(&event, message_event);
|
||||
event->event_id = SWITCH_EVENT_RECV_MESSAGE;
|
||||
|
||||
if ((to = switch_event_get_header(event, "to"))) {
|
||||
char *v;
|
||||
if ((v = switch_core_get_variable_dup(to))) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Command", v);
|
||||
free(v);
|
||||
}
|
||||
|
||||
if (switch_event_fire(&event) == SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
|
||||
if (switch_event_fire(&event) == SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_event_destroy(&event);
|
||||
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
static switch_status_t api_chat_send(const char *proto, const char *from, const char *to, const char *subject,
|
||||
const char *body, const char *type, const char *hint)
|
||||
static switch_status_t api_chat_send(switch_event_t *message_event)
|
||||
{
|
||||
const char *proto;
|
||||
const char *from;
|
||||
const char *to;
|
||||
//const char *subject;
|
||||
//const char *body;
|
||||
const char *type;
|
||||
const char *hint;
|
||||
|
||||
proto = switch_event_get_header(message_event, "proto");
|
||||
from = switch_event_get_header(message_event, "from");
|
||||
to = switch_event_get_header(message_event, "to");
|
||||
//subject = switch_event_get_header(message_event, "subject");
|
||||
//body = switch_event_get_body(message_event);
|
||||
type = switch_event_get_header(message_event, "type");
|
||||
hint = switch_event_get_header(message_event, "hint");
|
||||
|
||||
|
||||
if (to) {
|
||||
char *v = NULL;
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
@@ -3322,7 +3563,7 @@ static switch_status_t api_chat_send(const char *proto, const char *from, const
|
||||
switch_api_execute(cmd, arg, NULL, &stream);
|
||||
|
||||
if (proto) {
|
||||
switch_core_chat_send(proto, "api", to, hint && strchr(hint, '/') ? hint : from, !zstr(type) ? type : NULL, (char *) stream.data, NULL, NULL);
|
||||
switch_core_chat_send_args(proto, "api", to, hint && strchr(hint, '/') ? hint : from, !zstr(type) ? type : NULL, (char *) stream.data, NULL, NULL);
|
||||
}
|
||||
|
||||
switch_safe_free(stream.data);
|
||||
@@ -3600,8 +3841,8 @@ static int next_file(switch_file_handle_t *handle)
|
||||
}
|
||||
|
||||
handle->samples = context->fh.samples;
|
||||
handle->samplerate = context->fh.samplerate;
|
||||
handle->channels = context->fh.channels;
|
||||
//handle->samplerate = context->fh.samplerate;
|
||||
//handle->channels = context->fh.channels;
|
||||
handle->format = context->fh.format;
|
||||
handle->sections = context->fh.sections;
|
||||
handle->seekable = context->fh.seekable;
|
||||
@@ -3667,7 +3908,9 @@ static switch_status_t file_string_file_close(switch_file_handle_t *handle)
|
||||
{
|
||||
file_string_context_t *context = handle->private_info;
|
||||
|
||||
switch_core_file_close(&context->fh);
|
||||
if (switch_test_flag((&context->fh), SWITCH_FILE_OPEN)) {
|
||||
switch_core_file_close(&context->fh);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -3778,7 +4021,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "digit_action_set_realm", "change binding realm", "",
|
||||
digit_action_set_realm_function, DIGIT_ACTION_SET_REALM_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "privacy", "Set privacy on calls", "Set caller privacy on calls.", privacy_function, "off|on|name|full|number",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
@@ -3802,7 +4044,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "delay_echo", "echo audio at a specified delay", "Delay n ms", delay_function, "<delay ms>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "strftime", "strftime", "strftime", strftime_function, "[<epoch>|]<format string>", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "phrase", "Say a Phrase", "Say a Phrase", phrase_function, "<macro_name>,<data>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "eval", "Do Nothing", "Do Nothing", eval_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "eval", "Do Nothing", "Do Nothing", eval_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "stop", "Do Nothing", "Do Nothing", eval_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "set_zombie_exec", "Enable Zombie Execution", "Enable Zombie Execution",
|
||||
zombie_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "pre_answer", "Pre-Answer the call", "Pre-Answer the call for a channel.", pre_answer_function, "", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "answer", "Answer the call", "Answer the call for a channel.", answer_function, "", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "hangup", "Hangup the call", "Hangup the call for a channel.", hangup_function, "[<cause>]", SAF_SUPPORT_NOMEDIA);
|
||||
@@ -3810,36 +4055,38 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "presence", "Send Presence", "Send Presence.", presence_function, "<rpid> <status> [<id>]",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "log", "Logs to the logger", LOG_LONG_DESC, log_function, "<log_level> <log_string>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "info", "Display Call Info", "Display Call Info", info_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "event", "Fire an event", "Fire an event", event_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "info", "Display Call Info", "Display Call Info", info_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "event", "Fire an event", "Fire an event", event_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "sound_test", "Analyze Audio", "Analyze Audio", sound_test_function, "", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "export", "Export a channel variable across a bridge", EXPORT_LONG_DESC, export_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "bridge_export", "Export a channel variable across a bridge", EXPORT_LONG_DESC, bridge_export_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "set", "Set a channel variable", SET_LONG_DESC, set_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "push", "Set a channel variable", SET_LONG_DESC, push_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "unshift", "Set a channel variable", SET_LONG_DESC, unshift_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "set_global", "Set a global variable", SET_GLOBAL_LONG_DESC, set_global_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "set_profile_var", "Set a caller profile variable", SET_PROFILE_VAR_LONG_DESC, set_profile_var_function,
|
||||
"<varname>=<value>", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
"<varname>=<value>", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "unset", "Unset a channel variable", UNSET_LONG_DESC, unset_function, "<varname>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "ring_ready", "Indicate Ring_Ready", "Indicate Ring_Ready on a channel.", ring_ready_function, "", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "remove_bugs", "Remove media bugs", "Remove all media bugs from a channel.", remove_bugs_function, "", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "break", "Break", "Set the break flag.", break_function, "", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "detect_speech", "Detect speech", "Detect speech on a channel.", detect_speech_function, DETECT_SPEECH_SYNTAX, SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "play_and_detect_speech", "Play and do speech recognition", "Play and do speech recognition", play_and_detect_speech_function, PLAY_AND_DETECT_SPEECH_SYNTAX, SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "ivr", "Run an ivr menu", "Run an ivr menu.", ivr_application_function, "<menu_name>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "redirect", "Send session redirect", "Send a redirect message to a session.", redirect_function, "<redirect_data>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "send_info", "Send info", "Send info", send_info_function, "<info>", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "jitterbuffer", "Send session jitterbuffer", "Send a jitterbuffer message to a session.",
|
||||
jitterbuffer_function, "<jitterbuffer_data>", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "send_display", "Send session a new display", "Send session a new display.", display_function, "<text>",
|
||||
@@ -3852,7 +4099,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "send_dtmf", "Send dtmf to be sent", "Send dtmf to be sent from a session", send_dtmf_function, "<dtmf_data>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "sched_cencel", "cancel scheduled tasks", "cancel scheduled tasks", sched_cancel_function, "[group]",
|
||||
SWITCH_ADD_APP(app_interface, "sched_cancel", "cancel scheduled tasks", "cancel scheduled tasks", sched_cancel_function, "[group]",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "sched_hangup", SCHED_HANGUP_DESCR, SCHED_HANGUP_DESCR, sched_hangup_function, "[+]<time> [<cause>]",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
@@ -3900,7 +4147,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
"<min> <max> <file> <var_name> <timeout> <terminators> <digit_timeout>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "play_and_get_digits", "Play and get Digits", "Play and get Digits",
|
||||
play_and_get_digits_function,
|
||||
"<min> <max> <tries> <timeout> <terminators> <file> <invalid_file> <var_name> <regexp> [<digit_timeout>]", SAF_NONE);
|
||||
"\n\t<min> <max> <tries> <timeout> <terminators> <file> <invalid_file> <var_name> <regexp> [<digit_timeout>] ['<failure_ext> [failure_dp [failure_context]]']", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "stop_record_session", "Stop Record Session", STOP_SESS_REC_DESC, stop_record_session_function, "<path>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "record_session", "Record Session", SESS_REC_DESC, record_session_function, "<path> [+<timeout>]", SAF_MEDIA_TAP);
|
||||
SWITCH_ADD_APP(app_interface, "record", "Record File", "Record a file from the channels input", record_function,
|
||||
@@ -3916,7 +4163,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "bridge", "Bridge Audio", "Bridge the audio between two sessions", audio_bridge_function, "<channel_url>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "system", "Execute a system command", "Execute a system command", system_session_function, "<command>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "say", "say", "say", say_function, SAY_SYNTAX, SAF_NONE);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "wait_for_silence", "wait_for_silence", "wait_for_silence", wait_for_silence_function, WAIT_FOR_SILENCE_SYNTAX,
|
||||
|
||||
@@ -303,12 +303,12 @@ SWITCH_STANDARD_APP(easyroute_app_function)
|
||||
|
||||
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
destnum = argv[0];
|
||||
if (argc == 2) {
|
||||
if (argc >= 2) {
|
||||
if (!strcasecmp(argv[1], "noat")) {
|
||||
noat = 1;
|
||||
} else if (!strcasecmp(argv[1], "separator")) {
|
||||
if (argc == 3) {
|
||||
switch_set_string(separator, argv[2]);
|
||||
separator = argv[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,13 +358,13 @@ SWITCH_STANDARD_API(easyroute_function)
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
if (argc == 2) {
|
||||
if (argc >= 2) {
|
||||
if (!strcasecmp(argv[1], "noat")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Entering noat.\n");
|
||||
noat = 1;
|
||||
} else if (!strcasecmp(argv[1], "separator")) {
|
||||
if (argc == 3) {
|
||||
switch_set_string(separator, argv[2]);
|
||||
separator = argv[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,15 +356,25 @@ static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t
|
||||
if (service && regex && replace) {
|
||||
switch_regex_t *re = NULL, *re2 = NULL;
|
||||
int proceed = 0, ovector[30];
|
||||
char substituted[1024] = "";
|
||||
char rbuf[1024] = "";
|
||||
char *substituted = NULL;
|
||||
char *substituted_2 = NULL;
|
||||
char *uri;
|
||||
char *uri_expanded = NULL;
|
||||
enum_route_t *route;
|
||||
int supported = 0;
|
||||
uint32_t len = 0;
|
||||
|
||||
if ((proceed = switch_regex_perform(number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
if (strchr(regex, '(')) {
|
||||
switch_perform_substitution(re, proceed, replace, number, substituted, sizeof(substituted), ovector);
|
||||
len = (uint32_t) (strlen(number) + strlen(replace) + 10) * proceed;
|
||||
if (!(substituted = malloc(len))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
switch_regex_safe_free(re);
|
||||
goto end;
|
||||
}
|
||||
memset(substituted, 0, len);
|
||||
|
||||
switch_perform_substitution(re, proceed, replace, number, substituted, len, ovector);
|
||||
uri = substituted;
|
||||
} else {
|
||||
uri = replace;
|
||||
@@ -377,15 +387,41 @@ static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t
|
||||
}
|
||||
|
||||
if ((proceed = switch_regex_perform(uri, route->regex, &re2, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
switch_event_t *event = NULL;
|
||||
|
||||
if (strchr(route->regex, '(')) {
|
||||
switch_perform_substitution(re2, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
|
||||
uri = rbuf;
|
||||
len = (uint32_t) (strlen(uri) + strlen(route->replace) + 10) * proceed;
|
||||
if (!(substituted_2 = malloc(len))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
switch_safe_free(substituted);
|
||||
switch_regex_safe_free(re);
|
||||
switch_regex_safe_free(re2);
|
||||
switch_mutex_unlock(MUTEX);
|
||||
goto end;
|
||||
}
|
||||
memset(substituted_2, 0, len);
|
||||
|
||||
switch_perform_substitution(re2, proceed, route->replace, uri, substituted_2, len, ovector);
|
||||
uri = substituted_2;
|
||||
} else {
|
||||
uri = route->replace;
|
||||
}
|
||||
switch_event_create(&event, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
uri_expanded = switch_event_expand_headers(event, uri);
|
||||
switch_event_destroy(&event);
|
||||
|
||||
if (uri_expanded == uri) {
|
||||
uri_expanded = NULL;
|
||||
} else {
|
||||
uri = uri_expanded;
|
||||
}
|
||||
|
||||
supported++;
|
||||
add_result(results, order, preference, service, uri, supported);
|
||||
|
||||
}
|
||||
switch_safe_free(uri_expanded);
|
||||
switch_safe_free(substituted_2);
|
||||
switch_regex_safe_free(re2);
|
||||
}
|
||||
switch_mutex_unlock(MUTEX);
|
||||
@@ -394,6 +430,7 @@ static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t
|
||||
add_result(results, order, preference, service, uri, 0);
|
||||
}
|
||||
|
||||
switch_safe_free(substituted);
|
||||
switch_regex_safe_free(re);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1329,7 +1329,7 @@ static switch_bool_t inband_dtmf_callback(switch_media_bug_t *bug, void *user_da
|
||||
if (digit_str[0]) {
|
||||
char *p = digit_str;
|
||||
while (p && *p) {
|
||||
switch_dtmf_t dtmf;
|
||||
switch_dtmf_t dtmf = {0};
|
||||
dtmf.digit = *p;
|
||||
dtmf.duration = switch_core_default_dtmf_duration(0);
|
||||
switch_channel_queue_dtmf(channel, &dtmf);
|
||||
|
||||
@@ -37,7 +37,7 @@ SWITCH_MODULE_DEFINITION(mod_fifo, mod_fifo_load, mod_fifo_shutdown, NULL);
|
||||
|
||||
#define MANUAL_QUEUE_NAME "manual_calls"
|
||||
#define FIFO_EVENT "fifo::info"
|
||||
#define FIFO_DELAY_DESTROY 100
|
||||
|
||||
static switch_status_t load_config(int reload, int del_all);
|
||||
#define MAX_PRI 10
|
||||
|
||||
@@ -298,6 +298,7 @@ struct fifo_node {
|
||||
int caller_count;
|
||||
int consumer_count;
|
||||
int ring_consumer_count;
|
||||
int member_count;
|
||||
switch_time_t start_waiting;
|
||||
uint32_t importance;
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
@@ -311,6 +312,8 @@ struct fifo_node {
|
||||
outbound_strategy_t outbound_strategy;
|
||||
int ring_timeout;
|
||||
int default_lag;
|
||||
char *domain_name;
|
||||
struct fifo_node *next;
|
||||
};
|
||||
|
||||
typedef struct fifo_node fifo_node_t;
|
||||
@@ -520,13 +523,16 @@ static switch_status_t caller_read_frame_callback(switch_core_session_t *session
|
||||
char buf[25] = "";
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
const char *caller_exit_key = switch_channel_get_variable(channel, "fifo_caller_exit_key");
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
args.input_callback = moh_on_dtmf;
|
||||
args.buf = buf;
|
||||
args.buflen = sizeof(buf);
|
||||
args.read_frame_callback = chime_read_frame_callback;
|
||||
args.user_data = user_data;
|
||||
|
||||
if (switch_ivr_play_file(session, NULL, cd->list[cd->index], &args) != SWITCH_STATUS_SUCCESS) {
|
||||
status = switch_ivr_play_file(session, NULL, cd->list[cd->index], &args);
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
@@ -563,6 +569,8 @@ static switch_status_t consumer_read_frame_callback(switch_core_session_t *sessi
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
struct fifo_node;
|
||||
|
||||
static struct {
|
||||
switch_hash_t *caller_orig_hash;
|
||||
switch_hash_t *consumer_orig_hash;
|
||||
@@ -586,6 +594,7 @@ static struct {
|
||||
int threads;
|
||||
switch_thread_t *node_thread;
|
||||
int debug;
|
||||
struct fifo_node *nodes;
|
||||
} globals;
|
||||
|
||||
|
||||
@@ -633,9 +642,6 @@ static void cancel_caller_outbound_call(const char *key, switch_call_cause_t cau
|
||||
*cancel_cause = cause;
|
||||
}
|
||||
switch_mutex_unlock(globals.caller_orig_mutex);
|
||||
|
||||
fifo_caller_del(key);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -814,7 +820,8 @@ static fifo_node_t *create_node(const char *name, uint32_t importance, switch_mu
|
||||
char outbound_count[80] = "";
|
||||
callback_t cbt = { 0 };
|
||||
char *sql = NULL;
|
||||
|
||||
char *domain_name = NULL;
|
||||
|
||||
if (!globals.running) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -826,6 +833,12 @@ static fifo_node_t *create_node(const char *name, uint32_t importance, switch_mu
|
||||
node->pool = pool;
|
||||
node->outbound_strategy = default_strategy;
|
||||
node->name = switch_core_strdup(node->pool, name);
|
||||
|
||||
if (!strchr(name, '@')) {
|
||||
domain_name = switch_core_get_variable_dup("domain");
|
||||
node->domain_name = switch_core_strdup(node->pool, domain_name);
|
||||
}
|
||||
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
fifo_queue_create(&node->fifo_list[x], 1000, node->pool);
|
||||
switch_assert(node->fifo_list[x]);
|
||||
@@ -839,16 +852,25 @@ static fifo_node_t *create_node(const char *name, uint32_t importance, switch_mu
|
||||
cbt.len = sizeof(outbound_count);
|
||||
sql = switch_mprintf("select count(*) from fifo_outbound where fifo_name = '%q'", name);
|
||||
fifo_execute_sql_callback(mutex, sql, sql2str_callback, &cbt);
|
||||
if (atoi(outbound_count) > 0) {
|
||||
node->member_count = atoi(outbound_count);
|
||||
if (node->member_count > 0) {
|
||||
node->has_outbound = 1;
|
||||
}
|
||||
} else {
|
||||
node->has_outbound = 0;
|
||||
}
|
||||
switch_safe_free(sql);
|
||||
|
||||
node->importance = importance;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
|
||||
switch_core_hash_insert(globals.fifo_hash, name, node);
|
||||
node->next = globals.nodes;
|
||||
globals.nodes = node;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_safe_free(domain_name);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1202,6 +1224,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
node = switch_core_hash_find(globals.fifo_hash, node_name);
|
||||
switch_thread_rwlock_rdlock(node->rwlock);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
for (i = 0; i < cbh->rowcount; i++) {
|
||||
@@ -1249,15 +1272,29 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
for (i = 0; i < cbh->rowcount; i++) {
|
||||
struct call_helper *h = cbh->rows[i];
|
||||
char *parsed = NULL;
|
||||
int use_ent = 0;
|
||||
|
||||
if (strstr(h->originate_string, "user/")) {
|
||||
switch_event_create_brackets(h->originate_string, '<', '>', ',', &ovars, &parsed, SWITCH_TRUE);
|
||||
use_ent = 1;
|
||||
} else {
|
||||
switch_event_create_brackets(h->originate_string, '{', '}', ',', &ovars, &parsed, SWITCH_TRUE);
|
||||
}
|
||||
|
||||
switch_event_create_brackets(h->originate_string, '{', '}', ',', &ovars, &parsed, SWITCH_TRUE);
|
||||
switch_event_del_header(ovars, "fifo_outbound_uuid");
|
||||
|
||||
if (!h->timeout) h->timeout = node->ring_timeout;
|
||||
if (timeout < h->timeout) timeout = h->timeout;
|
||||
|
||||
stream.write_function(&stream, "[leg_timeout=%d,fifo_outbound_uuid=%s,fifo_name=%s]%s,",
|
||||
h->timeout, h->uuid, node->name, parsed ? parsed : h->originate_string);
|
||||
if (use_ent) {
|
||||
stream.write_function(&stream, "{ignore_early_media=true,outbound_redirect_fatal=true,leg_timeout=%d,fifo_outbound_uuid=%s,fifo_name=%s}%s%s",
|
||||
h->timeout, h->uuid, node->name,
|
||||
parsed ? parsed : h->originate_string, (i == cbh->rowcount - 1) ? "" : SWITCH_ENT_ORIGINATE_DELIM);
|
||||
} else {
|
||||
stream.write_function(&stream, "[leg_timeout=%d,fifo_outbound_uuid=%s,fifo_name=%s]%s,",
|
||||
h->timeout, h->uuid, node->name, parsed ? parsed : h->originate_string);
|
||||
}
|
||||
|
||||
stream2.write_function(&stream2, "%s,", h->uuid);
|
||||
switch_safe_free(parsed);
|
||||
|
||||
@@ -1265,10 +1302,6 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
|
||||
originate_string = (char *) stream.data;
|
||||
|
||||
if (originate_string) {
|
||||
end_of(originate_string) = '\0';
|
||||
}
|
||||
|
||||
uuid_list = (char *) stream2.data;
|
||||
|
||||
if (uuid_list) {
|
||||
@@ -1477,6 +1510,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
node->ring_consumer_count = 0;
|
||||
node->busy = 0;
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
}
|
||||
|
||||
|
||||
@@ -1533,6 +1567,7 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
node = switch_core_hash_find(globals.fifo_hash, h->node_name);
|
||||
switch_thread_rwlock_rdlock(node->rwlock);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (node) {
|
||||
@@ -1582,7 +1617,7 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
sql = switch_mprintf("update fifo_outbound set ring_count=ring_count-1, "
|
||||
"outbound_fail_count=outbound_fail_count+1, next_avail=%ld + lag + 1 where uuid='%q' and use_count > 0",
|
||||
"outbound_fail_count=outbound_fail_count+1, next_avail=%ld + lag + 1 where uuid='%q'",
|
||||
(long) switch_epoch_time_now(NULL), h->uuid);
|
||||
fifo_execute_sql(sql, globals.sql_mutex);
|
||||
switch_safe_free(sql);
|
||||
@@ -1640,6 +1675,7 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
}
|
||||
node->busy = 0;
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
}
|
||||
switch_core_destroy_memory_pool(&h->pool);
|
||||
|
||||
@@ -1771,73 +1807,88 @@ static void find_consumers(fifo_node_t *node)
|
||||
|
||||
static void *SWITCH_THREAD_FUNC node_thread_run(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
fifo_node_t *node;
|
||||
fifo_node_t *node, *last, *this_node;
|
||||
int cur_priority = 1;
|
||||
|
||||
globals.node_thread_running = 1;
|
||||
|
||||
while (globals.node_thread_running == 1) {
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
const void *var;
|
||||
int ppl_waiting, consumer_total, idle_consumers, found = 0;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
|
||||
if (globals.debug) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Trying priority: %d\n", cur_priority);
|
||||
|
||||
last = NULL;
|
||||
node = globals.nodes;
|
||||
|
||||
restart:
|
||||
while(node) {
|
||||
int x = 0;
|
||||
switch_event_t *pop;
|
||||
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
if ((node = (fifo_node_t *) val)) {
|
||||
int x = 0;
|
||||
switch_event_t *pop;
|
||||
this_node = node;
|
||||
node = node->next;
|
||||
|
||||
if (node->ready == FIFO_DELAY_DESTROY) {
|
||||
if (switch_thread_rwlock_trywrlock(node->rwlock) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&pop);
|
||||
}
|
||||
}
|
||||
|
||||
node->ready = 0;
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_mutex_unlock(node->mutex);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
goto restart;
|
||||
if (this_node->ready == 0) {
|
||||
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(this_node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
const char *caller_uuid = switch_event_get_header(pop, "unique-id");
|
||||
switch_ivr_kill_uuid(caller_uuid, SWITCH_CAUSE_MANAGER_REQUEST);
|
||||
switch_event_destroy(&pop);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (node->outbound_priority == 0) node->outbound_priority = 5;
|
||||
if (node->has_outbound && node->ready && !node->busy && node->outbound_priority == cur_priority) {
|
||||
ppl_waiting = node_caller_count(node);
|
||||
consumer_total = node->consumer_count;
|
||||
idle_consumers = node_idle_consumers(node);
|
||||
|
||||
if (globals.debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"%s waiting %d consumer_total %d idle_consumers %d ring_consumers %d pri %d\n",
|
||||
node->name, ppl_waiting, consumer_total, idle_consumers, node->ring_consumer_count, node->outbound_priority);
|
||||
if (this_node->ready == 0 && switch_thread_rwlock_trywrlock(this_node->rwlock) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", this_node->name);
|
||||
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(this_node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&pop);
|
||||
}
|
||||
}
|
||||
|
||||
if (last) {
|
||||
last->next = this_node->next;
|
||||
} else {
|
||||
globals.nodes = this_node->next;
|
||||
}
|
||||
|
||||
switch_core_hash_destroy(&this_node->consumer_hash);
|
||||
switch_mutex_unlock(this_node->mutex);
|
||||
switch_mutex_unlock(this_node->update_mutex);
|
||||
switch_thread_rwlock_unlock(this_node->rwlock);
|
||||
switch_core_destroy_memory_pool(&this_node->pool);
|
||||
continue;
|
||||
}
|
||||
|
||||
last = this_node;
|
||||
|
||||
if (this_node->outbound_priority == 0) this_node->outbound_priority = 5;
|
||||
|
||||
if (this_node->has_outbound && !this_node->busy && this_node->outbound_priority == cur_priority) {
|
||||
ppl_waiting = node_caller_count(this_node);
|
||||
consumer_total = this_node->consumer_count;
|
||||
idle_consumers = node_idle_consumers(this_node);
|
||||
|
||||
if (globals.debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"%s waiting %d consumer_total %d idle_consumers %d ring_consumers %d pri %d\n",
|
||||
this_node->name, ppl_waiting, consumer_total, idle_consumers, this_node->ring_consumer_count, this_node->outbound_priority);
|
||||
}
|
||||
|
||||
|
||||
if ((ppl_waiting - node->ring_consumer_count > 0) && (!consumer_total || !idle_consumers)) {
|
||||
found++;
|
||||
find_consumers(node);
|
||||
switch_yield(1000000);
|
||||
}
|
||||
if ((ppl_waiting - this_node->ring_consumer_count > 0) && (!consumer_total || !idle_consumers)) {
|
||||
found++;
|
||||
find_consumers(this_node);
|
||||
switch_yield(1000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (++cur_priority > 10) {
|
||||
cur_priority = 1;
|
||||
@@ -1875,20 +1926,6 @@ static int stop_node_thread(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_ocancel(switch_core_session_t *session)
|
||||
{
|
||||
//switch_channel_t *channel;
|
||||
//const char *var;
|
||||
|
||||
switch_assert(session);
|
||||
|
||||
//channel = switch_core_session_get_channel(session);
|
||||
|
||||
cancel_caller_outbound_call(switch_core_session_get_uuid(session), SWITCH_CAUSE_ORIGINATOR_CANCEL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void check_cancel(fifo_node_t *node)
|
||||
{
|
||||
int ppl_waiting;
|
||||
@@ -1918,9 +1955,16 @@ static void send_presence(fifo_node_t *node)
|
||||
}
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "park");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", node->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", node->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "queue");
|
||||
|
||||
if (node->domain_name) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s@%s", node->name, node->domain_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", node->name, node->domain_name);
|
||||
} else {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", node->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", node->name);
|
||||
}
|
||||
|
||||
if ((wait_count = node_caller_count(node)) > 0) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Active (%d waiting)", wait_count);
|
||||
} else {
|
||||
@@ -1942,39 +1986,52 @@ static void send_presence(fifo_node_t *node)
|
||||
static void pres_event_handler(switch_event_t *event)
|
||||
{
|
||||
char *to = switch_event_get_header(event, "to");
|
||||
char *dup_to = NULL, *node_name;
|
||||
char *domain_name = NULL;
|
||||
char *dup_to = NULL, *node_name , *dup_node_name;
|
||||
fifo_node_t *node;
|
||||
|
||||
if (!globals.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!to || strncasecmp(to, "park+", 5)) {
|
||||
if (!to || strncasecmp(to, "queue+", 6) || !strchr(to, '@')) {
|
||||
return;
|
||||
}
|
||||
|
||||
dup_to = strdup(to);
|
||||
switch_assert(dup_to);
|
||||
|
||||
node_name = dup_to + 5;
|
||||
node_name = dup_to + 6;
|
||||
|
||||
if ((domain_name = strchr(node_name, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
}
|
||||
|
||||
dup_node_name = switch_mprintf("%q@%q", node_name, domain_name);
|
||||
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (!(node = switch_core_hash_find(globals.fifo_hash, node_name))) {
|
||||
if (!(node = switch_core_hash_find(globals.fifo_hash, node_name)) && !(node = switch_core_hash_find(globals.fifo_hash, dup_node_name))) {
|
||||
node = create_node(node_name, 0, globals.sql_mutex);
|
||||
node->domain_name = switch_core_strdup(node->pool, domain_name);
|
||||
node->ready = 1;
|
||||
}
|
||||
|
||||
switch_thread_rwlock_rdlock(node->rwlock);
|
||||
send_presence(node);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_safe_free(dup_to);
|
||||
switch_safe_free(dup_node_name);
|
||||
}
|
||||
|
||||
static uint32_t fifo_add_outbound(const char *node_name, const char *url, uint32_t priority)
|
||||
{
|
||||
fifo_node_t *node;
|
||||
switch_event_t *call_event;
|
||||
uint32_t i = 0;
|
||||
|
||||
if (priority >= MAX_PRI) {
|
||||
priority = MAX_PRI - 1;
|
||||
@@ -1988,6 +2045,8 @@ static uint32_t fifo_add_outbound(const char *node_name, const char *url, uint32
|
||||
node = create_node(node_name, 0, globals.sql_mutex);
|
||||
}
|
||||
|
||||
switch_thread_rwlock_rdlock(node->rwlock);
|
||||
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_event_create(&call_event, SWITCH_EVENT_CHANNEL_DATA);
|
||||
@@ -1996,7 +2055,11 @@ static uint32_t fifo_add_outbound(const char *node_name, const char *url, uint32
|
||||
fifo_queue_push(node->fifo_list[priority], call_event);
|
||||
call_event = NULL;
|
||||
|
||||
return fifo_queue_size(node->fifo_list[priority]);
|
||||
i = fifo_queue_size(node->fifo_list[priority]);
|
||||
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
@@ -2218,11 +2281,11 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
char *list_string;
|
||||
int nlist_count;
|
||||
char *nlist[MAX_NODES_PER_CONSUMER];
|
||||
int consumer = 0;
|
||||
int consumer = 0, in_table = 0;
|
||||
const char *arg_fifo_name = NULL;
|
||||
const char *arg_inout = NULL;
|
||||
const char *serviced_uuid = NULL;
|
||||
|
||||
|
||||
if (!globals.running) {
|
||||
return;
|
||||
}
|
||||
@@ -2395,6 +2458,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
|
||||
fifo_queue_push(node->fifo_list[p], call_event);
|
||||
fifo_caller_add(node, session);
|
||||
in_table = 1;
|
||||
|
||||
call_event = NULL;
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", fifo_queue_size(node->fifo_list[p]));
|
||||
@@ -2491,8 +2555,6 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
|
||||
switch_channel_clear_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_BRIDGE_TAG);
|
||||
|
||||
fifo_caller_del(switch_core_session_get_uuid(session));
|
||||
|
||||
if (!aborted && switch_channel_ready(channel)) {
|
||||
switch_channel_set_state(channel, CS_HIBERNATE);
|
||||
goto done;
|
||||
@@ -2524,10 +2586,13 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
if (orbit_ann) {
|
||||
switch_ivr_play_file(session, NULL, orbit_ann, NULL);
|
||||
}
|
||||
switch_ivr_session_transfer(session, cd.orbit_exten, cd.orbit_dialplan, cd.orbit_context);
|
||||
|
||||
if (strcmp(cd.orbit_exten, "_continue_")) {
|
||||
switch_ivr_session_transfer(session, cd.orbit_exten, cd.orbit_dialplan, cd.orbit_context);
|
||||
}
|
||||
}
|
||||
|
||||
check_ocancel(session);
|
||||
cancel_caller_outbound_call(switch_core_session_get_uuid(session), SWITCH_CAUSE_ORIGINATOR_CANCEL);
|
||||
|
||||
goto done;
|
||||
|
||||
@@ -2958,6 +3023,9 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
||||
switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, switch_core_session_get_uuid(other_session));
|
||||
switch_channel_set_variable(other_channel, SWITCH_SIGNAL_BOND_VARIABLE, switch_core_session_get_uuid(session));
|
||||
|
||||
switch_ivr_multi_threaded_bridge(session, other_session, on_dtmf, other_session, session);
|
||||
|
||||
if (outbound_id) {
|
||||
@@ -3135,6 +3203,10 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
|
||||
done:
|
||||
|
||||
if (!consumer && in_table) {
|
||||
fifo_caller_del(switch_core_session_get_uuid(session));
|
||||
}
|
||||
|
||||
if (switch_true(switch_channel_get_variable(channel, "fifo_destroy_after_use"))) {
|
||||
do_destroy = 1;
|
||||
}
|
||||
@@ -3146,7 +3218,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
}
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
if (node->ready == 1 && do_destroy) {
|
||||
node->ready = FIFO_DELAY_DESTROY;
|
||||
node->ready = 0;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
@@ -3664,7 +3736,6 @@ void node_dump(switch_stream_handle_t *stream)
|
||||
#define FIFO_API_SYNTAX "list|list_verbose|count|debug|status|importance [<fifo name>]|reparse [del_all]"
|
||||
SWITCH_STANDARD_API(fifo_api_function)
|
||||
{
|
||||
int len = 0;
|
||||
fifo_node_t *node;
|
||||
char *data = NULL;
|
||||
int argc = 0;
|
||||
@@ -3723,6 +3794,7 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
|
||||
switch_mutex_lock(node->mutex);
|
||||
list_node(node, x_report, &x, verbose);
|
||||
switch_mutex_unlock(node->mutex);
|
||||
@@ -3759,9 +3831,8 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
len = node_caller_count(node);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node_caller_count(node), len);
|
||||
stream->write_function(stream, "%s:%d:%d:%d:%d:%d\n", (char *) var, node->consumer_count, node_caller_count(node), node->member_count, node->ring_consumer_count, node_idle_consumers(node));
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
x++;
|
||||
}
|
||||
@@ -3770,9 +3841,8 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
stream->write_function(stream, "none\n");
|
||||
}
|
||||
} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
|
||||
len = node_caller_count(node);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node_caller_count(node), len);
|
||||
stream->write_function(stream, "%s:%d:%d:%d:%d:%d\n", argv[1], node->consumer_count, node_caller_count(node), node->member_count, node->ring_consumer_count, node_idle_consumers(node));
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
} else {
|
||||
stream->write_function(stream, "none\n");
|
||||
@@ -3782,7 +3852,6 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
len = node_caller_count(node);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d\n", (char *) var, node->has_outbound);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
@@ -3793,7 +3862,6 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
stream->write_function(stream, "none\n");
|
||||
}
|
||||
} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
|
||||
len = node_caller_count(node);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d\n", argv[1], node->has_outbound);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
@@ -3966,8 +4034,8 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
switch_mutex_lock(globals.mutex);
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
if ((node = (fifo_node_t *) val) && node->is_static) {
|
||||
node->ready = 0;
|
||||
if ((node = (fifo_node_t *) val) && node->is_static && node->ready == 1) {
|
||||
node->ready = -1;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
@@ -3984,6 +4052,7 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
|
||||
if (!(node = switch_core_hash_find(globals.fifo_hash, MANUAL_QUEUE_NAME))) {
|
||||
node = create_node(MANUAL_QUEUE_NAME, 0, globals.sql_mutex);
|
||||
node->ready = 2;
|
||||
node->is_static = 0;
|
||||
}
|
||||
|
||||
@@ -4136,7 +4205,7 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
free(sql);
|
||||
free(name_dup);
|
||||
node->has_outbound = 1;
|
||||
|
||||
node->member_count++;
|
||||
}
|
||||
node->ready = 1;
|
||||
node->is_static = 1;
|
||||
@@ -4151,41 +4220,18 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
done:
|
||||
|
||||
if (reload) {
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
switch_event_t *pop;
|
||||
fifo_node_t *node;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
top:
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
int x = 0;
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
if (!(node = (fifo_node_t *) val) || !node->is_static || node->ready) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node_caller_count(node) || node->consumer_count || node_idle_consumers(node)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s removal delayed, still in use.\n", node->name);
|
||||
node->ready = FIFO_DELAY_DESTROY;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&pop);
|
||||
}
|
||||
}
|
||||
|
||||
for (node = globals.nodes; node; node = node->next) {
|
||||
if (node->ready == -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s queued for removal\n", node->name);
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
goto top;
|
||||
node->ready = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fifo_caller_del(NULL);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
fifo_caller_del(NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -4198,6 +4244,8 @@ static void fifo_member_add(char *fifo_name, char *originate_string, int simo_co
|
||||
{
|
||||
char digest[SWITCH_MD5_DIGEST_STRING_SIZE] = { 0 };
|
||||
char *sql, *name_dup, *p;
|
||||
char outbound_count[80] = "";
|
||||
callback_t cbt = { 0 };
|
||||
fifo_node_t *node = NULL;
|
||||
|
||||
if (!fifo_name) return;
|
||||
@@ -4221,8 +4269,6 @@ static void fifo_member_add(char *fifo_name, char *originate_string, int simo_co
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
node->has_outbound = 1;
|
||||
|
||||
name_dup = strdup(fifo_name);
|
||||
if ((p = strchr(name_dup, '@'))) {
|
||||
*p = '\0';
|
||||
@@ -4239,6 +4285,17 @@ static void fifo_member_add(char *fifo_name, char *originate_string, int simo_co
|
||||
free(sql);
|
||||
free(name_dup);
|
||||
|
||||
cbt.buf = outbound_count;
|
||||
cbt.len = sizeof(outbound_count);
|
||||
sql = switch_mprintf("select count(*) from fifo_outbound where fifo_name = '%q'", fifo_name);
|
||||
fifo_execute_sql_callback(globals.sql_mutex, sql, sql2str_callback, &cbt);
|
||||
node->member_count = atoi(outbound_count);
|
||||
if (node->member_count > 0) {
|
||||
node->has_outbound = 1;
|
||||
} else {
|
||||
node->has_outbound = 0;
|
||||
}
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
static void fifo_member_del(char *fifo_name, char *originate_string)
|
||||
@@ -4274,10 +4331,11 @@ static void fifo_member_del(char *fifo_name, char *originate_string)
|
||||
cbt.len = sizeof(outbound_count);
|
||||
sql = switch_mprintf("select count(*) from fifo_outbound where fifo_name = '%q'", node->name);
|
||||
fifo_execute_sql_callback(globals.sql_mutex, sql, sql2str_callback, &cbt);
|
||||
if (atoi(outbound_count) > 0) {
|
||||
node->has_outbound = 1;
|
||||
node->member_count = atoi(outbound_count);
|
||||
if (node->member_count > 0) {
|
||||
node->has_outbound = 1;
|
||||
} else {
|
||||
node->has_outbound = 0;
|
||||
node->has_outbound = 0;
|
||||
}
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
@@ -4433,10 +4491,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_fifo_load)
|
||||
*/
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown)
|
||||
{
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
switch_event_t *pop = NULL;
|
||||
fifo_node_t *node;
|
||||
fifo_node_t *node, *this_node;
|
||||
switch_mutex_t *mutex = globals.mutex;
|
||||
|
||||
switch_event_unbind(&globals.node);
|
||||
@@ -4453,24 +4509,27 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown)
|
||||
switch_cond_next();
|
||||
}
|
||||
|
||||
node = globals.nodes;
|
||||
|
||||
while ((hi = switch_hash_first(NULL, globals.fifo_hash))) {
|
||||
while(node) {
|
||||
int x = 0;
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
switch_mutex_lock(node->mutex);
|
||||
this_node = node;
|
||||
node = node->next;
|
||||
|
||||
|
||||
switch_mutex_lock(this_node->update_mutex);
|
||||
switch_mutex_lock(this_node->mutex);
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
while (fifo_queue_pop(this_node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&pop);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(node->mutex);
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
switch_mutex_unlock(this_node->mutex);
|
||||
switch_core_hash_delete(globals.fifo_hash, this_node->name);
|
||||
switch_core_hash_destroy(&this_node->consumer_hash);
|
||||
switch_mutex_unlock(this_node->update_mutex);
|
||||
switch_core_destroy_memory_pool(&this_node->pool);
|
||||
}
|
||||
|
||||
switch_core_hash_destroy(&globals.fifo_hash);
|
||||
|
||||
@@ -4,9 +4,10 @@ MODNAME=mod_hash
|
||||
ESL_DIR=$(switch_srcdir)/libs/esl
|
||||
|
||||
mod_LTLIBRARIES = mod_hash.la
|
||||
mod_hash_la_DEPENDENCIES = $(ESL_DIR)/libesl.so
|
||||
mod_hash_la_SOURCES = mod_hash.c
|
||||
mod_hash_la_CFLAGS = $(AM_CFLAGS) -I$(ESL_DIR)/src/include
|
||||
mod_hash_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(ESL_DIR)/libesl.so
|
||||
mod_hash_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_hash_la_LDFLAGS = -avoid-version -module -no-undefined -shared -L$(ESL_DIR) -lesl
|
||||
|
||||
$(ESL_DIR)/libesl.so:
|
||||
|
||||
@@ -407,7 +407,7 @@ SWITCH_LIMIT_STATUS(limit_status_hash)
|
||||
|
||||
/* CORE HASH STUFF */
|
||||
|
||||
#define HASH_USAGE "[insert|delete]/<realm>/<key>/<val>"
|
||||
#define HASH_USAGE "[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>"
|
||||
#define HASH_DESC "save data"
|
||||
|
||||
SWITCH_STANDARD_APP(hash_function)
|
||||
@@ -443,11 +443,33 @@ SWITCH_STANDARD_APP(hash_function)
|
||||
value = strdup(argv[3]);
|
||||
switch_assert(value);
|
||||
switch_core_hash_insert(globals.db_hash, hash_key, value);
|
||||
} else if (!strcasecmp(argv[0], "insert_ifempty")) {
|
||||
if (argc < 4) {
|
||||
goto usage;
|
||||
}
|
||||
if (!(value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
value = strdup(argv[3]);
|
||||
switch_assert(value);
|
||||
switch_core_hash_insert(globals.db_hash, hash_key, value);
|
||||
} else {
|
||||
switch_safe_free(value);
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(argv[0], "delete")) {
|
||||
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
switch_safe_free(value);
|
||||
switch_core_hash_delete(globals.db_hash, hash_key);
|
||||
}
|
||||
} else if (!strcasecmp(argv[0], "delete_ifmatch")) {
|
||||
if (argc < 4) {
|
||||
goto usage;
|
||||
}
|
||||
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
if(!strcmp(argv[3], value)) {
|
||||
switch_core_hash_delete(globals.db_hash, hash_key);
|
||||
}
|
||||
switch_safe_free(value);
|
||||
}
|
||||
} else {
|
||||
goto usage;
|
||||
}
|
||||
@@ -463,7 +485,7 @@ SWITCH_STANDARD_APP(hash_function)
|
||||
switch_safe_free(hash_key);
|
||||
}
|
||||
|
||||
#define HASH_API_USAGE "insert|select|delete/realm/key[/value]"
|
||||
#define HASH_API_USAGE "insert|insert_ifempty|select|delete|delete_ifmatch/realm/key[/value]"
|
||||
SWITCH_STANDARD_API(hash_api_function)
|
||||
{
|
||||
int argc = 0;
|
||||
@@ -498,6 +520,21 @@ SWITCH_STANDARD_API(hash_api_function)
|
||||
switch_core_hash_insert(globals.db_hash, hash_key, value);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
|
||||
} else if (!strcasecmp(argv[0], "insert_ifempty")) {
|
||||
if (argc < 4) {
|
||||
goto usage;
|
||||
}
|
||||
switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
|
||||
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
stream->write_function(stream, "-ERR key already exists\n");
|
||||
switch_safe_free(value);
|
||||
} else {
|
||||
value = strdup(argv[3]);
|
||||
switch_assert(value);
|
||||
switch_core_hash_insert(globals.db_hash, hash_key, value);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
}
|
||||
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
|
||||
} else if (!strcasecmp(argv[0], "delete")) {
|
||||
switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
|
||||
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
@@ -508,6 +545,23 @@ SWITCH_STANDARD_API(hash_api_function)
|
||||
stream->write_function(stream, "-ERR Not found\n");
|
||||
}
|
||||
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
|
||||
} else if (!strcasecmp(argv[0], "delete_ifmatch")) {
|
||||
if (argc < 4) {
|
||||
goto usage;
|
||||
}
|
||||
switch_thread_rwlock_wrlock(globals.db_hash_rwlock);
|
||||
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
if(!strcmp(argv[3],value)) {
|
||||
switch_core_hash_delete(globals.db_hash, hash_key);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Doesn't match\n");
|
||||
}
|
||||
switch_safe_free(value);
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Not found\n");
|
||||
}
|
||||
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
|
||||
} else if (!strcasecmp(argv[0], "select")) {
|
||||
switch_thread_rwlock_rdlock(globals.db_hash_rwlock);
|
||||
if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
|
||||
@@ -945,7 +999,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
|
||||
switch_scheduler_add_task(switch_epoch_time_now(NULL) + LIMIT_HASH_CLEANUP_INTERVAL, limit_hash_cleanup_callback, "limit_hash_cleanup", "mod_hash", 0, NULL,
|
||||
SSHF_NONE);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "hash", "Insert into the hashtable", HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA)
|
||||
SWITCH_ADD_APP(app_interface, "hash", "Insert into the hashtable", HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA | SAF_ZOMBIE_EXEC)
|
||||
SWITCH_ADD_API(commands_api_interface, "hash", "hash get/set", hash_api_function, "[insert|delete|select]/<realm>/<key>/<value>");
|
||||
SWITCH_ADD_API(commands_api_interface, "hash_dump", "dump hash/limit_hash data (used for synchronization)", hash_dump_function, HASH_DUMP_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "hash_remote", "hash remote", hash_remote_function, HASH_REMOTE_SYNTAX);
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
BASE=../../../..
|
||||
LOCAL_OBJS=ivr.o util.o config.o menu.o
|
||||
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -127,6 +127,7 @@ struct callback_obj {
|
||||
int matches;
|
||||
switch_memory_pool_t *pool;
|
||||
char *lookup_number;
|
||||
char *lrn_number;
|
||||
char *cid;
|
||||
switch_bool_t intrastate;
|
||||
switch_bool_t intralata;
|
||||
@@ -604,6 +605,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
char *key = NULL;
|
||||
int i = 0;
|
||||
int r = 0;
|
||||
switch_bool_t lcr_skipped = SWITCH_TRUE; /* assume we'll throw it away, paranoid about leak */
|
||||
|
||||
switch_memory_pool_t *pool = cbt->pool;
|
||||
|
||||
@@ -622,6 +624,10 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
additional->carrier_name = switch_core_strdup(pool, switch_str_nil(argv[i]));
|
||||
} else if (CF("lcr_rate_field")) {
|
||||
if (!argv[i] || zstr(argv[i])) {
|
||||
/* maybe we want to consider saying which carriers have null rate fields... maybe they can run the query and find out */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "rate field is null, skipping\n");
|
||||
/* kill prev/next pointers */
|
||||
/* additional->prev = NULL; */
|
||||
goto end;
|
||||
}
|
||||
additional->rate = (float)atof(switch_str_nil(argv[i]));
|
||||
@@ -658,6 +664,13 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
additional->dialstring = get_bridge_data(pool, cbt->lookup_number, cbt->cid, additional, cbt->profile, cbt->session);
|
||||
|
||||
if (cbt->head == NULL) {
|
||||
if (cbt->max_rate && (cbt->max_rate < additional->rate)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Skipping [%s] because [%f] is higher than the max_rate of [%f]\n",
|
||||
additional->carrier_name, additional->rate, cbt->max_rate);
|
||||
lcr_skipped = SWITCH_FALSE;
|
||||
r = 0; goto end;
|
||||
}
|
||||
|
||||
key = switch_core_sprintf(pool, "%s:%s", additional->gw_prefix, additional->gw_suffix);
|
||||
additional->next = cbt->head;
|
||||
cbt->head = additional;
|
||||
@@ -666,6 +679,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error inserting into dedup hash\n");
|
||||
r = -1; goto end;
|
||||
}
|
||||
lcr_skipped = SWITCH_FALSE;
|
||||
r = 0; goto end;
|
||||
}
|
||||
|
||||
@@ -695,6 +709,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error inserting into dedup hash\n");
|
||||
r = -1; goto end;
|
||||
}
|
||||
lcr_skipped = SWITCH_FALSE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -716,6 +731,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error inserting into dedup hash\n");
|
||||
r = -1; goto end;
|
||||
}
|
||||
lcr_skipped = SWITCH_FALSE;
|
||||
break;
|
||||
} else if (current->next == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "adding %s to end of list after %s\n",
|
||||
@@ -726,6 +742,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error inserting into dedup hash\n");
|
||||
r = -1; goto end;
|
||||
}
|
||||
lcr_skipped = SWITCH_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -733,8 +750,21 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
|
||||
end:
|
||||
|
||||
/* event is freed in lcr_destroy() switch_event_destroy(&additional->fields); */
|
||||
|
||||
/* lcr was not added to any lists, so destroy lcr object here */
|
||||
if (lcr_skipped == SWITCH_TRUE) {
|
||||
/* complain loudly if we're asked to destroy a route that is
|
||||
added to the route list */
|
||||
if (additional && additional->prev != NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"additional->prev != NULL\n");
|
||||
}
|
||||
if (current && current->next == additional) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"current->next == additional\n");
|
||||
}
|
||||
lcr_destroy(additional);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
@@ -798,7 +828,7 @@ static switch_status_t is_intrastatelata(callback_t *cb_struct)
|
||||
cb_struct->lookup_number+1, cb_struct->lookup_number+4,
|
||||
cb_struct->cid+1, cb_struct->cid+4);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", sql);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", sql);
|
||||
|
||||
return(lcr_execute_sql_callback(sql, intrastatelata_callback, cb_struct));
|
||||
|
||||
@@ -808,8 +838,9 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
|
||||
{
|
||||
switch_stream_handle_t sql_stream = { 0 };
|
||||
char *digits = cb_struct->lookup_number;
|
||||
char *digits_copy;
|
||||
char *digits_expanded;
|
||||
char *digits_copy = NULL;
|
||||
char *digits_expanded = NULL;
|
||||
char *lrn_digits_expanded = NULL;
|
||||
profile_t *profile = cb_struct->profile;
|
||||
switch_bool_t lookup_status;
|
||||
switch_channel_t *channel;
|
||||
@@ -832,6 +863,11 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
|
||||
}
|
||||
|
||||
digits_expanded = expand_digits(cb_struct->pool, digits_copy, cb_struct->profile->quote_in_list);
|
||||
if (cb_struct->lrn_number) {
|
||||
lrn_digits_expanded = expand_digits(cb_struct->pool, cb_struct->lrn_number, cb_struct->profile->quote_in_list);
|
||||
} else {
|
||||
lrn_digits_expanded = switch_core_strdup(cb_struct->pool, digits_expanded);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "Has NPA NXX: [%u == %u]\n", profile->profile_has_npanxx, SWITCH_TRUE);
|
||||
if (profile->profile_has_npanxx == SWITCH_TRUE) {
|
||||
@@ -866,6 +902,10 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
|
||||
id_str = switch_core_sprintf(cb_struct->pool, "%d", cb_struct->profile->id);
|
||||
switch_channel_set_variable_var_check(channel, "lcr_query_profile", id_str, SWITCH_FALSE);
|
||||
switch_channel_set_variable_var_check(channel, "lcr_query_expanded_digits", digits_expanded, SWITCH_FALSE);
|
||||
switch_channel_set_variable_var_check(channel, "lcr_query_expanded_lrn_digits", lrn_digits_expanded, SWITCH_FALSE);
|
||||
if ( cb_struct->lrn_number ) {
|
||||
switch_channel_set_variable_var_check(channel, "lcr_lrn", cb_struct->lrn_number, SWITCH_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cb_struct->event) {
|
||||
@@ -876,6 +916,10 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
|
||||
id_str = switch_core_sprintf(cb_struct->pool, "%d", cb_struct->profile->id);
|
||||
switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_query_profile", id_str);
|
||||
switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_query_expanded_digits", digits_expanded);
|
||||
switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_query_expanded_lrn_digits", lrn_digits_expanded);
|
||||
if ( cb_struct->lrn_number ) {
|
||||
switch_event_add_header_string(cb_struct->event, SWITCH_STACK_BOTTOM, "lcr_lrn", cb_struct->lrn_number);
|
||||
}
|
||||
}
|
||||
|
||||
/* set up the query to be executed */
|
||||
@@ -998,7 +1042,7 @@ static switch_status_t lcr_load_config()
|
||||
char *export_fields = NULL;
|
||||
char *limit_type = NULL;
|
||||
int argc, x = 0;
|
||||
char *argv[4] = { 0 };
|
||||
char *argv[32] = { 0 };
|
||||
|
||||
SWITCH_STANDARD_STREAM(order_by);
|
||||
|
||||
@@ -1078,29 +1122,48 @@ static switch_status_t lcr_load_config()
|
||||
SWITCH_STANDARD_STREAM(sql_stream);
|
||||
if (zstr(custom_sql)) {
|
||||
/* use default sql */
|
||||
|
||||
/* Checking for codec field, adding if needed */
|
||||
if (db_check("SELECT codec FROM carrier_gateway LIMIT 1") == SWITCH_TRUE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec field defined.\n");
|
||||
} else {
|
||||
if (db_check("ALTER TABLE carrier_gateway add codec varchar(255);") == SWITCH_TRUE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "adding codec field your lcr carrier_gateway database schema.\n");
|
||||
} else {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checking for cid field, adding if needed */
|
||||
if (db_check("SELECT cid FROM lcr LIMIT 1") == SWITCH_TRUE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cid field defined.\n");
|
||||
} else {
|
||||
if (db_check("ALTER TABLE lcr add cid varchar(32);") == SWITCH_TRUE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "adding cid field to your lcr database schema.\n");
|
||||
} else {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (db_check("SELECT lrn FROM lcr LIMIT 1") != SWITCH_TRUE) {
|
||||
if (db_check("ALTER TABLE lcr ADD lrn BOOLEAN NOT NULL DEFAULT false")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "adding lrn field to your lcr database schema.\n");
|
||||
} else {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
sql_stream.write_function(&sql_stream,
|
||||
"SELECT l.digits AS lcr_digits, c.carrier_name AS lcr_carrier_name, l.${lcr_rate_field} AS lcr_rate_field, \
|
||||
cg.prefix AS lcr_gw_prefix, cg.suffix AS lcr_gw_suffix, l.lead_strip AS lcr_lead_strip, \
|
||||
l.trail_strip AS lcr_trail_strip, l.prefix AS lcr_prefix, l.suffix AS lcr_suffix "
|
||||
);
|
||||
if (db_check("SELECT codec from carrier_gateway limit 1") == SWITCH_TRUE) {
|
||||
sql_stream.write_function(&sql_stream, ", cg.codec AS lcr_codec ");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec field defined.\n");
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"codec field not defined, please update your lcr carrier_gateway database schema.\n"
|
||||
);
|
||||
}
|
||||
if (db_check("SELECT cid from lcr limit 1") == SWITCH_TRUE) {
|
||||
sql_stream.write_function(&sql_stream, ", l.cid AS lcr_cid ");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cid field defined.\n");
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cid field not defined, please update your lcr database schema.\n");
|
||||
}
|
||||
l.trail_strip AS lcr_trail_strip, l.prefix AS lcr_prefix, l.suffix AS lcr_suffix, \
|
||||
cg.codec AS lcr_codec, l.cid AS lcr_cid ");
|
||||
sql_stream.write_function(&sql_stream, "FROM lcr l JOIN carriers c ON l.carrier_id=c.id \
|
||||
JOIN carrier_gateway cg ON c.id=cg.carrier_id WHERE \
|
||||
c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND digits IN (");
|
||||
sql_stream.write_function(&sql_stream, "${lcr_query_expanded_digits}");
|
||||
JOIN carrier_gateway cg ON c.id=cg.carrier_id \
|
||||
WHERE c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND (\
|
||||
(digits IN (${lcr_query_expanded_digits}) AND lrn = false) OR \
|
||||
(digits IN (${lcr_query_expanded_lrn_digits}) AND lrn = true)");
|
||||
|
||||
sql_stream.write_function(&sql_stream, ") AND CURRENT_TIMESTAMP BETWEEN date_start AND date_end ");
|
||||
if (profile->id > 0) {
|
||||
sql_stream.write_function(&sql_stream, "AND lcr_profile=%d ", profile->id);
|
||||
@@ -1430,6 +1493,7 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
|
||||
switch_event_t *event = NULL;
|
||||
const char *intrastate = NULL;
|
||||
const char *intralata = NULL;
|
||||
const char *lrn = NULL;
|
||||
|
||||
if (session) {
|
||||
pool = switch_core_session_get_pool(session);
|
||||
@@ -1443,8 +1507,12 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
|
||||
|
||||
intrastate = switch_channel_get_variable(channel, "intrastate");
|
||||
intralata = switch_channel_get_variable(channel, "intralata");
|
||||
lrn = switch_channel_get_variable(channel, "lrn");
|
||||
routes.lrn_number = (char *) lrn;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", intrastate);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intralata channel var is [%s]\n", intralata);
|
||||
|
||||
if (!zstr(intralata) && !strcasecmp((char *)intralata, "true")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on intralata rates\n");
|
||||
routes.intralata = SWITCH_FALSE;
|
||||
@@ -1531,7 +1599,7 @@ void str_repeat(size_t how_many, char *what, switch_stream_handle_t *str_stream)
|
||||
SWITCH_STANDARD_APP(lcr_app_function)
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[4] = { 0 };
|
||||
char *argv[32] = { 0 };
|
||||
char *mydata = NULL;
|
||||
char *dest = NULL;
|
||||
char vbuf[1024] = "";
|
||||
@@ -1544,6 +1612,7 @@ SWITCH_STANDARD_APP(lcr_app_function)
|
||||
switch_memory_pool_t *pool;
|
||||
switch_event_t *event;
|
||||
const char *intra = NULL;
|
||||
const char *lrn = NULL;
|
||||
|
||||
if (!(mydata = switch_core_session_strdup(session, data))) {
|
||||
return;
|
||||
@@ -1557,11 +1626,15 @@ SWITCH_STANDARD_APP(lcr_app_function)
|
||||
switch_event_create(&event, SWITCH_EVENT_MESSAGE);
|
||||
routes.event = event;
|
||||
}
|
||||
|
||||
routes.pool = pool;
|
||||
|
||||
|
||||
lrn = switch_channel_get_variable(channel, "lrn");
|
||||
routes.lrn_number = (char *) lrn;
|
||||
|
||||
intra = switch_channel_get_variable(channel, "intrastate");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n",
|
||||
zstr(intra) ? "undef" : intra);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", zstr(intra) ? "undef" : intra);
|
||||
if (zstr(intra) || strcasecmp((char *)intra, "true")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on interstate rates\n");
|
||||
routes.intrastate = SWITCH_FALSE;
|
||||
@@ -1578,6 +1651,7 @@ SWITCH_STANDARD_APP(lcr_app_function)
|
||||
|
||||
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
dest = argv[0];
|
||||
|
||||
if (argc > 1) {
|
||||
lcr_profile = argv[1];
|
||||
}
|
||||
@@ -1664,21 +1738,20 @@ static void write_data(switch_stream_handle_t *stream, switch_bool_t as_xml, con
|
||||
|
||||
SWITCH_STANDARD_API(dialplan_lcr_function)
|
||||
{
|
||||
char *argv[9] = { 0 };
|
||||
char *argv[32] = { 0 };
|
||||
int argc;
|
||||
char *mydata = NULL;
|
||||
//char *dialstring = NULL;
|
||||
char *lcr_profile = NULL;
|
||||
lcr_route current = NULL;
|
||||
max_obj_t maximum_lengths = { 0 };
|
||||
callback_t cb_struct = { 0 };
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
char *mydata = NULL;
|
||||
char *lcr_profile = NULL;
|
||||
lcr_route current = NULL;
|
||||
max_obj_t maximum_lengths = { 0 };
|
||||
callback_t cb_struct = { 0 };
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
switch_event_t *event;
|
||||
switch_status_t lookup_status = SWITCH_STATUS_SUCCESS;
|
||||
switch_bool_t as_xml = SWITCH_FALSE;
|
||||
char *event_str = NULL;
|
||||
switch_xml_t event_xml = NULL;
|
||||
int rowcount=0;
|
||||
switch_bool_t as_xml = SWITCH_FALSE;
|
||||
char *event_str = NULL;
|
||||
switch_xml_t event_xml = NULL;
|
||||
int rowcount = 0;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
goto usage;
|
||||
@@ -1708,10 +1781,18 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
|
||||
}
|
||||
if (argc > 2) {
|
||||
int i;
|
||||
for (i=2; i<argc; i++) {
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (!strcasecmp(argv[i], "intrastate")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on intrastate rates\n");
|
||||
cb_struct.intrastate = SWITCH_TRUE;
|
||||
} else if (!strcasecmp(argv[i], "lrn")) {
|
||||
i++;
|
||||
if (argv[i]) {
|
||||
cb_struct.lrn_number = argv[i];
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "LRN number [%s]\n", cb_struct.lrn_number);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "you must pass a LRN number to use lrn\n");
|
||||
}
|
||||
} else if (!strcasecmp(argv[i], "as")) {
|
||||
i++;
|
||||
if (argv[i] && !strcasecmp(argv[i], "xml")) {
|
||||
@@ -1868,7 +1949,7 @@ usage:
|
||||
|
||||
SWITCH_STANDARD_API(dialplan_lcr_admin_function)
|
||||
{
|
||||
char *argv[4] = { 0 };
|
||||
char *argv[32] = { 0 };
|
||||
int argc;
|
||||
char *mydata = NULL;
|
||||
switch_hash_index_t *hi;
|
||||
|
||||
@@ -23,21 +23,22 @@ DROP TABLE IF EXISTS `lcr`;
|
||||
CREATE TABLE `lcr` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`digits` varchar(15) default NULL,
|
||||
`rate` float(11,5) unsigned NOT NULL,
|
||||
`intrastate_rate` float(11, 5) unsigned NOT NULL,
|
||||
`intralata_rate` float(11, 5) unsigned NOT NULL,
|
||||
`rate` float(11,5) unsigned,
|
||||
`intrastate_rate` float(11, 5) unsigned,
|
||||
`intralata_rate` float(11, 5) unsigned,
|
||||
`carrier_id` int(11) NOT NULL,
|
||||
`lead_strip` int(11) NOT NULL,
|
||||
`trail_strip` int(11) NOT NULL,
|
||||
`prefix` varchar(16) NOT NULL,
|
||||
`suffix` varchar(16) NOT NULL,
|
||||
`lcr_profile` varchar(32) default NULL,
|
||||
`lcr_profile` int(11) NOT NULL default 0,
|
||||
`date_start` datetime NOT NULL DEFAULT '1970-01-01',
|
||||
`date_end` datetime NOT NULL DEFAULT '2030-12-31',
|
||||
`quality` float(10,6) NOT NULL,
|
||||
`reliability` float(10,6) NOT NULL,
|
||||
`cid` varchar(32) NOT NULL DEFAULT '',
|
||||
`enabled` boolean NOT NULL DEFAULT '1',
|
||||
`lrn` boolean NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `carrier_id` (`carrier_id`),
|
||||
KEY `digits` (`digits`),
|
||||
|
||||
@@ -42,9 +42,9 @@ CREATE TABLE lcr
|
||||
(
|
||||
id serial NOT NULL,
|
||||
digits NUMERIC(20, 0),
|
||||
rate numeric(11,5) NOT NULL,
|
||||
intrastate_rate numeric(11,5) NOT NULL,
|
||||
intralata_rate numeric(11,5) NOT NULL,
|
||||
rate numeric(11,5),
|
||||
intrastate_rate numeric(11,5),
|
||||
intralata_rate numeric(11,5),
|
||||
carrier_id integer NOT NULL REFERENCES carriers(id),
|
||||
lead_strip integer NOT NULL DEFAULT 0,
|
||||
trail_strip integer NOT NULL DEFAULT 0,
|
||||
@@ -57,6 +57,7 @@ CREATE TABLE lcr
|
||||
reliability numeric(10,6) NOT NULL DEFAULT 0,
|
||||
cid VARCHAR(32) NOT NULL DEFAULT '',
|
||||
enabled boolean NOT NULL DEFAULT 'true',
|
||||
lrn boolean NOT NULL DEFAULT 'false',
|
||||
CONSTRAINT lcr_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
MEMCACHED=libmemcached-0.32
|
||||
BASE=../../../..
|
||||
|
||||
WANT_CURL=yes
|
||||
|
||||
MEMCACHED_DIR=$(switch_srcdir)/libs/$(MEMCACHED)
|
||||
MEMCACHED_BUILDDIR=$(switch_builddir)/libs/$(MEMCACHED)
|
||||
|
||||
|
||||
@@ -1,33 +1,94 @@
|
||||
#include <switch.h>
|
||||
#include "mod_mongo.h"
|
||||
|
||||
#define DELIMITER ';'
|
||||
#define FIND_ONE_SYNTAX "mongo_find_one ns; query; fields"
|
||||
#define MAPREDUCE_SYNTAX "mongo_mapreduce ns; query"
|
||||
|
||||
static struct {
|
||||
mongo_connection_pool_t *conn_pool;
|
||||
char *map;
|
||||
char *reduce;
|
||||
char *finalize;
|
||||
} globals;
|
||||
|
||||
SWITCH_STANDARD_API(mongo_mapreduce_function)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
DBClientBase *conn = NULL;
|
||||
char *ns = NULL, *json_query = NULL;
|
||||
|
||||
ns = strdup(cmd);
|
||||
switch_assert(ns != NULL);
|
||||
|
||||
if ((json_query = strchr(ns, DELIMITER))) {
|
||||
*json_query++ = '\0';
|
||||
}
|
||||
|
||||
if (!zstr(ns) && !zstr(json_query)) {
|
||||
try {
|
||||
BSONObj query = fromjson(json_query);
|
||||
BSONObj out;
|
||||
BSONObjBuilder cmd;
|
||||
|
||||
cmd.append("mapreduce", conn->nsGetCollection(ns));
|
||||
if (!zstr(globals.map)) {
|
||||
cmd.appendCode("map", globals.map);
|
||||
}
|
||||
if (!zstr(globals.reduce)) {
|
||||
cmd.appendCode("reduce", globals.reduce);
|
||||
}
|
||||
if (!zstr(globals.finalize)) {
|
||||
cmd.appendCode("finalize", globals.finalize);
|
||||
}
|
||||
if(!query.isEmpty()) {
|
||||
cmd.append("query", query);
|
||||
}
|
||||
cmd.append("out", BSON("inline" << 1));
|
||||
|
||||
conn = mongo_connection_pool_get(globals.conn_pool);
|
||||
if (conn) {
|
||||
conn->runCommand(conn->nsGetDB(ns), cmd.done(), out);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
|
||||
|
||||
stream->write_function(stream, "-OK\n%s\n", out.toString().c_str());
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\nNo connection\n");
|
||||
}
|
||||
} catch (DBException &e) {
|
||||
if (conn) {
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_TRUE);
|
||||
}
|
||||
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\n%s\n", MAPREDUCE_SYNTAX);
|
||||
}
|
||||
|
||||
switch_safe_free(ns);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static const char *SYNTAX = "mongo_find_one ns; query; fields";
|
||||
|
||||
SWITCH_STANDARD_API(mongo_find_one_function)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
char *ns = NULL, *json_query = NULL, *json_fields = NULL;
|
||||
char delim = ';';
|
||||
|
||||
ns = strdup(cmd);
|
||||
switch_assert(ns != NULL);
|
||||
|
||||
if ((json_query = strchr(ns, delim))) {
|
||||
if ((json_query = strchr(ns, DELIMITER))) {
|
||||
*json_query++ = '\0';
|
||||
if ((json_fields = strchr(json_query, delim))) {
|
||||
if ((json_fields = strchr(json_query, DELIMITER))) {
|
||||
*json_fields++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(ns) && !zstr(json_query) && !zstr(json_fields)) {
|
||||
|
||||
DBClientConnection *conn = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
|
||||
try {
|
||||
BSONObj query = fromjson(json_query);
|
||||
@@ -36,7 +97,7 @@ SWITCH_STANDARD_API(mongo_find_one_function)
|
||||
conn = mongo_connection_pool_get(globals.conn_pool);
|
||||
if (conn) {
|
||||
BSONObj res = conn->findOne(ns, Query(query), &fields);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
|
||||
|
||||
stream->write_function(stream, "-OK\n%s\n", res.toString().c_str());
|
||||
} else {
|
||||
@@ -44,14 +105,13 @@ SWITCH_STANDARD_API(mongo_find_one_function)
|
||||
}
|
||||
} catch (DBException &e) {
|
||||
if (conn) {
|
||||
mongo_connection_destroy(&conn);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_TRUE);
|
||||
}
|
||||
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\n%s\n", SYNTAX);
|
||||
stream->write_function(stream, "-ERR\n%s\n", FIND_ONE_SYNTAX);
|
||||
}
|
||||
|
||||
switch_safe_free(ns);
|
||||
@@ -64,7 +124,7 @@ static switch_status_t config(void)
|
||||
const char *cf = "mongo.conf";
|
||||
switch_xml_t cfg, xml, settings, param;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
const char *host = "127.0.0.1";
|
||||
const char *conn_str = "127.0.0.1";
|
||||
switch_size_t min_connections = 1, max_connections = 1;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
|
||||
@@ -79,7 +139,10 @@ static switch_status_t config(void)
|
||||
int tmp;
|
||||
|
||||
if (!strcmp(var, "host")) {
|
||||
host = val;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "'host' is deprecated. use 'connection-string'\n");
|
||||
conn_str = val;
|
||||
} else if (!strcmp(var, "connection-string")) {
|
||||
conn_str = val;
|
||||
} else if (!strcmp(var, "min-connections")) {
|
||||
if ((tmp = atoi(val)) > 0) {
|
||||
min_connections = tmp;
|
||||
@@ -88,15 +151,21 @@ static switch_status_t config(void)
|
||||
if ((tmp = atoi(val)) > 0) {
|
||||
max_connections = tmp;
|
||||
}
|
||||
} else if (!strcmp(var, "map")) {
|
||||
globals.map = strdup(val);
|
||||
} else if (!strcmp(var, "reduce")) {
|
||||
globals.reduce = strdup(val);
|
||||
} else if (!strcmp(var, "finalize")) {
|
||||
globals.finalize = strdup(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mongo_connection_pool_create(&globals.conn_pool, min_connections, max_connections, host) != SWITCH_STATUS_SUCCESS) {
|
||||
if (mongo_connection_pool_create(&globals.conn_pool, min_connections, max_connections, conn_str) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Can't create connection pool\n");
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mongo connection pool created [%s %d/%d]\n", host, (int)min_connections, (int)max_connections);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Mongo connection pool created [%s %d/%d]\n", conn_str, (int)min_connections, (int)max_connections);
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
@@ -125,7 +194,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load)
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
SWITCH_ADD_API(api_interface, "mongo_find_one", "mongo", mongo_find_one_function, SYNTAX);
|
||||
SWITCH_ADD_API(api_interface, "mongo_find_one", "findOne", mongo_find_one_function, FIND_ONE_SYNTAX);
|
||||
SWITCH_ADD_API(api_interface, "mongo_mapreduce", "Map/Reduce", mongo_mapreduce_function, MAPREDUCE_SYNTAX);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -133,6 +203,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load)
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mongo_shutdown)
|
||||
{
|
||||
mongo_connection_pool_destroy(&globals.conn_pool);
|
||||
switch_safe_free(globals.map);
|
||||
switch_safe_free(globals.reduce);
|
||||
switch_safe_free(globals.finalize);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef MOD_MONGO_H
|
||||
#define MOD_MONGO_H
|
||||
|
||||
|
||||
#include <client/dbclient.h>
|
||||
#include <client/connpool.h>
|
||||
#include <db/json.h>
|
||||
@@ -10,7 +9,7 @@
|
||||
using namespace mongo;
|
||||
|
||||
typedef struct {
|
||||
char *host;
|
||||
char *conn_str;
|
||||
|
||||
switch_size_t min_connections;
|
||||
switch_size_t max_connections;
|
||||
@@ -22,16 +21,16 @@ typedef struct {
|
||||
} mongo_connection_pool_t;
|
||||
|
||||
|
||||
switch_status_t mongo_connection_create(DBClientConnection **connection, const char *host);
|
||||
void mongo_connection_destroy(DBClientConnection **conn);
|
||||
switch_status_t mongo_connection_create(DBClientBase **connection, const char *conn_str);
|
||||
void mongo_connection_destroy(DBClientBase **conn);
|
||||
|
||||
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
|
||||
const char *host);
|
||||
const char *conn_str);
|
||||
void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool);
|
||||
|
||||
|
||||
DBClientConnection *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool);
|
||||
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientConnection *conn);
|
||||
DBClientBase *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool);
|
||||
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientBase *conn, switch_bool_t destroy);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,24 +10,35 @@
|
||||
scoped_conn.done();
|
||||
*/
|
||||
|
||||
switch_status_t mongo_connection_create(DBClientConnection **connection, const char *host)
|
||||
switch_status_t mongo_connection_create(DBClientBase **connection, const char *conn_str)
|
||||
{
|
||||
DBClientConnection *conn = new DBClientConnection();
|
||||
|
||||
try {
|
||||
conn->connect(host);
|
||||
} catch (DBException &e) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't connect to mongo [%s]\n", host);
|
||||
return SWITCH_STATUS_GENERR;
|
||||
DBClientBase *conn = NULL;
|
||||
string conn_string(conn_str), err_msg;
|
||||
ConnectionString cs = ConnectionString::parse(conn_string, err_msg);
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!cs.isValid()) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't parse url: %s\n", err_msg.c_str());
|
||||
return status;
|
||||
}
|
||||
|
||||
*connection = conn;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", host);
|
||||
try {
|
||||
conn = cs.connect(err_msg);
|
||||
} catch (DBException &e) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't connect to mongo [%s]: %s\n", conn_str, err_msg.c_str());
|
||||
return status;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
if (conn) {
|
||||
*connection = conn;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", conn_str);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void mongo_connection_destroy(DBClientConnection **conn)
|
||||
void mongo_connection_destroy(DBClientBase **conn)
|
||||
{
|
||||
switch_assert(*conn != NULL);
|
||||
delete *conn;
|
||||
@@ -36,12 +47,12 @@ void mongo_connection_destroy(DBClientConnection **conn)
|
||||
}
|
||||
|
||||
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
|
||||
const char *host)
|
||||
const char *conn_str)
|
||||
{
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
mongo_connection_pool_t *cpool = NULL;
|
||||
DBClientConnection *conn = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
|
||||
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
@@ -61,14 +72,14 @@ switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool
|
||||
|
||||
cpool->min_connections = min_connections;
|
||||
cpool->max_connections = max_connections;
|
||||
cpool->host = switch_core_strdup(pool, host);
|
||||
cpool->conn_str = switch_core_strdup(pool, conn_str);
|
||||
|
||||
cpool->pool = pool;
|
||||
|
||||
for (cpool->size = 0; cpool->size < min_connections; cpool->size++) {
|
||||
|
||||
if (mongo_connection_create(&conn, host) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_pool_put(cpool, conn);
|
||||
if (mongo_connection_create(&conn, conn_str) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_pool_put(cpool, conn, SWITCH_FALSE);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -82,7 +93,6 @@ switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -94,7 +104,7 @@ void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool)
|
||||
switch_assert(cpool != NULL);
|
||||
|
||||
while (switch_queue_trypop(cpool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_destroy((DBClientConnection **)&data);
|
||||
mongo_connection_destroy((DBClientBase **)&data);
|
||||
}
|
||||
|
||||
switch_mutex_destroy(cpool->mutex);
|
||||
@@ -104,9 +114,9 @@ void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool)
|
||||
}
|
||||
|
||||
|
||||
DBClientConnection *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool)
|
||||
DBClientBase *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool)
|
||||
{
|
||||
DBClientConnection *conn = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
void *data = NULL;
|
||||
|
||||
switch_assert(conn_pool != NULL);
|
||||
@@ -114,8 +124,8 @@ DBClientConnection *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
|
||||
if (switch_queue_trypop(conn_pool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
conn = (DBClientConnection *) data;
|
||||
} else if (mongo_connection_create(&conn, conn_pool->host) == SWITCH_STATUS_SUCCESS) {
|
||||
conn = (DBClientBase *) data;
|
||||
} else if (mongo_connection_create(&conn, conn_pool->conn_str) == SWITCH_STATUS_SUCCESS) {
|
||||
if (++conn_pool->size > conn_pool->max_connections) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Connection pool is empty. You may want to increase 'max-connections'\n");
|
||||
}
|
||||
@@ -130,7 +140,7 @@ DBClientConnection *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool
|
||||
return conn;
|
||||
}
|
||||
|
||||
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientConnection *conn)
|
||||
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientBase *conn, switch_bool_t destroy)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
@@ -138,7 +148,7 @@ switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DB
|
||||
switch_assert(conn != NULL);
|
||||
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
if (conn_pool->size > conn_pool->max_connections) {
|
||||
if (destroy || conn_pool->size > conn_pool->max_connections) {
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: Destroy connection %p\n", conn);
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,135 +0,0 @@
|
||||
/* Copy paste from FS mod_voicemail */
|
||||
#include <switch.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
const char *global_cf = "protovm.conf";
|
||||
|
||||
void populate_profile_menu_event(vmivr_profile_t *profile, vmivr_menu_profile_t *menu) {
|
||||
switch_xml_t cfg, xml, x_profiles, x_profile, x_keys, x_phrases, x_menus, x_menu;
|
||||
|
||||
free_profile_menu_event(menu);
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
goto end;
|
||||
}
|
||||
if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile->name))) {
|
||||
if ((x_menus = switch_xml_child(x_profile, "menus"))) {
|
||||
if ((x_menu = switch_xml_find_child(x_menus, "menu", "name", menu->name))) {
|
||||
if ((x_keys = switch_xml_child(x_menu, "keys"))) {
|
||||
switch_event_import_xml(switch_xml_child(x_keys, "key"), "dtmf", "action", &menu->event_keys_dtmf);
|
||||
switch_event_import_xml(switch_xml_child(x_keys, "key"), "action", "dtmf", &menu->event_keys_action);
|
||||
switch_event_import_xml(switch_xml_child(x_keys, "key"), "action", "variable", &menu->event_keys_varname);
|
||||
}
|
||||
if ((x_phrases = switch_xml_child(x_menu, "phrases"))) {
|
||||
switch_event_import_xml(switch_xml_child(x_phrases, "phrase"), "name", "value", &menu->event_phrases);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (xml)
|
||||
switch_xml_free(xml);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void free_profile_menu_event(vmivr_menu_profile_t *menu) {
|
||||
if (menu->event_keys_dtmf) {
|
||||
switch_event_destroy(&menu->event_keys_dtmf);
|
||||
}
|
||||
if (menu->event_keys_action) {
|
||||
switch_event_destroy(&menu->event_keys_action);
|
||||
}
|
||||
if (menu->event_keys_varname) {
|
||||
switch_event_destroy(&menu->event_keys_varname);
|
||||
}
|
||||
|
||||
if (menu->event_phrases) {
|
||||
switch_event_destroy(&menu->event_phrases);
|
||||
}
|
||||
}
|
||||
|
||||
vmivr_profile_t *get_profile(switch_core_session_t *session, const char *profile_name)
|
||||
{
|
||||
vmivr_profile_t *profile = NULL;
|
||||
switch_xml_t cfg, xml, x_profiles, x_profile, x_apis, param;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
|
||||
return profile;
|
||||
}
|
||||
if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile_name))) {
|
||||
if (!(profile = switch_core_session_alloc(session, sizeof(vmivr_profile_t)))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
profile->name = profile_name;
|
||||
|
||||
profile->current_msg = 0;
|
||||
profile->current_msg_uuid = NULL;
|
||||
|
||||
/* TODO Make the following configurable */
|
||||
profile->api_profile = profile->name;
|
||||
profile->menu_check_auth = "std_authenticate";
|
||||
profile->menu_check_main = "std_navigator";
|
||||
profile->menu_check_terminate = "std_purge";
|
||||
|
||||
if ((x_apis = switch_xml_child(x_profile, "apis"))) {
|
||||
int total_options = 0;
|
||||
int total_invalid_options = 0;
|
||||
for (param = switch_xml_child(x_apis, "api"); param; param = param->next) {
|
||||
char *var, *val;
|
||||
if ((var = (char *) switch_xml_attr_soft(param, "name")) && (val = (char *) switch_xml_attr_soft(param, "value"))) {
|
||||
if (!strcasecmp(var, "msg_undelete") && !profile->api_msg_undelete)
|
||||
profile->api_msg_undelete = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_delete") && !profile->api_msg_delete)
|
||||
profile->api_msg_delete = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_list") && !profile->api_msg_list)
|
||||
profile->api_msg_list = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_count") && !profile->api_msg_count)
|
||||
profile->api_msg_count = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_save") && !profile->api_msg_save)
|
||||
profile->api_msg_save = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_purge") && !profile->api_msg_purge)
|
||||
profile->api_msg_purge = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_get") && !profile->api_msg_get)
|
||||
profile->api_msg_get = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "msg_forward") && !profile->api_msg_forward)
|
||||
profile->api_msg_forward = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "pref_greeting_set") && !profile->api_pref_greeting_set)
|
||||
profile->api_pref_greeting_set = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "pref_recname_set") && !profile->api_pref_recname_set)
|
||||
profile->api_pref_recname_set = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "pref_password_set") && !profile->api_pref_password_set)
|
||||
profile->api_pref_password_set = switch_core_session_strdup(session, val);
|
||||
else if (!strcasecmp(var, "auth_login") && !profile->api_auth_login)
|
||||
profile->api_auth_login = switch_core_session_strdup(session, val);
|
||||
else
|
||||
total_invalid_options++;
|
||||
total_options++;
|
||||
}
|
||||
}
|
||||
if (total_options - total_invalid_options != 12) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing api definition for profile '%s'\n", profile_name);
|
||||
profile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
switch_xml_free(xml);
|
||||
return profile;
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
extern const char *global_cf;
|
||||
|
||||
struct vmivr_profile {
|
||||
const char *name;
|
||||
|
||||
const char *domain;
|
||||
const char *id;
|
||||
|
||||
int current_msg;
|
||||
const char *current_msg_uuid;
|
||||
|
||||
const char *menu_check_auth;
|
||||
const char *menu_check_main;
|
||||
const char *menu_check_terminate;
|
||||
|
||||
switch_bool_t authorized;
|
||||
|
||||
const char *api_profile;
|
||||
const char *api_auth_login;
|
||||
const char *api_msg_delete;
|
||||
const char *api_msg_undelete;
|
||||
const char *api_msg_list;
|
||||
const char *api_msg_count;
|
||||
const char *api_msg_save;
|
||||
const char *api_msg_purge;
|
||||
const char *api_msg_get;
|
||||
const char *api_msg_forward;
|
||||
const char *api_pref_greeting_set;
|
||||
const char *api_pref_recname_set;
|
||||
const char *api_pref_password_set;
|
||||
|
||||
};
|
||||
typedef struct vmivr_profile vmivr_profile_t;
|
||||
|
||||
struct vmivr_menu_profile {
|
||||
const char *name;
|
||||
|
||||
switch_event_t *event_keys_action;
|
||||
switch_event_t *event_keys_dtmf;
|
||||
switch_event_t *event_keys_varname;
|
||||
switch_event_t *event_phrases;
|
||||
};
|
||||
typedef struct vmivr_menu_profile vmivr_menu_profile_t;
|
||||
|
||||
vmivr_profile_t *get_profile(switch_core_session_t *session, const char *profile_name);
|
||||
|
||||
void free_profile_menu_event(vmivr_menu_profile_t *menu);
|
||||
void populate_profile_menu_event(vmivr_profile_t *profile, vmivr_menu_profile_t *menu);
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
||||
@@ -1,250 +0,0 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* ivr.c -- MT IVR System Interface
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "ivr.h"
|
||||
|
||||
int match_dtmf(switch_core_session_t *session, dtmf_ss_t *loc) {
|
||||
switch_bool_t is_invalid[128] = { SWITCH_FALSE };
|
||||
int i;
|
||||
loc->potentialMatch = NULL;
|
||||
loc->completeMatch = NULL;
|
||||
loc->potentialMatchCount = 0;
|
||||
|
||||
for (i = 0; i < loc->dtmf_received; i++) {
|
||||
int j;
|
||||
loc->potentialMatchCount = 0;
|
||||
for (j = 0; !zstr(loc->dtmf_accepted[j]) && j < 128; j++) {
|
||||
switch_bool_t cMatch = SWITCH_FALSE;
|
||||
char test[2] = { 0 };
|
||||
|
||||
if (is_invalid[j])
|
||||
continue;
|
||||
|
||||
test[0] = loc->dtmf_stored[i];
|
||||
if (loc->dtmf_accepted[j][i] == 'N' && atoi(test) >= 2 && atoi(test) <= 9)
|
||||
cMatch = SWITCH_TRUE;
|
||||
if (loc->dtmf_accepted[j][i] == 'X' && atoi(test) >= 0 && atoi(test) <= 9) {
|
||||
cMatch = SWITCH_TRUE;
|
||||
}
|
||||
if (i >= strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.')
|
||||
cMatch = SWITCH_TRUE;
|
||||
if (loc->dtmf_accepted[j][i] == loc->dtmf_stored[i])
|
||||
cMatch = SWITCH_TRUE;
|
||||
|
||||
if (cMatch == SWITCH_FALSE) {
|
||||
is_invalid[j] = SWITCH_TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.') {
|
||||
loc->completeMatch = loc->dtmf_accepted[j];
|
||||
}
|
||||
if (i == loc->dtmf_received - 1 && loc->dtmf_received == strlen(loc->dtmf_accepted[j]) && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] != '.') {
|
||||
loc->completeMatch = loc->dtmf_accepted[j];
|
||||
continue;
|
||||
}
|
||||
loc->potentialMatchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static switch_status_t cb_on_dtmf_ignore(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
|
||||
{
|
||||
switch (itype) {
|
||||
case SWITCH_INPUT_TYPE_DTMF:
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
|
||||
switch_channel_queue_dtmf(channel, dtmf);
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t cb_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
|
||||
{
|
||||
dtmf_ss_t *loc = (dtmf_ss_t*) buf;
|
||||
|
||||
switch (itype) {
|
||||
case SWITCH_INPUT_TYPE_DTMF:
|
||||
{
|
||||
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
|
||||
switch_bool_t audio_was_stopped = loc->audio_stopped;
|
||||
loc->audio_stopped = SWITCH_TRUE;
|
||||
|
||||
if (loc->dtmf_received >= sizeof(loc->dtmf_stored)) {
|
||||
loc->result = RES_BUFFER_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
if (!loc->terminate_key || dtmf->digit != loc->terminate_key)
|
||||
loc->dtmf_stored[loc->dtmf_received++] = dtmf->digit;
|
||||
|
||||
match_dtmf(session, loc);
|
||||
|
||||
if (loc->terminate_key && dtmf->digit == loc->terminate_key && loc->result == RES_WAITFORMORE) {
|
||||
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
|
||||
loc->result = RES_FOUND;
|
||||
} else {
|
||||
loc->result = RES_INVALID;
|
||||
}
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else {
|
||||
if (loc->potentialMatchCount == 0 && loc->completeMatch != NULL) {
|
||||
loc->result = RES_FOUND;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else if (loc->potentialMatchCount > 0) {
|
||||
loc->result = RES_WAITFORMORE;
|
||||
if (!audio_was_stopped)
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else {
|
||||
loc->result = RES_INVALID;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t captureMenuInitialize(dtmf_ss_t *loc, char **dtmf_accepted) {
|
||||
int i;
|
||||
|
||||
memset(loc, 0, sizeof(*loc));
|
||||
|
||||
for (i = 0; dtmf_accepted[i] && i < 16; i++) {
|
||||
strncpy(loc->dtmf_accepted[i], dtmf_accepted[i], 128);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t playbackBufferDTMF(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
args.input_callback = cb_on_dtmf_ignore;
|
||||
|
||||
if (macro_name) {
|
||||
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
switch_status_t captureMenu(switch_core_session_t *session, dtmf_ss_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
args.input_callback = cb_on_dtmf;
|
||||
args.buf = loc;
|
||||
|
||||
if (macro_name && loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
|
||||
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
|
||||
}
|
||||
|
||||
if (switch_channel_ready(channel) && (status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK) && timeout && loc->result == RES_WAITFORMORE) {
|
||||
loc->audio_stopped = SWITCH_TRUE;
|
||||
switch_ivr_collect_digits_callback(session, &args, timeout, 0);
|
||||
if (loc->result == RES_WAITFORMORE) {
|
||||
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
|
||||
loc->result = RES_FOUND;
|
||||
} else {
|
||||
loc->result = RES_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_status_t captureMenuRecord(switch_core_session_t *session, dtmf_ss_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
args.input_callback = cb_on_dtmf;
|
||||
args.buf = loc;
|
||||
|
||||
if (loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
|
||||
loc->recorded_audio = SWITCH_TRUE;
|
||||
switch_ivr_gentones(session, "%(1000, 0, 640)", 0, NULL); /* TODO Make this optional and configurable */
|
||||
status = switch_ivr_record_file(session, fh, file_path, &args, max_record_len);
|
||||
|
||||
}
|
||||
if (loc->result == RES_WAITFORMORE) {
|
||||
loc->result = RES_TIMEOUT;
|
||||
}
|
||||
|
||||
} else {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -1,30 +0,0 @@
|
||||
struct dtmf_ss {
|
||||
char dtmf_stored[128];
|
||||
int dtmf_received;
|
||||
char dtmf_accepted[16][128];
|
||||
int result;
|
||||
switch_bool_t audio_stopped;
|
||||
switch_bool_t recorded_audio;
|
||||
const char *potentialMatch;
|
||||
int potentialMatchCount;
|
||||
const char *completeMatch;
|
||||
char terminate_key;
|
||||
};
|
||||
typedef struct dtmf_ss dtmf_ss_t;
|
||||
|
||||
#define RES_WAITFORMORE 0
|
||||
#define RES_FOUND 1
|
||||
#define RES_INVALID 3
|
||||
#define RES_TIMEOUT 4
|
||||
#define RES_BREAK 5
|
||||
#define RES_RECORD 6
|
||||
#define RES_BUFFER_OVERFLOW 99
|
||||
|
||||
#define MAX_DTMF_SIZE_OPTION 32
|
||||
|
||||
switch_status_t captureMenu(switch_core_session_t *session, dtmf_ss_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout);
|
||||
switch_status_t captureMenuRecord(switch_core_session_t *session, dtmf_ss_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len);
|
||||
switch_status_t captureMenuInitialize(dtmf_ss_t *loc, char **dtmf_accepted);
|
||||
|
||||
switch_status_t playbackBufferDTMF(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout);
|
||||
|
||||
@@ -1,743 +0,0 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* menu.c -- VoiceMail Menu
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "ivr.h"
|
||||
#include "menu.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
/* List of available menu */
|
||||
vmivr_menu_function_t menu_list[] = {
|
||||
{"std_authenticate", mtvm_menu_authenticate},
|
||||
{"std_navigator", mtvm_menu_main},
|
||||
{"std_record_name", mtvm_menu_record_name},
|
||||
{"std_set_password", mtvm_menu_set_password},
|
||||
{"std_select_greeting_slot", mtvm_menu_select_greeting_slot},
|
||||
{"std_record_greeting_with_slot", mtvm_menu_record_greeting_with_slot},
|
||||
{"std_preference", mtvm_menu_preference},
|
||||
{"std_purge", mtvm_menu_purge},
|
||||
{"std_forward", mtvm_menu_forward},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
#define MAX_ATTEMPT 3 /* TODO Make these fields configurable */
|
||||
#define DEFAULT_IVR_TIMEOUT 3000
|
||||
|
||||
void mtvm_menu_purge(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
if (profile->id && profile->authorized) {
|
||||
if (1==1 /* TODO make Purge email on exit optional ??? */) {
|
||||
const char *cmd = switch_core_session_sprintf(session, "%s %s %s", profile->api_profile, profile->domain, profile->id);
|
||||
mt_api_execute(session, profile->api_msg_purge, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
void mtvm_menu_main(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_event_t *msg_list_params = NULL;
|
||||
size_t msg_count = 0;
|
||||
size_t current_msg = 1;
|
||||
size_t next_msg = current_msg;
|
||||
size_t previous_msg = current_msg;
|
||||
char *cmd = NULL;
|
||||
int retry;
|
||||
|
||||
/* Different switch to control playback of phrases */
|
||||
switch_bool_t initial_count_played = SWITCH_FALSE;
|
||||
switch_bool_t skip_header = SWITCH_FALSE;
|
||||
switch_bool_t msg_deleted = SWITCH_FALSE;
|
||||
switch_bool_t msg_undeleted = SWITCH_FALSE;
|
||||
switch_bool_t msg_saved = SWITCH_FALSE;
|
||||
|
||||
vmivr_menu_profile_t menu = { "std_navigator" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get VoiceMail List And update msg count */
|
||||
cmd = switch_core_session_sprintf(session, "json %s %s %s", profile->api_profile, profile->domain, profile->id);
|
||||
msg_list_params = jsonapi2event(session, NULL, profile->api_msg_list, cmd);
|
||||
msg_count = atol(switch_event_get_header(msg_list_params,"VM-List-Count"));
|
||||
|
||||
/* TODO Add Detection of new message and notify the user */
|
||||
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
char cid_buf[1024] = "";
|
||||
dtmf_ss_t loc;
|
||||
char *dtmfa[16] = { 0 };
|
||||
switch_event_t *phrase_params = NULL;
|
||||
|
||||
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
|
||||
append_event_profile(phrase_params, profile, menu);
|
||||
|
||||
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
|
||||
|
||||
previous_msg = current_msg;
|
||||
|
||||
/* Simple Protection to not go out of msg list scope */
|
||||
/* TODO: Add Prompt to notify they reached the begining or the end */
|
||||
if (next_msg == 0) {
|
||||
next_msg = 1;
|
||||
} else if (next_msg > msg_count) {
|
||||
next_msg = msg_count;
|
||||
}
|
||||
|
||||
current_msg = next_msg;
|
||||
|
||||
captureMenuInitialize(&loc, dtmfa);
|
||||
|
||||
/* Prompt related to previous Message here */
|
||||
append_event_message(session, profile, phrase_params, msg_list_params, previous_msg);
|
||||
if (msg_deleted) {
|
||||
msg_deleted = SWITCH_FALSE;
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "ack"), "deleted", phrase_params, NULL, 0);
|
||||
}
|
||||
if (msg_undeleted) {
|
||||
msg_undeleted = SWITCH_FALSE;
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "ack"), "undeleted", phrase_params, NULL, 0);
|
||||
}
|
||||
if (msg_saved) {
|
||||
msg_saved = SWITCH_FALSE;
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "ack"), "saved", phrase_params, NULL, 0);
|
||||
}
|
||||
|
||||
/* Prompt related the current message */
|
||||
append_event_message(session, profile, phrase_params, msg_list_params, current_msg);
|
||||
|
||||
/* Save in profile the current msg info for other menu processing AND restoration of our current position */
|
||||
switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", switch_str_nil(switch_event_get_header(phrase_params, "VM-Message-Caller-Number")), switch_str_nil(switch_event_get_header(phrase_params, "VM-Message-Caller-Name")));
|
||||
|
||||
/* Display MSG CID/Name to caller */
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = cid_buf;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
profile->current_msg = current_msg;
|
||||
profile->current_msg_uuid = switch_core_session_strdup(session, switch_event_get_header(phrase_params, "VM-Message-UUID"));
|
||||
|
||||
/* TODO check if msg is gone (purged by another session, notify user and auto jump to next message or something) */
|
||||
if (!skip_header) {
|
||||
if (!initial_count_played) {
|
||||
cmd = switch_core_session_sprintf(session, "json %s %s %s", profile->api_profile, profile->domain, profile->id);
|
||||
jsonapi2event(session, phrase_params, profile->api_msg_count, cmd);
|
||||
initial_count_played = SWITCH_TRUE;
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "msg_count"), NULL, phrase_params, NULL, 0);
|
||||
}
|
||||
if (msg_count > 0) {
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "say_msg_number"), NULL, phrase_params, NULL, 0);
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "say_date"), NULL, phrase_params, NULL, 0);
|
||||
}
|
||||
}
|
||||
if (msg_count > 0) {
|
||||
/* TODO Update the Read date of a message (When msg start, or when it listen compleatly ??? To be determined */
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "play_message"), NULL, phrase_params, NULL, 0);
|
||||
}
|
||||
skip_header = SWITCH_FALSE;
|
||||
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
|
||||
|
||||
if (loc.result == RES_TIMEOUT) {
|
||||
/* TODO Ask for the prompt Again IF retry != 0 */
|
||||
} else if (loc.result == RES_INVALID) {
|
||||
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
|
||||
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = MAX_ATTEMPT;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "skip_intro")) { /* Skip Header / Play the recording again */
|
||||
skip_header = SWITCH_TRUE;
|
||||
} else if (!strcasecmp(action, "next_msg")) { /* Next Message */
|
||||
next_msg++;
|
||||
} else if (!strcasecmp(action, "prev_msg")) { /* Previous Message */
|
||||
next_msg--;
|
||||
} else if (!strcasecmp(action, "delete_msg")) { /* Delete / Undelete Message */
|
||||
const char *msg_flags = switch_event_get_header(phrase_params, "VM-Message-Flags");
|
||||
if (!msg_flags || strncasecmp(msg_flags, "delete", 6)) {
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(phrase_params, "VM-Message-UUID"));
|
||||
mt_api_execute(session, profile->api_msg_delete, cmd);
|
||||
|
||||
msg_deleted = SWITCH_TRUE;
|
||||
/* TODO Option for auto going to next message or just return to the menu (So user used to do 76 to delete and next message wont be confused) */
|
||||
next_msg++;
|
||||
} else {
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(phrase_params, "VM-Message-UUID"));
|
||||
mt_api_execute(session, profile->api_msg_undelete, cmd);
|
||||
|
||||
msg_undeleted = SWITCH_TRUE;
|
||||
}
|
||||
} else if (!strcasecmp(action, "save_msg")) { /* Save Message */
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(phrase_params, "VM-Message-UUID"));
|
||||
mt_api_execute(session, profile->api_msg_save, cmd);
|
||||
|
||||
msg_saved = SWITCH_TRUE;
|
||||
} else if (!strcasecmp(action, "callback")) { /* CallBack caller */
|
||||
const char *cid_num = switch_event_get_header(phrase_params, "VM-Message-Caller-Number");
|
||||
if (cid_num) {
|
||||
/* TODO add detection for private number */
|
||||
switch_core_session_execute_exten(session, cid_num, "XML", profile->domain);
|
||||
} else {
|
||||
/* TODO Some error msg that the msg doesn't contain a caller number */
|
||||
}
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
} else if (!strcasecmp(action, "return")) { /* Return */
|
||||
retry = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* IF the API to get the message returned us a COPY of the file locally (temp file create from a DB or from a web server), delete it */
|
||||
if (switch_true(switch_event_get_header(phrase_params, "VM-Message-Private-Local-Copy"))) {
|
||||
const char *file_path = switch_event_get_header(phrase_params, "VM-Message-File-Path");
|
||||
if (file_path && unlink(file_path) != 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete temp file [%s]\n", file_path);
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrase_params);
|
||||
}
|
||||
|
||||
switch_event_destroy(&msg_list_params);
|
||||
|
||||
free_profile_menu_event(&menu);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void mtvm_menu_forward(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
|
||||
vmivr_menu_profile_t menu = { "std_forward_ask_prepend" };
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
const char *prepend_filepath = NULL;
|
||||
int retry;
|
||||
switch_bool_t forward_msg = SWITCH_FALSE;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
dtmf_ss_t loc;
|
||||
char *dtmfa[16] = { 0 };
|
||||
switch_event_t *phrase_params = NULL;
|
||||
|
||||
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
append_event_profile(phrase_params, profile, menu);
|
||||
|
||||
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
|
||||
|
||||
captureMenuInitialize(&loc, dtmfa);
|
||||
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
|
||||
|
||||
if (loc.result == RES_TIMEOUT) {
|
||||
/* TODO Ask for the prompt Again IF retry != 0 */
|
||||
} else if (loc.result == RES_INVALID) {
|
||||
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
|
||||
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = MAX_ATTEMPT;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "return")) { /* Return to the previous menu */
|
||||
retry = -1;
|
||||
forward_msg = SWITCH_FALSE;
|
||||
} else if (!strcasecmp(action, "prepend")) { /* Prepend record msg */
|
||||
vmivr_menu_profile_t sub_menu = { "std_record_message" };
|
||||
char *tmp_filepath = generate_random_file_name(session, "protovm", "wav" /* TODO make it configurable */);
|
||||
switch_status_t status;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &sub_menu);
|
||||
|
||||
status = mtvm_menu_record(session, profile, sub_menu, tmp_filepath);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
//char *cmd = switch_core_session_sprintf(session, "%s %s %s %d %s", profile->api_profile, profile->domain, profile->id, gnum, tmp_filepath);
|
||||
//char *str_num = switch_core_session_sprintf(session, "%d", gnum);
|
||||
//mt_api_execute(session, profile->api_pref_greeting_set, cmd);
|
||||
//playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
|
||||
prepend_filepath = tmp_filepath;
|
||||
retry = -1;
|
||||
forward_msg = SWITCH_TRUE;
|
||||
} else {
|
||||
/* TODO Error Recording msg */
|
||||
}
|
||||
free_profile_menu_event(&sub_menu);
|
||||
|
||||
} else if (!strcasecmp(action, "forward")) { /* Forward without prepend msg */
|
||||
retry = -1;
|
||||
forward_msg = SWITCH_TRUE;
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrase_params);
|
||||
|
||||
|
||||
}
|
||||
/* Ask Extension to Forward */
|
||||
if (forward_msg) {
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
const char *id = NULL;
|
||||
vmivr_menu_profile_t sub_menu = { "std_forward_ask_extension" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &sub_menu);
|
||||
|
||||
id = mtvm_menu_get_input_set(session, profile, sub_menu, "X.");
|
||||
if (id) {
|
||||
const char *cmd = switch_core_session_sprintf(session, "%s %s %s %s %s %s %s%s%s", profile->api_profile, profile->domain, profile->id, profile->current_msg_uuid, profile->domain, id, prepend_filepath?" ":"", prepend_filepath?prepend_filepath:"" );
|
||||
if (mt_api_execute(session, profile->api_msg_forward, cmd) == SWITCH_STATUS_SUCCESS) {
|
||||
playbackBufferDTMF(session, switch_event_get_header(sub_menu.event_phrases, "ack"), "saved", NULL, NULL, 0);
|
||||
retry = -1;
|
||||
} else {
|
||||
playbackBufferDTMF(session, switch_event_get_header(sub_menu.event_phrases, "invalid_extension"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
/* TODO Prompt about input not valid */
|
||||
}
|
||||
free_profile_menu_event(&sub_menu);
|
||||
/* TODO add Confirmation of the transfered number */
|
||||
}
|
||||
/* TODO Ask if we want to transfer the msg to more person */
|
||||
|
||||
}
|
||||
|
||||
free_profile_menu_event(&menu);
|
||||
}
|
||||
|
||||
|
||||
void mtvm_menu_record_name(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_status_t status;
|
||||
vmivr_menu_profile_t menu = { "std_record_name" };
|
||||
|
||||
char *tmp_filepath = generate_random_file_name(session, "protovm", "wav" /* TODO make it configurable */);
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
status = mtvm_menu_record(session, profile, menu, tmp_filepath);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
char *cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, tmp_filepath);
|
||||
mt_api_execute(session, profile->api_pref_recname_set, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void mtvm_menu_set_password(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
char *password;
|
||||
vmivr_menu_profile_t menu = { "std_set_password" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
password = mtvm_menu_get_input_set(session, profile, menu, "XXX." /* TODO Conf Min 3 Digit */);
|
||||
|
||||
/* TODO Add Prompts to tell if password was set and if it was not */
|
||||
if (password) {
|
||||
char *cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, password);
|
||||
mt_api_execute(session, profile->api_pref_password_set, cmd);
|
||||
|
||||
}
|
||||
|
||||
free_profile_menu_event(&menu);
|
||||
}
|
||||
|
||||
void mtvm_menu_authenticate(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
vmivr_menu_profile_t menu = { "std_authenticate" };
|
||||
int retry;
|
||||
const char *auth_var = NULL;
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
if (profile->id && (auth_var = switch_channel_get_variable(channel, "voicemail_authorized")) && switch_true(auth_var)) {
|
||||
profile->authorized = SWITCH_TRUE;
|
||||
}
|
||||
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0 && profile->authorized == SWITCH_FALSE; retry--) {
|
||||
const char *id = profile->id, *password = NULL;
|
||||
char *cmd = NULL;
|
||||
|
||||
if (!id) {
|
||||
vmivr_menu_profile_t sub_menu = { "std_authenticate_ask_user" };
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &sub_menu);
|
||||
|
||||
id = mtvm_menu_get_input_set(session, profile, sub_menu, "X." /* TODO Conf Min 3 Digit */);
|
||||
free_profile_menu_event(&sub_menu);
|
||||
}
|
||||
if (!password) {
|
||||
vmivr_menu_profile_t sub_menu = { "std_authenticate_ask_password" };
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &sub_menu);
|
||||
|
||||
password = mtvm_menu_get_input_set(session, profile, sub_menu, "X." /* TODO Conf Min 3 Digit */);
|
||||
free_profile_menu_event(&sub_menu);
|
||||
}
|
||||
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, id, password);
|
||||
|
||||
if (mt_api_execute(session, profile->api_auth_login, cmd) == SWITCH_STATUS_SUCCESS) {
|
||||
profile->id = id;
|
||||
profile->authorized = SWITCH_TRUE;
|
||||
} else {
|
||||
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "fail_auth"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
free_profile_menu_event(&menu);
|
||||
}
|
||||
|
||||
void mtvm_menu_select_greeting_slot(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
vmivr_menu_profile_t menu = { "std_select_greeting_slot" };
|
||||
|
||||
const char *result;
|
||||
int gnum = -1;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
result = mtvm_menu_get_input_set(session, profile, menu, "X");
|
||||
|
||||
if (result)
|
||||
gnum = atoi(result);
|
||||
if (gnum != -1) {
|
||||
char * cmd = switch_core_session_sprintf(session, "%s %s %s %d", profile->api_profile, profile->domain, profile->id, gnum);
|
||||
if (mt_api_execute(session, profile->api_pref_greeting_set, cmd) == SWITCH_STATUS_SUCCESS) {
|
||||
char *str_num = switch_core_session_sprintf(session, "%d", gnum);
|
||||
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
|
||||
} else {
|
||||
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "invalid_slot"), NULL, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
free_profile_menu_event(&menu);
|
||||
}
|
||||
|
||||
void mtvm_menu_record_greeting_with_slot(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
|
||||
vmivr_menu_profile_t menu = { "std_record_greeting_with_slot" };
|
||||
|
||||
const char *result;
|
||||
int gnum = -1;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
result = mtvm_menu_get_input_set(session, profile, menu, "X");
|
||||
|
||||
if (result)
|
||||
gnum = atoi(result);
|
||||
|
||||
/* If user entered 0, we don't accept it */
|
||||
if (gnum > 0) {
|
||||
vmivr_menu_profile_t sub_menu = { "std_record_greeting" };
|
||||
char *tmp_filepath = generate_random_file_name(session, "protovm", "wav" /* TODO make it configurable */);
|
||||
switch_status_t status;
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &sub_menu);
|
||||
|
||||
status = mtvm_menu_record(session, profile, sub_menu, tmp_filepath);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
char *cmd = switch_core_session_sprintf(session, "%s %s %s %d %s", profile->api_profile, profile->domain, profile->id, gnum, tmp_filepath);
|
||||
char *str_num = switch_core_session_sprintf(session, "%d", gnum);
|
||||
mt_api_execute(session, profile->api_pref_greeting_set, cmd);
|
||||
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
|
||||
}
|
||||
free_profile_menu_event(&sub_menu);
|
||||
|
||||
}
|
||||
|
||||
free_profile_menu_event(&menu);
|
||||
|
||||
}
|
||||
|
||||
void mtvm_menu_preference(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
int retry;
|
||||
|
||||
vmivr_menu_profile_t menu = { "std_preference" };
|
||||
|
||||
/* Initialize Menu Configs */
|
||||
populate_profile_menu_event(profile, &menu);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
dtmf_ss_t loc;
|
||||
char *dtmfa[16] = { 0 };
|
||||
switch_event_t *phrase_params = NULL;
|
||||
|
||||
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
append_event_profile(phrase_params, profile, menu);
|
||||
|
||||
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
|
||||
|
||||
captureMenuInitialize(&loc, dtmfa);
|
||||
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
|
||||
|
||||
if (loc.result == RES_TIMEOUT) {
|
||||
/* TODO Ask for the prompt Again IF retry != 0 */
|
||||
} else if (loc.result == RES_INVALID) {
|
||||
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
|
||||
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = MAX_ATTEMPT;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "return")) { /* Return to the previous menu */
|
||||
retry = -1;
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrase_params);
|
||||
}
|
||||
|
||||
free_profile_menu_event(&menu);
|
||||
}
|
||||
|
||||
char *mtvm_menu_get_input_set(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *input_mask) {
|
||||
char *result = NULL;
|
||||
int retry;
|
||||
const char *terminate_key = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys : %s\n", menu.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
terminate_key = switch_event_get_header(menu.event_keys_action, "ivrengine:terminate_entry");
|
||||
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
dtmf_ss_t loc;
|
||||
char *dtmfa[16] = { 0 };
|
||||
int i;
|
||||
switch_event_t *phrase_params = NULL;
|
||||
|
||||
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
append_event_profile(phrase_params, profile, menu);
|
||||
|
||||
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
|
||||
|
||||
/* Find the last entry and append this one to it */
|
||||
for (i=0; dtmfa[i] && i < 16; i++){
|
||||
}
|
||||
dtmfa[i] = (char *) input_mask;
|
||||
|
||||
captureMenuInitialize(&loc, dtmfa);
|
||||
if (terminate_key) {
|
||||
loc.terminate_key = terminate_key[0];
|
||||
}
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "instructions"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
|
||||
|
||||
if (loc.result == RES_TIMEOUT) {
|
||||
/* TODO Ask for the prompt Again IF retry != 0 */
|
||||
} else if (loc.result == RES_INVALID) {
|
||||
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
|
||||
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
|
||||
/* Reset the try count */
|
||||
retry = MAX_ATTEMPT;
|
||||
|
||||
if (!strncasecmp(loc.completeMatch, input_mask, 1)) {
|
||||
result = switch_core_session_strdup(session, loc.dtmf_stored);
|
||||
retry = -1;
|
||||
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrase_params);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
switch_status_t mtvm_menu_record(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *file_name) {
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
int retry;
|
||||
|
||||
switch_bool_t record_prompt = SWITCH_TRUE;
|
||||
switch_bool_t listen_recording = SWITCH_FALSE;
|
||||
switch_bool_t play_instruction = SWITCH_TRUE;
|
||||
|
||||
if (!menu.event_keys_dtmf || !menu.event_phrases) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
|
||||
dtmf_ss_t loc;
|
||||
|
||||
char *dtmfa[16] = { 0 };
|
||||
switch_event_t *phrase_params = NULL;
|
||||
switch_file_handle_t fh = { 0 };
|
||||
|
||||
/* TODO Make the following configurable */
|
||||
fh.thresh = 200;
|
||||
fh.silence_hits = 4;
|
||||
//fh.samplerate = 8000;
|
||||
|
||||
|
||||
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
append_event_profile(phrase_params, profile, menu);
|
||||
|
||||
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
|
||||
|
||||
captureMenuInitialize(&loc, dtmfa);
|
||||
if (record_prompt) {
|
||||
if (play_instruction) {
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "instructions"), NULL, phrase_params, NULL, 0);
|
||||
}
|
||||
play_instruction = SWITCH_TRUE;
|
||||
|
||||
captureMenuRecord(session, &loc, phrase_params, file_name, &fh, 30 /* TODO Make max recording configurable */);
|
||||
} else {
|
||||
if (listen_recording) {
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Record-File-Path", "%s", file_name);
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "play_recording"), NULL, phrase_params, NULL, 0);
|
||||
listen_recording = SWITCH_FALSE;
|
||||
|
||||
}
|
||||
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
|
||||
}
|
||||
|
||||
if (loc.recorded_audio) {
|
||||
/* Reset the try count */
|
||||
retry = MAX_ATTEMPT;
|
||||
|
||||
/* TODO Check if message is too short */
|
||||
|
||||
record_prompt = SWITCH_FALSE;
|
||||
|
||||
} else if (loc.result == RES_TIMEOUT) {
|
||||
/* TODO Ask for the prompt Again IF retry != 0 */
|
||||
} else if (loc.result == RES_INVALID) {
|
||||
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
|
||||
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
|
||||
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
|
||||
|
||||
/* Reset the try count */
|
||||
retry = MAX_ATTEMPT;
|
||||
|
||||
if (action) {
|
||||
if (!strcasecmp(action, "listen")) { /* Listen */
|
||||
listen_recording = SWITCH_TRUE;
|
||||
|
||||
} else if (!strcasecmp(action, "save")) {
|
||||
retry = -1;
|
||||
/* TODO ALLOW SAVE ONLY IF FILE IS RECORDED AND HIGHER THAN MIN SIZE */
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
} else if (!strcasecmp(action, "rerecord")) {
|
||||
record_prompt = SWITCH_TRUE;
|
||||
|
||||
} else if (!strcasecmp(action, "skip_instruction")) { /* Skip Recording Greeting */
|
||||
play_instruction = SWITCH_FALSE;
|
||||
|
||||
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
|
||||
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
|
||||
if (fPtr) {
|
||||
fPtr(session, profile);
|
||||
}
|
||||
} else if (!strcasecmp(action, "return")) { /* Return */
|
||||
retry = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrase_params);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void (*mtvm_get_menu_function(const char *menu_name))(switch_core_session_t *session, vmivr_profile_t *profile) {
|
||||
int i = 0;
|
||||
|
||||
if (menu_name) {
|
||||
for (i=0; menu_list[i].name ; i++) {
|
||||
if (!strcasecmp(menu_list[i].name, menu_name)) {
|
||||
return menu_list[i].pt2Func;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef _MENU_H_
|
||||
#define _MENU_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void mtvm_menu_purge(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_authenticate(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_main(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_record_name(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_set_password(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_select_greeting_slot(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_record_greeting_with_slot(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_preference(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
void mtvm_menu_forward(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
|
||||
switch_status_t mtvm_menu_record(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *file_name);
|
||||
char *mtvm_menu_get_input_set(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *input_mask);
|
||||
|
||||
|
||||
struct vmivr_menu_function {
|
||||
const char *name;
|
||||
void (*pt2Func)(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
|
||||
};
|
||||
typedef struct vmivr_menu_function vmivr_menu_function_t;
|
||||
|
||||
extern vmivr_menu_function_t menu_list[];
|
||||
|
||||
void (*mtvm_get_menu_function(const char *menu_name))(switch_core_session_t *session, vmivr_profile_t *profile);
|
||||
|
||||
#endif /* _MENU_H_ */
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* mod_protovm.c -- MT VoiceMail System
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "menu.h"
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_protovm_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_protovm_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_protovm_load);
|
||||
|
||||
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
|
||||
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
|
||||
*/
|
||||
SWITCH_MODULE_DEFINITION(mod_protovm, mod_protovm_load, mod_protovm_shutdown, NULL);
|
||||
|
||||
|
||||
#define MTVM_DESC "protovm"
|
||||
#define MTVM_USAGE "<check> profile domain [id]"
|
||||
|
||||
SWITCH_STANDARD_APP(protovm_function)
|
||||
{
|
||||
const char *id = NULL;
|
||||
const char *domain = NULL;
|
||||
const char *profile_name = NULL;
|
||||
vmivr_profile_t *profile = NULL;
|
||||
int argc = 0;
|
||||
char *argv[6] = { 0 };
|
||||
char *mydata = NULL;
|
||||
|
||||
if (!zstr(data)) {
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[1])
|
||||
profile_name = argv[1];
|
||||
|
||||
if (argv[2])
|
||||
domain = argv[2];
|
||||
|
||||
if (!strcasecmp(argv[0], "check")) {
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
|
||||
if (domain && profile_name) {
|
||||
profile = get_profile(session, profile_name);
|
||||
|
||||
if (profile) {
|
||||
void (*fPtrAuth)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(profile->menu_check_auth);
|
||||
void (*fPtrMain)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(profile->menu_check_main);
|
||||
void (*fPtrTerminate)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(profile->menu_check_terminate);
|
||||
|
||||
profile->domain = domain;
|
||||
profile->id = id;
|
||||
|
||||
if (fPtrAuth && !profile->authorized) {
|
||||
fPtrAuth(session, profile);
|
||||
}
|
||||
|
||||
if (fPtrMain && profile->authorized) {
|
||||
fPtrMain(session, profile);
|
||||
}
|
||||
if (fPtrTerminate) {
|
||||
fPtrTerminate(session, profile);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Macro expands to: switch_status_t mod_protovm_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_protovm_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "protovm", "protovm", MTVM_DESC, protovm_function, MTVM_USAGE, SAF_NONE);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Called when the system shuts down
|
||||
Macro expands to: switch_status_t mod_protovm_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_protovm_shutdown)
|
||||
{
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -1,176 +0,0 @@
|
||||
<configuration name="protovm.conf" description="ProtoVoicemailIVR">
|
||||
<profiles>
|
||||
<profile name="default">
|
||||
<apis>
|
||||
<api name="auth_login" value="vm_fsdb_auth_login" />
|
||||
<api name="msg_list" value="vm_fsdb_msg_list" />
|
||||
<api name="msg_count" value="vm_fsdb_msg_count" />
|
||||
<api name="msg_delete" value="vm_fsdb_msg_delete" />
|
||||
<api name="msg_undelete" value="vm_fsdb_msg_undelete" />
|
||||
<api name="msg_save" value="vm_fsdb_msg_save" />
|
||||
<api name="msg_purge" value="vm_fsdb_msg_purge" />
|
||||
<api name="msg_get" value="vm_fsdb_msg_get" />
|
||||
<api name="msg_forward" value="vm_fsdb_msg_forward" />
|
||||
<api name="pref_greeting_set" value="vm_fsdb_pref_greeting_set" />
|
||||
<api name="pref_recname_set" value="vm_fsdb_pref_recname_set" />
|
||||
<api name="pref_password_set" value="vm_fsdb_pref_password_set" />
|
||||
</apis>
|
||||
<menus>
|
||||
<menu name="std_authenticate">
|
||||
<phrases>
|
||||
<phrase name="fail_auth" value="fail_auth@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_authenticate_ask_user">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="enter_id@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_authenticate_ask_password">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="enter_pass@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_navigator">
|
||||
<phrases>
|
||||
<phrase name="msg_count" value="message_count@protovm" />
|
||||
<phrase name="say_date" value="say_date_event@protovm" />
|
||||
<phrase name="say_msg_number" value="say_message_number@protovm" />
|
||||
<phrase name="menu_options" value="listen_file_check@protovm" />
|
||||
<phrase name="ack" value="ack@protovm" />
|
||||
<phrase name="play_message" value="play_message@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="1" action="skip_intro" variable="VM-Key-Main-Listen-File" />
|
||||
<key dtmf="6" action="next_msg" variable="VM-Key-Main-Next-Msg" />
|
||||
<key dtmf="4" action="prev_msg" />
|
||||
<key dtmf="7" action="delete_msg" variable="VM-Key-Main-Delete-File" /> <!-- Same key for undelete if it already deleted -->
|
||||
<key dtmf="8" action="menu:std_forward" variable="VM-Key-Main-Forward" />
|
||||
<key dtmf="3" action="save_msg" variable="VM-Key-Main-Save-File" />
|
||||
<key dtmf="2" action="callback" variable="VM-Key-Main-Callback" />
|
||||
<key dtmf="5" action="menu:std_preference" />
|
||||
<key dtmf="#" action="return" /> <!-- TODO Might Conflict with future fast-forward -->
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_preference">
|
||||
<phrases>
|
||||
<phrase name="menu_options" value="config_menu@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="1" action="menu:std_record_greeting_with_slot" variable="VM-Key-Record-Greeting" />
|
||||
<key dtmf="2" action="menu:std_select_greeting_slot" variable="VM-Key-Choose-Greeting" />
|
||||
<key dtmf="3" action="menu:std_record_name" variable="VM-Key-Record-Name" />
|
||||
<key dtmf="6" action="menu:std_set_password" variable="VM-Key-Change-Password" />
|
||||
<key dtmf="#" action="return" variable="VM-Key-Main-Menu" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_record_greeting">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="record_greeting@protovm" />
|
||||
<phrase name="play_recording" value="play_recording@protovm" />
|
||||
<phrase name="menu_options" value="record_file_check@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
|
||||
<key dtmf="3" action="save" variable="VM-Key-Save-File" />
|
||||
<key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
|
||||
<key dtmf="#" action="skip_instruction" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
|
||||
<menu name="std_record_name">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="record_name@protovm" />
|
||||
<phrase name="play_recording" value="play_recording@protovm" />
|
||||
<phrase name="menu_options" value="record_file_check@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
|
||||
<key dtmf="3" action="save" variable="VM-Key-Save-File" />
|
||||
<key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
|
||||
<key dtmf="#" action="skip_instruction" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_record_message">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="record_message@protovm" />
|
||||
<phrase name="play_recording" value="play_recording@protovm" />
|
||||
<phrase name="menu_options" value="record_file_check@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
|
||||
<key dtmf="3" action="save" variable="VM-Key-Save-File" />
|
||||
<key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
|
||||
<key dtmf="#" action="skip_instruction" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_forward_ask_prepend">
|
||||
<phrases>
|
||||
<phrase name="menu_options" value="forward_ask_prepend@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="1" action="prepend" variable="VM-Key-Prepend" />
|
||||
<key dtmf="8" action="forward" variable="VM-Key-Forward" />
|
||||
<key dtmf="#" action="return" variable="VM-Key-Return" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_forward_ask_extension">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="forward_ask_extension@protovm" />
|
||||
<phrase name="ack" value="ack@protovm" />
|
||||
<phrase name="invalid_extension" value="invalid_extension@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_select_greeting_slot">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="choose_greeting@protovm" />
|
||||
<phrase name="invalid_slot" value="choose_greeting_fail@protovm" />
|
||||
<phrase name="selected_slot" value="greeting_selected@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_record_greeting_with_slot">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="choose_greeting@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
</keys>
|
||||
</menu>
|
||||
|
||||
<menu name="std_set_password">
|
||||
<phrases>
|
||||
<phrase name="instructions" value="enter_pass@protovm" />
|
||||
</phrases>
|
||||
<keys>
|
||||
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
|
||||
</keys>
|
||||
</menu>
|
||||
</menus>
|
||||
</profile>
|
||||
</profiles>
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -1,397 +0,0 @@
|
||||
<include><!--This line will be ignored it's here to validate the xml and is optional -->
|
||||
<macros name="protovm" sound-prefix="$${sounds_dir}/en/us/callie">
|
||||
<macro name="press_key">
|
||||
<input pattern="^(.*):(.*)$">
|
||||
<match>
|
||||
<action function="play-file" data="$2"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="plurial_msg">
|
||||
<input pattern="^[01]:(.*):(.*)$" break_on_match="true">
|
||||
<match>
|
||||
<action function="play-file" data="$1"/>
|
||||
</match>
|
||||
</input>
|
||||
<input pattern="^.*:(.*):(.*)$" break_on_match="true">
|
||||
<match>
|
||||
<action function="play-file" data="$2"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="enter_id">
|
||||
<input pattern="(.+)">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
<nomatch>
|
||||
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
|
||||
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
|
||||
</nomatch>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
|
||||
<macro name="enter_pass">
|
||||
<input pattern="(.+)">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-enter_pass.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
<nomatch>
|
||||
<action function="play-file" data="voicemail/vm-enter_pass.wav"/>
|
||||
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
|
||||
</nomatch>
|
||||
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="fail_auth">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-fail_auth.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="hello">
|
||||
<input>
|
||||
<match>
|
||||
<!--<action function="play-file" data="voicemail/vm-hello.wav"/> -->
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="goodbye">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-goodbye.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="abort">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-abort.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="message_count">
|
||||
<input field="${VM-Total-New-Urgent-Messages}" pattern="^(0)$">
|
||||
<nomatch>
|
||||
<action function="play-file" data="voicemail/vm-you_have.wav"/>
|
||||
<action function="say" data="${VM-Total-New-Urgent-Messages}" method="pronounced" type="items"/>
|
||||
<action function="play-file" data="voicemail/vm-urgent-new.wav"/>
|
||||
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-New-Urgent-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
|
||||
</nomatch>
|
||||
</input>
|
||||
<input field="${VM-Total-New-Messages}" pattern="^(\d+)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-you_have.wav"/>
|
||||
<action function="say" data="${VM-Total-New-Messages}" method="pronounced" type="items"/>
|
||||
<action function="play-file" data="voicemail/vm-new.wav"/>
|
||||
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-New-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input field="${VM-Total-Saved-Messages}" pattern="^(0)$">
|
||||
<nomatch>
|
||||
<action function="play-file" data="currency/and.wav"/>
|
||||
<action function="say" data="${VM-Total-Saved-Messages}" method="pronounced" type="items"/>
|
||||
<action function="play-file" data="voicemail/vm-saved.wav"/>
|
||||
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-Saved-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
|
||||
</nomatch>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="menu">
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Play-New-Messages}:voicemail/vm-listen_new.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Play-Saved-Messages}:voicemail/vm-listen_saved.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Config-Menu}:voicemail/vm-advanced.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Terminator}:voicemail/vm-to_exit.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="config_menu">
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-Greeting}:voicemail/vm-to_record_greeting.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Choose-Greeting}:voicemail/vm-choose_greeting.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-Name}:voicemail/vm-record_name2.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Change-Password}:voicemail/vm-change_password.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Menu}:voicemail/vm-main_menu.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="record_name">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-record_name1.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="forward_ask_prepend">
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="forward_ask_extension">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
|
||||
<!-- <action function="phrase" phrase="play-file" data="voicemail/vm-followed_by.wav"/>
|
||||
<action function="say" data="${VM-Key-Terminate}" method="pronounced" type="name_spelled"/>-->
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="record_file_check">
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Save-File}:voicemail/vm-save_recording.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-File}:voicemail/vm-rerecord.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
|
||||
<macro name="record_urgent_check">
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Urgent}:voicemail/vm-mark-urgent.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Terminator}:voicemail/vm-continue.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="forward_prepend">
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="forward_message_enter_extension">
|
||||
<input pattern="^([0-9#*])$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-followed_by.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="invalid_extension">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="listen_file_check">
|
||||
<input>
|
||||
<match>
|
||||
<!--<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Next-Msg}:voicemail/vm-for_next_msg.wav"/>--> <!-- Not existant in callie recordings -->
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Save-File}:voicemail/vm-save_recording.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Delete-File}:voicemail/vm-delete_recording.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input field="${VM-Message-Email}" pattern="^$">
|
||||
<nomatch>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Email}:voicemail/vm-forward_to_email.wav"/>
|
||||
</nomatch>
|
||||
</input>
|
||||
<input>
|
||||
<match>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Callback}:voicemail/vm-return_call.wav"/>
|
||||
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="choose_greeting">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="choose_greeting_fail">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="record_greeting">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-record_greeting.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="record_message">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-record_message.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="greeting_selected">
|
||||
<input pattern="^(\d+)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-greeting.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="items"/>
|
||||
<action function="play-file" data="voicemail/vm-selected.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="play_greeting">
|
||||
<input pattern="^(.*)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-person.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
<action function="play-file" data="voicemail/vm-not_available.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="say_number">
|
||||
<input pattern="^(\d+)$">
|
||||
<match>
|
||||
<action function="say" data="$1" method="pronounced" type="items"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="say_message_number">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-${VM-Message-Type}.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-message_number.wav"/>
|
||||
<action function="say" data="${VM-Message-Number}" method="pronounced" type="items"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="say_phone_number">
|
||||
<input pattern="^(.*)$">
|
||||
<match>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="say_name">
|
||||
<input pattern="^(.*)$">
|
||||
<match>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
<!-- Note: Update this to marked-urgent,emailed and saved once new sound files are recorded -->
|
||||
<macro name="ack">
|
||||
<input pattern="^(too-small)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-too-small.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input pattern="^(undeleted)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-message.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-$1.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input pattern="^(deleted)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-message.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-$1.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input pattern="^(saved)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-message.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-$1.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input pattern="^(emailed)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-message.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-$1.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
<input pattern="^(marked-urgent)$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-message.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-$1.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="say_date">
|
||||
<input pattern="^(.*)$">
|
||||
<match>
|
||||
<action function="say" data="$1" method="pronounced" type="short_date_time"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="say_date_event">
|
||||
<input>
|
||||
<match>
|
||||
<action function="say" data="${VM-Message-Received-Epoch}" method="pronounced" type="short_date_time"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="play_message">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="${VM-Message-File-Path}"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="play_recording">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="${VM-Record-File-Path}"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
||||
<macro name="disk_quota_exceeded">
|
||||
<input>
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-mailbox_full.wav"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
</macros>
|
||||
</include><!--This line will be ignored it's here to validate the xml and is optional -->
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
*
|
||||
*
|
||||
* utils.c -- MT VoiceMail / Different utility that might need to go into the core (after cleanup)
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
switch_status_t mt_merge_media_files(const char** inputs, const char *output) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_file_handle_t fh_output = { 0 };
|
||||
int channels = 1;
|
||||
int rate = 8000; /* TODO Make this configurable */
|
||||
int j = 0;
|
||||
|
||||
if (switch_core_file_open(&fh_output, output, channels, rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s\n", output);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (j = 0; inputs[j] != NULL && j < 128 && status == SWITCH_STATUS_SUCCESS; j++) {
|
||||
switch_file_handle_t fh_input = { 0 };
|
||||
char buf[2048];
|
||||
switch_size_t len = sizeof(buf) / 2;
|
||||
|
||||
if (switch_core_file_open(&fh_input, inputs[j], channels, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s\n", inputs[j]);
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
break;
|
||||
}
|
||||
|
||||
while (switch_core_file_read(&fh_input, buf, &len) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_core_file_write(&fh_output, buf, &len) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Write error\n");
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fh_input.file_interface) {
|
||||
switch_core_file_close(&fh_input);
|
||||
}
|
||||
}
|
||||
|
||||
if (fh_output.file_interface) {
|
||||
switch_core_file_close(&fh_output);
|
||||
}
|
||||
end:
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_event_t *jsonapi2event(switch_core_session_t *session, switch_event_t *apply_event, const char *api, const char *data) {
|
||||
switch_event_t *phrases_event = NULL;
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute(api, data, session, &stream);
|
||||
switch_event_create_json(&phrases_event, (char *) stream.data);
|
||||
switch_safe_free(stream.data);
|
||||
|
||||
if (apply_event) {
|
||||
switch_event_header_t *hp;
|
||||
for (hp = phrases_event->headers; hp; hp = hp->next) {
|
||||
if (!strncasecmp(hp->name, "VM-", 3)) {
|
||||
switch_event_add_header(apply_event, SWITCH_STACK_BOTTOM, hp->name, "%s", hp->value);
|
||||
}
|
||||
}
|
||||
switch_event_destroy(&phrases_event);
|
||||
phrases_event = apply_event;
|
||||
|
||||
}
|
||||
|
||||
return phrases_event;
|
||||
}
|
||||
|
||||
char *generate_random_file_name(switch_core_session_t *session, const char *mod_name, char *file_extension) {
|
||||
char rand_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = "";
|
||||
switch_uuid_t srand_uuid;
|
||||
|
||||
switch_uuid_get(&srand_uuid);
|
||||
switch_uuid_format(rand_uuid, &srand_uuid);
|
||||
|
||||
return switch_core_session_sprintf(session, "%s%s%s_%s.%s", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, mod_name, rand_uuid, file_extension);
|
||||
|
||||
}
|
||||
|
||||
switch_status_t mt_api_execute(switch_core_session_t *session, const char *apiname, const char *arguments) {
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute(apiname, arguments, session, &stream);
|
||||
if (!strncasecmp(stream.data, "-ERR", 4)) {
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
}
|
||||
switch_safe_free(stream.data);
|
||||
return status;
|
||||
}
|
||||
|
||||
void append_event_profile(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu) {
|
||||
/* Used for some appending function */
|
||||
if (profile->name && profile->id && profile->domain) {
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Profile", "%s", profile->name);
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Account-ID", "%s", profile->id);
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Account-Domain", "%s", profile->domain);
|
||||
}
|
||||
}
|
||||
|
||||
void populate_dtmfa_from_event(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu, char **dtmfa) {
|
||||
int i = 0;
|
||||
if (menu.event_keys_dtmf) {
|
||||
switch_event_header_t *hp;
|
||||
|
||||
for (hp = menu.event_keys_dtmf->headers; hp; hp = hp->next) {
|
||||
if (strlen(hp->name) < 3 && hp->value) { /* TODO This is a hack to discard default FS Events ! */
|
||||
const char *varphrasename = switch_event_get_header(menu.event_keys_varname, hp->value);
|
||||
dtmfa[i++] = hp->name;
|
||||
|
||||
if (varphrasename && !zstr(varphrasename)) {
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, varphrasename, "%s", hp->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void append_event_message(switch_core_session_t *session, vmivr_profile_t *profile, switch_event_t *phrase_params, switch_event_t *msg_list_event, size_t current_msg) {
|
||||
|
||||
char *varname;
|
||||
char *apicmd;
|
||||
|
||||
varname = switch_mprintf("VM-List-Message-%" SWITCH_SIZE_T_FMT "-UUID", current_msg);
|
||||
apicmd = switch_mprintf("json %s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(msg_list_event, varname));
|
||||
|
||||
switch_safe_free(varname);
|
||||
|
||||
jsonapi2event(session, phrase_params, profile->api_msg_get, apicmd);
|
||||
|
||||
/* TODO Set these 2 header correctly */
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Type", "%s", "new");
|
||||
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Number", "%"SWITCH_SIZE_T_FMT, current_msg);
|
||||
|
||||
switch_event_add_header_string(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Private-Local-Copy", "False");
|
||||
|
||||
switch_safe_free(apicmd);
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
switch_status_t mt_merge_files(const char** inputs, const char *output);
|
||||
|
||||
void append_event_message(switch_core_session_t *session, vmivr_profile_t *profile, switch_event_t *phrase_params, switch_event_t *msg_list_event, size_t current_msg);
|
||||
void append_event_profile(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu);
|
||||
char *generate_random_file_name(switch_core_session_t *session, const char *mod_name, char *file_extension);
|
||||
switch_event_t *jsonapi2event(switch_core_session_t *session, switch_event_t *apply_event, const char *api, const char *data);
|
||||
switch_status_t mt_merge_media_files(const char** inputs, const char *output);
|
||||
switch_status_t mt_api_execute(switch_core_session_t *session, const char *apiname, const char *arguments);
|
||||
void populate_dtmfa_from_event(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu, char **dtmfa);
|
||||
#endif /* _UTIL_H_ */
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mod_sms"
|
||||
ProjectGUID="{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}"
|
||||
RootNamespace="mod_sms"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\mod_sms.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_sms</ProjectName>
|
||||
<ProjectGuid>{11C9BC3D-45E9-46E3-BE84-B8CEE4685E39}</ProjectGuid>
|
||||
<RootNamespace>mod_sms</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_sms.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* mod_sms.c -- Abstract SMS
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#define SMS_CHAT_PROTO "GLOBAL_SMS"
|
||||
#define MY_EVENT_SEND_MESSAGE "SMS::SEND_MESSAGE"
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sms_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_sms_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_sms, mod_sms_load, mod_sms_shutdown, NULL);
|
||||
|
||||
|
||||
static void event_handler(switch_event_t *event)
|
||||
{
|
||||
const char *dest_proto = switch_event_get_header(event, "dest_proto");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "skip_global_process", "true");
|
||||
switch_core_chat_send(dest_proto, event);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
BREAK_ON_TRUE,
|
||||
BREAK_ON_FALSE,
|
||||
BREAK_ALWAYS,
|
||||
BREAK_NEVER
|
||||
} break_t;
|
||||
|
||||
|
||||
|
||||
static int parse_exten(switch_event_t *event, switch_xml_t xexten, switch_event_t **extension)
|
||||
{
|
||||
switch_xml_t xcond, xaction, xexpression;
|
||||
char *exten_name = (char *) switch_xml_attr(xexten, "name");
|
||||
int proceed = 0;
|
||||
char *expression_expanded = NULL, *field_expanded = NULL;
|
||||
switch_regex_t *re = NULL;
|
||||
const char *to = switch_event_get_header(event, "to");
|
||||
|
||||
if (!to) {
|
||||
to = "nobody";
|
||||
}
|
||||
|
||||
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, NULL);
|
||||
|
||||
switch_safe_free(field_expanded);
|
||||
switch_safe_free(expression_expanded);
|
||||
|
||||
if (switch_xml_child(xcond, "condition")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, 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_event_expand_headers(event, 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_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s Date/Time Match (PASS) [%s] break=%s\n",
|
||||
to, exten_name, do_break_a ? do_break_a : "on-false");
|
||||
anti_action = SWITCH_FALSE;
|
||||
} else if (time_match == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s Date/Time Match (FAIL) [%s] break=%s\n",
|
||||
to, exten_name, do_break_a ? do_break_a : "on-false");
|
||||
}
|
||||
|
||||
if (field) {
|
||||
if (strchr(field, '$')) {
|
||||
if ((field_expanded = switch_event_expand_headers(event, field)) == field) {
|
||||
field_expanded = NULL;
|
||||
field_data = field;
|
||||
} else {
|
||||
field_data = field_expanded;
|
||||
}
|
||||
} else {
|
||||
field_data = switch_event_get_header(event, 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_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n",
|
||||
to, exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false");
|
||||
anti_action = SWITCH_FALSE;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n",
|
||||
to, exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false");
|
||||
}
|
||||
} else if (time_match == -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s Absolute Condition [%s]\n", to, 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 ((switch_event_create(extension, SWITCH_EVENT_CLONE)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (loop) {
|
||||
loop_count = atoi(loop);
|
||||
}
|
||||
|
||||
for (;loop_count > 0; loop_count--) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s ANTI-Action %s(%s) %s\n", to, application, data, xinline ? "INLINE" : "");
|
||||
|
||||
if (xinline) {
|
||||
switch_core_execute_chat_app(event, application, data);
|
||||
} else {
|
||||
switch_event_add_header_string(*extension, SWITCH_STACK_BOTTOM, application, zstr(data) ? "__undef" : data);
|
||||
}
|
||||
}
|
||||
proceed = 1;
|
||||
}
|
||||
} else {
|
||||
if (field && strchr(expression, '(')) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DP_MATCH", NULL);
|
||||
switch_capture_regex(re, proceed, field_data, ovector, "DP_MATCH", switch_regex_set_event_header_callback, event);
|
||||
}
|
||||
|
||||
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))) {
|
||||
abort();
|
||||
}
|
||||
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 ((switch_event_create(extension, SWITCH_EVENT_CLONE)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (loop) {
|
||||
loop_count = atoi(loop);
|
||||
}
|
||||
for (;loop_count > 0; loop_count--) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s Action %s(%s) %s\n", to, application, app_data, xinline ? "INLINE" : "");
|
||||
|
||||
if (xinline) {
|
||||
switch_core_execute_chat_app(event, application, app_data);
|
||||
} else {
|
||||
switch_event_add_header_string(*extension, SWITCH_STACK_BOTTOM, application, zstr(data) ? "__undef" : 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;
|
||||
}
|
||||
|
||||
|
||||
static switch_event_t *chatplan_hunt(switch_event_t *event)
|
||||
{
|
||||
switch_event_t *extension = NULL;
|
||||
switch_xml_t alt_root = NULL, cfg, xml = NULL, xcontext, xexten = NULL;
|
||||
const char *alt_path;
|
||||
const char *context;
|
||||
const char *from;
|
||||
const char *to;
|
||||
|
||||
if (!(context = switch_event_get_header(event, "context"))) {
|
||||
context = "default";
|
||||
}
|
||||
|
||||
if (!(from = switch_event_get_header(event, "from_user"))) {
|
||||
from = switch_event_get_header(event, "from");
|
||||
}
|
||||
|
||||
if (!(to = switch_event_get_header(event, "to_user"))) {
|
||||
to = switch_event_get_header(event, "to");
|
||||
}
|
||||
|
||||
alt_path = switch_event_get_header(event, "alt_path");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Processing text message %s->%s in context %s\n", from, to, context);
|
||||
|
||||
/* get our handle to the "chatplan" section of the config */
|
||||
|
||||
if (!zstr(alt_path)) {
|
||||
switch_xml_t conf = NULL, tag = NULL;
|
||||
if (!(alt_root = switch_xml_parse_file_simple(alt_path))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of [%s] failed\n", alt_path);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((conf = switch_xml_find_child(alt_root, "section", "name", "chatplan")) && (tag = switch_xml_find_child(conf, "chatplan", NULL, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Getting chatplan from alternate path: %s\n", alt_path);
|
||||
xml = alt_root;
|
||||
cfg = tag;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of chatplan failed\n");
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
if (switch_xml_locate("chatplan", NULL, NULL, NULL, &xml, &cfg, event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of chatplan failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* get a handle to the context tag */
|
||||
if (!(xcontext = switch_xml_find_child(cfg, "context", "name", context))) {
|
||||
if (!(xcontext = switch_xml_find_child(cfg, "context", "name", "global"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Context %s not found\n", context);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
xexten = switch_xml_child(xcontext, "extension");
|
||||
|
||||
while (xexten) {
|
||||
int proceed = 0;
|
||||
const char *cont = switch_xml_attr(xexten, "continue");
|
||||
const char *exten_name = switch_xml_attr(xexten, "name");
|
||||
|
||||
if (!exten_name) {
|
||||
exten_name = "UNKNOWN";
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
|
||||
"Chatplan: %s parsing [%s->%s] continue=%s\n",
|
||||
to, context, exten_name, cont ? cont : "false");
|
||||
|
||||
proceed = parse_exten(event, xexten, &extension);
|
||||
|
||||
if (proceed && !switch_true(cont)) {
|
||||
break;
|
||||
}
|
||||
|
||||
xexten = xexten->next;
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
xml = NULL;
|
||||
|
||||
done:
|
||||
switch_xml_free(xml);
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t chat_send(switch_event_t *message_event)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_event_t *exten;
|
||||
int forwards = 0;
|
||||
const char *var;
|
||||
|
||||
var = switch_event_get_header(message_event, "max_forwards");
|
||||
|
||||
if (!var) {
|
||||
forwards = 70;
|
||||
} else {
|
||||
forwards = atoi(var);
|
||||
|
||||
if (forwards) {
|
||||
forwards--;
|
||||
}
|
||||
|
||||
if (!forwards) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max forwards reached\n");
|
||||
DUMP_EVENT(message_event);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (forwards) {
|
||||
switch_event_add_header(message_event, SWITCH_STACK_BOTTOM, "max_forwards", "%d", forwards);
|
||||
}
|
||||
|
||||
if ((exten = chatplan_hunt(message_event))) {
|
||||
switch_event_header_t *hp;
|
||||
|
||||
for (hp = exten->headers; hp; hp = hp->next) {
|
||||
status = switch_core_execute_chat_app(message_event, hp->name, hp->value);
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch_event_destroy(&exten);
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_CHAT_APP(stop_function)
|
||||
{
|
||||
switch_set_flag(message, EF_NO_CHAT_EXEC);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_CHAT_APP(send_function)
|
||||
{
|
||||
const char *dest_proto = data;
|
||||
|
||||
if (zstr(dest_proto)) {
|
||||
dest_proto = switch_event_get_header(message, "dest_proto");
|
||||
}
|
||||
|
||||
switch_event_add_header(message, SWITCH_STACK_BOTTOM, "skip_global_process", "true");
|
||||
|
||||
switch_core_chat_send(dest_proto, message);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_CHAT_APP(set_function)
|
||||
{
|
||||
char *var, *val;
|
||||
|
||||
if (data) {
|
||||
var = strdup(data);
|
||||
if ((val = strchr(var, '='))) {
|
||||
*val++ = '\0';
|
||||
}
|
||||
|
||||
if (zstr(val)) {
|
||||
switch_event_del_header(message, var);
|
||||
} else {
|
||||
switch_event_add_header_string(message, SWITCH_STACK_BOTTOM, var, val);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_CHAT_APP(fire_function)
|
||||
{
|
||||
switch_event_t *fireme;
|
||||
|
||||
switch_event_dup(&fireme, message);
|
||||
switch_event_fire(&fireme);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_CHAT_APP(reply_function)
|
||||
{
|
||||
switch_event_t *reply;
|
||||
const char *proto = switch_event_get_header(message, "proto");
|
||||
|
||||
if (proto) {
|
||||
switch_ivr_create_message_reply(&reply, message, SMS_CHAT_PROTO);
|
||||
|
||||
if (!zstr(data)) {
|
||||
switch_event_set_body(reply, data);
|
||||
}
|
||||
|
||||
switch_core_chat_deliver(proto, &reply);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Macro expands to: switch_status_t mod_sms_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load)
|
||||
{
|
||||
switch_chat_interface_t *chat_interface;
|
||||
switch_chat_application_interface_t *chat_app_interface;
|
||||
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_CUSTOM, MY_EVENT_SEND_MESSAGE, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_CHAT(chat_interface, SMS_CHAT_PROTO, chat_send);
|
||||
|
||||
SWITCH_ADD_CHAT_APP(chat_app_interface, "reply", "reply to a message", "reply to a message", reply_function, "", SCAF_NONE);
|
||||
SWITCH_ADD_CHAT_APP(chat_app_interface, "stop", "stop execution", "stop execution", stop_function, "", SCAF_NONE);
|
||||
SWITCH_ADD_CHAT_APP(chat_app_interface, "set", "set a variable", "set a variable", set_function, "", SCAF_NONE);
|
||||
SWITCH_ADD_CHAT_APP(chat_app_interface, "send", "send the message as-is", "send the message as-is", send_function, "", SCAF_NONE);
|
||||
SWITCH_ADD_CHAT_APP(chat_app_interface, "fire", "fire the message", "fire the message", fire_function, "", SCAF_NONE);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
Called when the system shuts down
|
||||
Macro expands to: switch_status_t mod_sms_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sms_shutdown)
|
||||
{
|
||||
switch_event_unbind_callback(event_handler);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
|
||||
*/
|
||||
@@ -1,5 +1,5 @@
|
||||
BASE=../../../..
|
||||
VERSION=soundtouch-1.5.0
|
||||
VERSION=soundtouch-1.6.0
|
||||
SNDT_SRC=$(switch_srcdir)/libs/soundtouch
|
||||
SNDT_BUILD=$(switch_builddir)/libs/soundtouch
|
||||
LA=$(SNDT_BUILD)/source/SoundTouch/.libs/libSoundTouch.a
|
||||
|
||||
@@ -252,7 +252,7 @@ SWITCH_STANDARD_APP(soundtouch_start_function)
|
||||
char *argv[6];
|
||||
int argc;
|
||||
char *lbuf = NULL;
|
||||
int x;
|
||||
int x, n;
|
||||
|
||||
if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_soundtouch_"))) {
|
||||
if (!zstr(data) && !strcasecmp(data, "stop")) {
|
||||
@@ -275,26 +275,38 @@ SWITCH_STANDARD_APP(soundtouch_start_function)
|
||||
sth->tempo = 1;
|
||||
sth->hook_dtmf = false;
|
||||
sth->send_not_recv = false;
|
||||
n = 0;
|
||||
for (x = 0; x < argc; x++) {
|
||||
if (!strncasecmp(argv[x], "send_leg", 8)) {
|
||||
sth->send_not_recv = true;
|
||||
} else if (!strncasecmp(argv[x], "hook_dtmf", 9)) {
|
||||
sth->hook_dtmf = true;
|
||||
n++;
|
||||
} else if (strchr(argv[x], 'p')) {
|
||||
sth->pitch = normalize_soundtouch_value('p',atof(argv[x]));
|
||||
sth->pitch = normalize_soundtouch_value('p', atof(argv[x]));
|
||||
n++;
|
||||
} else if (strchr(argv[x], 'r')) {
|
||||
sth->rate = normalize_soundtouch_value('r',atof(argv[x]));
|
||||
sth->rate = normalize_soundtouch_value('r', atof(argv[x]));
|
||||
n++;
|
||||
} else if (strchr(argv[x], 'o')) {
|
||||
sth->pitch = normalize_soundtouch_value('p', compute_pitch_from_octaves(atof(argv[x])) );
|
||||
n++;
|
||||
} else if (strchr(argv[x], 's')) {
|
||||
/*12.0f taken from soundtouch conversion to octaves*/
|
||||
sth->pitch = normalize_soundtouch_value('p', compute_pitch_from_octaves(atof(argv[x]) / 12.0f) );
|
||||
n++;
|
||||
} else if (strchr(argv[x], 't')) {
|
||||
sth->tempo = normalize_soundtouch_value('t',atof(argv[x]));
|
||||
sth->tempo = normalize_soundtouch_value('t', atof(argv[x]));
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot run, no pitch set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sth->session = session;
|
||||
|
||||
@@ -308,9 +320,134 @@ SWITCH_STANDARD_APP(soundtouch_start_function)
|
||||
|
||||
}
|
||||
|
||||
/* API Interface Function */
|
||||
#define SOUNDTOUCH_API_SYNTAX "<uuid> [start|stop] [send_leg] [hook_dtmf] [-]<X>s [-]<X>o <X>p <X>r <X>t"
|
||||
SWITCH_STANDARD_API(soundtouch_api_function)
|
||||
{
|
||||
switch_core_session_t *rsession = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
switch_media_bug_t *bug;
|
||||
switch_status_t status;
|
||||
struct soundtouch_helper *sth;
|
||||
char *mycmd = NULL;
|
||||
int argc = 0;
|
||||
char *argv[10] = { 0 };
|
||||
char *uuid = NULL;
|
||||
char *action = NULL;
|
||||
char *lbuf = NULL;
|
||||
int x, n;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (!(mycmd = strdup(cmd))) {
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
|
||||
goto usage;
|
||||
}
|
||||
|
||||
uuid = argv[0];
|
||||
action = argv[1];
|
||||
|
||||
if (!(rsession = switch_core_session_locate(uuid))) {
|
||||
stream->write_function(stream, "-ERR Cannot locate session!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
channel = switch_core_session_get_channel(rsession);
|
||||
|
||||
if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_soundtouch_"))) {
|
||||
if (!zstr(action) && !strcasecmp(action, "stop")) {
|
||||
switch_channel_set_private(channel, "_soundtouch_", NULL);
|
||||
switch_core_media_bug_remove(rsession, &bug);
|
||||
stream->write_function(stream, "+OK Success\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Cannot run 2 at once on the same channel!\n");
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!zstr(action) && strcasecmp(action, "start")) {
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
goto usage;
|
||||
}
|
||||
|
||||
sth = (struct soundtouch_helper *) switch_core_session_alloc(rsession, sizeof(*sth));
|
||||
assert(sth != NULL);
|
||||
|
||||
|
||||
sth->pitch = 1;
|
||||
sth->rate = 1;
|
||||
sth->tempo = 1;
|
||||
sth->hook_dtmf = false;
|
||||
sth->send_not_recv = false;
|
||||
n = 0;
|
||||
for (x = 2; x < argc; x++) {
|
||||
if (!strncasecmp(argv[x], "send_leg", 8)) {
|
||||
sth->send_not_recv = true;
|
||||
} else if (!strncasecmp(argv[x], "hook_dtmf", 9)) {
|
||||
sth->hook_dtmf = true;
|
||||
n++;
|
||||
} else if (strchr(argv[x], 'p')) {
|
||||
sth->pitch = normalize_soundtouch_value('p', atof(argv[x]));
|
||||
n++;
|
||||
} else if (strchr(argv[x], 'r')) {
|
||||
sth->rate = normalize_soundtouch_value('r', atof(argv[x]));
|
||||
n++;
|
||||
} else if (strchr(argv[x], 'o')) {
|
||||
sth->pitch = normalize_soundtouch_value('p', compute_pitch_from_octaves(atof(argv[x])) );
|
||||
n++;
|
||||
} else if (strchr(argv[x], 's')) {
|
||||
/*12.0f taken from soundtouch conversion to octaves*/
|
||||
sth->pitch = normalize_soundtouch_value('p', compute_pitch_from_octaves(atof(argv[x]) / 12.0f) );
|
||||
n++;
|
||||
} else if (strchr(argv[x], 't')) {
|
||||
sth->tempo = normalize_soundtouch_value('t', atof(argv[x]));
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rsession), SWITCH_LOG_WARNING, "Cannot run, no pitch set\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
sth->session = rsession;
|
||||
|
||||
if ((status = switch_core_media_bug_add(rsession, "soundtouch", NULL, soundtouch_callback, sth, 0,
|
||||
sth->send_not_recv ? SMBF_WRITE_REPLACE : SMBF_READ_REPLACE, &bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR Failure!\n");
|
||||
goto done;
|
||||
} else {
|
||||
switch_channel_set_private(channel, "_soundtouch_", bug);
|
||||
stream->write_function(stream, "+OK Success\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
usage:
|
||||
stream->write_function(stream, "-USAGE: %s\n", SOUNDTOUCH_API_SYNTAX);
|
||||
|
||||
done:
|
||||
if (rsession) {
|
||||
switch_core_session_rwunlock(rsession);
|
||||
}
|
||||
|
||||
switch_safe_free(mycmd);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_soundtouch_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
@@ -318,6 +455,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_soundtouch_load)
|
||||
SWITCH_ADD_APP(app_interface, "soundtouch", "Alter the audio stream", "Alter the audio stream pitch/rate/tempo",
|
||||
soundtouch_start_function, "[send_leg] [hook_dtmf] [-]<X>s [-]<X>o <X>p <X>r <X>t", SAF_NONE);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "soundtouch", "soundtouch", soundtouch_api_function, SOUNDTOUCH_API_SYNTAX);
|
||||
|
||||
switch_console_set_complete("add soundtouch ::console::list_uuid ::[start:stop");
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -4,16 +4,16 @@ MODNAME=mod_spandsp
|
||||
TIFF_DIR=$(switch_srcdir)/libs/tiff-3.8.2
|
||||
TIFF_BUILDDIR=$(switch_builddir)/libs/tiff-3.8.2
|
||||
TIFF_LA=$(TIFF_BUILDDIR)/libtiff/libtiff.la
|
||||
|
||||
BUILD_CFLAGS=
|
||||
SPANDSP_DIR=$(switch_srcdir)/libs/spandsp
|
||||
SPANDSP_BUILDDIR=$(switch_builddir)/libs/spandsp
|
||||
SPANDSP_LA=$(SPANDSP_BUILDDIR)/src/libspandsp.la
|
||||
|
||||
mod_LTLIBRARIES = mod_spandsp.la
|
||||
mod_spandsp_la_SOURCES = mod_spandsp.c udptl.c mod_spandsp_fax.c mod_spandsp_dsp.c mod_spandsp_codecs.c
|
||||
mod_spandsp_la_CFLAGS = $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff -I.
|
||||
mod_spandsp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA)
|
||||
mod_spandsp_la_LDFLAGS = -avoid-version -module -no-undefined -shared -ljpeg
|
||||
mod_spandsp_la_SOURCES = mod_spandsp.c udptl.c mod_spandsp_fax.c mod_spandsp_dsp.c mod_spandsp_codecs.c mod_spandsp_modem.c
|
||||
mod_spandsp_la_CFLAGS = $(BUILD_CFLAGS) $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff -I.
|
||||
mod_spandsp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA) -ljpeg -lz -lutil
|
||||
mod_spandsp_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
||||
|
||||
$(SPANDSP_LA): $(TIFF_LA) $(SPANDSP_DIR) $(SPANDSP_DIR)/.update
|
||||
cd $(SPANDSP_BUILDDIR) && $(MAKE) -j1
|
||||
|
||||
@@ -301,6 +301,10 @@
|
||||
RelativePath=".\mod_spandsp_fax.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mod_spandsp_modem.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\udptl.c"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@@ -129,6 +129,7 @@
|
||||
<ClCompile Include="mod_spandsp_codecs.c" />
|
||||
<ClCompile Include="mod_spandsp_dsp.c" />
|
||||
<ClCompile Include="mod_spandsp_fax.c" />
|
||||
<ClCompile Include="mod_spandsp_modem.c" />
|
||||
<ClCompile Include="udptl.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -148,4 +149,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -36,11 +36,14 @@
|
||||
|
||||
#include "mod_spandsp.h"
|
||||
#include <spandsp/version.h>
|
||||
#include "mod_spandsp_modem.h"
|
||||
|
||||
/* **************************************************************************
|
||||
FREESWITCH MODULE DEFINITIONS
|
||||
************************************************************************* */
|
||||
|
||||
struct spandsp_globals spandsp_globals = { 0 };
|
||||
|
||||
#define SPANFAX_RX_USAGE "<filename>"
|
||||
#define SPANFAX_TX_USAGE "<filename>"
|
||||
|
||||
@@ -74,25 +77,35 @@ SWITCH_STANDARD_APP(stop_dtmf_session_function)
|
||||
SWITCH_STANDARD_APP(spandsp_fax_detect_session_function)
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[3] = { 0 };
|
||||
char *argv[4] = { 0 };
|
||||
char *dupdata;
|
||||
const char *app = NULL, *arg = NULL;
|
||||
int timeout = 0;
|
||||
int tone_type = MODEM_CONNECT_TONES_FAX_CNG;
|
||||
|
||||
if (!zstr(data) && (dupdata = switch_core_session_strdup(session, data))) {
|
||||
if ((argc = switch_split(dupdata, ' ', argv)) == 3) {
|
||||
if ((argc = switch_split(dupdata, ' ', argv)) >= 2) {
|
||||
app = argv[0];
|
||||
arg = argv[1];
|
||||
timeout = atoi(argv[2]);
|
||||
if (timeout < 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
if (argc > 2) {
|
||||
timeout = atoi(argv[2]);
|
||||
if (timeout < 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
if (argc > 3) {
|
||||
if (!strcmp(argv[3], "ced")) {
|
||||
tone_type = MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE;
|
||||
} else {
|
||||
tone_type = MODEM_CONNECT_TONES_FAX_CNG;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (app) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Enabling fax detection '%s' '%s'\n", argv[0], argv[1]);
|
||||
spandsp_fax_detect_session(session, "rw", timeout, 1, app, arg, NULL);
|
||||
spandsp_fax_detect_session(session, "rw", timeout, tone_type, 1, app, arg, NULL);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot Enable fax detection '%s' '%s'\n", argv[0], argv[1]);
|
||||
}
|
||||
@@ -106,10 +119,9 @@ SWITCH_STANDARD_APP(spandsp_stop_fax_detect_session_function)
|
||||
|
||||
static void event_handler(switch_event_t *event)
|
||||
{
|
||||
mod_spandsp_fax_event_handler(event);
|
||||
load_configuration(1);
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(t38_gateway_function)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
@@ -151,7 +163,7 @@ SWITCH_STANDARD_APP(t38_gateway_function)
|
||||
}
|
||||
|
||||
//switch_ivr_tone_detect_session(session, "t38", "1100.0", "rw", timeout, 1, direction, NULL, t38_gateway_start);
|
||||
spandsp_fax_detect_session(session, "rw", timeout, 1, direction, NULL, t38_gateway_start);
|
||||
spandsp_fax_detect_session(session, "rw", timeout, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, 1, direction, NULL, t38_gateway_start);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,12 +263,274 @@ SWITCH_STANDARD_API(stop_tone_detect_api)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void mod_spandsp_indicate_data(switch_core_session_t *session, switch_bool_t self, switch_bool_t on)
|
||||
{
|
||||
switch_core_session_t *target_session = NULL;
|
||||
int locked = 0;
|
||||
|
||||
if (self) {
|
||||
target_session = session;
|
||||
} else {
|
||||
if (switch_core_session_get_partner(session, &target_session) == SWITCH_STATUS_SUCCESS) {
|
||||
locked = 1;
|
||||
} else {
|
||||
target_session = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (target_session) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
msg = switch_core_session_alloc(target_session, sizeof(*msg));
|
||||
MESSAGE_STAMP_FFL(msg);
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_AUDIO_DATA;
|
||||
msg->from = __FILE__;
|
||||
msg->numeric_arg = on;
|
||||
|
||||
switch_core_session_queue_message(target_session, msg);
|
||||
|
||||
if (locked) {
|
||||
switch_core_session_rwunlock(target_session);
|
||||
locked = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* **************************************************************************
|
||||
CONFIGURATION
|
||||
************************************************************************* */
|
||||
|
||||
switch_status_t load_configuration(switch_bool_t reload)
|
||||
{
|
||||
switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL, callprogress = NULL, xdescriptor = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
switch_mutex_lock(spandsp_globals.mutex);
|
||||
|
||||
if (spandsp_globals.tones) {
|
||||
switch_core_hash_destroy(&spandsp_globals.tones);
|
||||
}
|
||||
|
||||
if (spandsp_globals.config_pool) {
|
||||
switch_core_destroy_memory_pool(&spandsp_globals.config_pool);
|
||||
}
|
||||
|
||||
switch_core_new_memory_pool(&spandsp_globals.config_pool);
|
||||
switch_core_hash_init(&spandsp_globals.tones, spandsp_globals.config_pool);
|
||||
|
||||
spandsp_globals.modem_dialplan = "XML";
|
||||
spandsp_globals.modem_context = "default";
|
||||
spandsp_globals.modem_count = 0;
|
||||
|
||||
|
||||
spandsp_globals.enable_t38 = 1;
|
||||
spandsp_globals.total_sessions = 0;
|
||||
spandsp_globals.verbose = 0;
|
||||
spandsp_globals.use_ecm = 1;
|
||||
spandsp_globals.disable_v17 = 0;
|
||||
spandsp_globals.prepend_string = switch_core_strdup(spandsp_globals.config_pool, "fax");
|
||||
spandsp_globals.spool = switch_core_strdup(spandsp_globals.config_pool, "/tmp");
|
||||
spandsp_globals.ident = "SpanDSP Fax Ident";
|
||||
spandsp_globals.header = "SpanDSP Fax Header";
|
||||
spandsp_globals.timezone = "";
|
||||
|
||||
/* TODO make configuration param */
|
||||
spandsp_globals.tonedebug = 1;
|
||||
|
||||
if ((xml = switch_xml_open_cfg("spandsp.conf", &cfg, NULL)) || (xml = switch_xml_open_cfg("fax.conf", &cfg, NULL))) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if ((x_lists = switch_xml_child(cfg, "modem-settings"))) {
|
||||
for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
|
||||
const char *name = switch_xml_attr(x_list, "name");
|
||||
const char *value = switch_xml_attr(x_list, "value");
|
||||
|
||||
if (zstr(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zstr(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!reload && !strcmp(name, "total-modems")) {
|
||||
int tmp = atoi(value);
|
||||
|
||||
if (tmp > -1 && tmp < MAX_MODEMS) {
|
||||
spandsp_globals.modem_count = tmp;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%d] for total-modems\n", tmp);
|
||||
}
|
||||
} else if (!strcmp(name, "dialplan")) {
|
||||
spandsp_globals.modem_dialplan = switch_core_strdup(spandsp_globals.config_pool, value);
|
||||
} else if (!strcmp(name, "context")) {
|
||||
spandsp_globals.modem_context = switch_core_strdup(spandsp_globals.config_pool, value);
|
||||
} else if (!strcmp(name, "verbose")) {
|
||||
if (switch_true(value)) {
|
||||
spandsp_globals.modem_verbose = 1;
|
||||
} else {
|
||||
spandsp_globals.modem_verbose = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((x_lists = switch_xml_child(cfg, "fax-settings")) || (x_lists = switch_xml_child(cfg, "settings"))) {
|
||||
for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
|
||||
const char *name = switch_xml_attr(x_list, "name");
|
||||
const char *value = switch_xml_attr(x_list, "value");
|
||||
|
||||
if (zstr(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zstr(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "use-ecm")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.use_ecm = 1;
|
||||
else
|
||||
spandsp_globals.use_ecm = 0;
|
||||
} else if (!strcmp(name, "verbose")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.verbose = 1;
|
||||
else
|
||||
spandsp_globals.verbose = 0;
|
||||
} else if (!strcmp(name, "disable-v17")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.disable_v17 = 1;
|
||||
else
|
||||
spandsp_globals.disable_v17 = 0;
|
||||
} else if (!strcmp(name, "enable-t38")) {
|
||||
if (switch_true(value)) {
|
||||
spandsp_globals.enable_t38= 1;
|
||||
} else {
|
||||
spandsp_globals.enable_t38 = 0;
|
||||
}
|
||||
} else if (!strcmp(name, "enable-t38-request")) {
|
||||
if (switch_true(value)) {
|
||||
spandsp_globals.enable_t38_request = 1;
|
||||
} else {
|
||||
spandsp_globals.enable_t38_request = 0;
|
||||
}
|
||||
} else if (!strcmp(name, "ident")) {
|
||||
spandsp_globals.ident = switch_core_strdup(spandsp_globals.config_pool, value);
|
||||
} else if (!strcmp(name, "header")) {
|
||||
spandsp_globals.header = switch_core_strdup(spandsp_globals.config_pool, value);
|
||||
} else if (!strcmp(name, "spool-dir")) {
|
||||
spandsp_globals.spool = switch_core_strdup(spandsp_globals.config_pool, value);
|
||||
} else if (!strcmp(name, "file-prefix")) {
|
||||
spandsp_globals.prepend_string = switch_core_strdup(spandsp_globals.config_pool, value);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown parameter %s\n", name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure call progress detector */
|
||||
if ((callprogress = switch_xml_child(cfg, "descriptors"))) {
|
||||
for (xdescriptor = switch_xml_child(callprogress, "descriptor"); xdescriptor; xdescriptor = switch_xml_next(xdescriptor)) {
|
||||
const char *name = switch_xml_attr(xdescriptor, "name");
|
||||
const char *tone_name = NULL;
|
||||
switch_xml_t tone = NULL, element = NULL;
|
||||
tone_descriptor_t *descriptor = NULL;
|
||||
|
||||
/* create descriptor */
|
||||
if (zstr(name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <descriptor> name\n");
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s\n", name);
|
||||
if (tone_descriptor_create(&descriptor, name, spandsp_globals.config_pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to allocate tone_descriptor: %s\n", name);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_core_hash_insert(spandsp_globals.tones, name, descriptor);
|
||||
|
||||
/* add tones to descriptor */
|
||||
for (tone = switch_xml_child(xdescriptor, "tone"); tone; tone = switch_xml_next(tone)) {
|
||||
int id = 0;
|
||||
tone_name = switch_xml_attr(tone, "name");
|
||||
if (zstr(tone_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <tone> name for <descriptor> %s\n", name);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
id = tone_descriptor_add_tone(descriptor, tone_name);
|
||||
if (id == -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Unable to add tone_descriptor: %s, tone: %s. (too many tones)\n", name, tone_name);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||
"Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
|
||||
/* add elements to tone */
|
||||
for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
|
||||
const char *freq1_attr = switch_xml_attr(element, "freq1");
|
||||
const char *freq2_attr = switch_xml_attr(element, "freq2");
|
||||
const char *min_attr = switch_xml_attr(element, "min");
|
||||
const char *max_attr = switch_xml_attr(element, "max");
|
||||
int freq1, freq2, min, max;
|
||||
if (zstr(freq1_attr)) {
|
||||
freq1 = 0;
|
||||
} else {
|
||||
freq1 = atoi(freq1_attr);
|
||||
}
|
||||
if (zstr(freq2_attr)) {
|
||||
freq2 = 0;
|
||||
} else {
|
||||
freq2 = atoi(freq2_attr);
|
||||
}
|
||||
if (zstr(min_attr)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Missing min in <element> of <descriptor> %s <tone> %s(%d)\n", name, tone_name, id);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
min = atoi(min_attr);
|
||||
if (zstr(max_attr)) {
|
||||
max = 0;
|
||||
} else {
|
||||
max = atoi(max_attr);
|
||||
}
|
||||
/* check params */
|
||||
if ((freq1 < 0 || freq2 < 0 || min < 0 || max < 0) || (freq1 == 0 && min == 0 && max == 0)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid element param.\n");
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||
"Adding tone_descriptor: %s, tone: %s(%d), element (%d, %d, %d, %d)\n", name, tone_name, id, freq1, freq2, min, max);
|
||||
tone_descriptor_add_tone_element(descriptor, id, freq1, freq2, min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(spandsp_globals.mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
|
||||
memset(&spandsp_globals, 0, sizeof(spandsp_globals));
|
||||
spandsp_globals.pool = pool;
|
||||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
switch_mutex_init(&spandsp_globals.mutex, SWITCH_MUTEX_NESTED, pool);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "t38_gateway", "Convert to T38 Gateway if tones are heard", "Convert to T38 Gateway if tones are heard",
|
||||
t38_gateway_function, "", SAF_MEDIA_TAP);
|
||||
@@ -270,14 +544,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
|
||||
SWITCH_ADD_APP(app_interface, "spandsp_start_dtmf", "Detect dtmf", "Detect inband dtmf on the session", dtmf_session_function, "", SAF_MEDIA_TAP);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "spandsp_start_fax_detect", "start fax detect", "start fax detect", spandsp_fax_detect_session_function,
|
||||
"<app>[ <arg>][ <timeout>]", SAF_NONE);
|
||||
"<app>[ <arg>][ <timeout>][ <tone_type>]", SAF_NONE);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "spandsp_stop_fax_detect", "stop fax detect", "stop fax detect", spandsp_stop_fax_detect_session_function, "", SAF_NONE);
|
||||
|
||||
load_configuration(0);
|
||||
|
||||
mod_spandsp_fax_load(pool);
|
||||
mod_spandsp_codecs_load(module_interface, pool);
|
||||
|
||||
|
||||
if (mod_spandsp_dsp_load(module_interface, pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load or process spandsp.conf, not adding tone_detect applications\n");
|
||||
} else {
|
||||
@@ -292,6 +568,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
|
||||
/* Not such severe to prevent loading */
|
||||
}
|
||||
|
||||
|
||||
modem_global_init(module_interface, pool);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mod_spandsp loaded, using spandsp library version [%s]\n", SPANDSP_RELEASE_DATETIME_STRING);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -303,6 +582,15 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_spandsp_shutdown)
|
||||
|
||||
mod_spandsp_fax_shutdown();
|
||||
mod_spandsp_dsp_shutdown();
|
||||
modem_global_shutdown();
|
||||
|
||||
if (spandsp_globals.tones) {
|
||||
switch_core_hash_destroy(&spandsp_globals.tones);
|
||||
}
|
||||
|
||||
if (spandsp_globals.config_pool) {
|
||||
switch_core_destroy_memory_pool(&spandsp_globals.config_pool);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
@@ -42,9 +42,41 @@ typedef HANDLE zap_socket_t;
|
||||
typedef int zap_socket_t;
|
||||
#endif
|
||||
|
||||
#define MAX_MODEMS 1024
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
#include <spandsp.h>
|
||||
|
||||
/* The global stuff */
|
||||
struct spandsp_globals {
|
||||
switch_memory_pool_t *pool;
|
||||
switch_memory_pool_t *config_pool;
|
||||
switch_mutex_t *mutex;
|
||||
|
||||
uint32_t total_sessions;
|
||||
|
||||
short int use_ecm;
|
||||
short int verbose;
|
||||
short int disable_v17;
|
||||
short int enable_t38;
|
||||
short int enable_t38_request;
|
||||
short int enable_t38_insist;
|
||||
char *ident;
|
||||
char *header;
|
||||
char *timezone;
|
||||
char *prepend_string;
|
||||
char *spool;
|
||||
switch_thread_cond_t *cond;
|
||||
switch_mutex_t *cond_mutex;
|
||||
int modem_count;
|
||||
int modem_verbose;
|
||||
char *modem_context;
|
||||
char *modem_dialplan;
|
||||
switch_hash_t *tones;
|
||||
int tonedebug;
|
||||
};
|
||||
|
||||
extern struct spandsp_globals spandsp_globals;
|
||||
|
||||
|
||||
typedef enum {
|
||||
FUNCTION_TX,
|
||||
@@ -52,6 +84,37 @@ typedef enum {
|
||||
FUNCTION_GW
|
||||
} mod_spandsp_fax_application_mode_t;
|
||||
|
||||
/******************************************************************************
|
||||
* TONE DETECTION WITH CADENCE
|
||||
*/
|
||||
|
||||
#define MAX_TONES 32
|
||||
#define STRLEN 128
|
||||
/**
|
||||
* Tone descriptor
|
||||
*
|
||||
* Defines a set of tones to look for
|
||||
*/
|
||||
struct tone_descriptor {
|
||||
/** The name of this descriptor set */
|
||||
const char *name;
|
||||
|
||||
/** Describes the tones to watch */
|
||||
super_tone_rx_descriptor_t *spandsp_tone_descriptor;
|
||||
|
||||
/** The mapping of tone id to key */
|
||||
char tone_keys[MAX_TONES][STRLEN];
|
||||
int idx;
|
||||
|
||||
};
|
||||
typedef struct tone_descriptor tone_descriptor_t;
|
||||
|
||||
|
||||
switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool);
|
||||
int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *name);
|
||||
switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max);
|
||||
|
||||
|
||||
void mod_spandsp_fax_load(switch_memory_pool_t *pool);
|
||||
switch_status_t mod_spandsp_codecs_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
|
||||
switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
|
||||
@@ -70,7 +133,10 @@ switch_status_t callprogress_detector_start(switch_core_session_t *session, cons
|
||||
switch_status_t callprogress_detector_stop(switch_core_session_t *session);
|
||||
|
||||
switch_status_t spandsp_fax_detect_session(switch_core_session_t *session,
|
||||
const char *flags, time_t timeout,
|
||||
const char *flags, int timeout, int tone_type,
|
||||
int hits, const char *app, const char *data, switch_tone_detect_callback_t callback);
|
||||
|
||||
switch_status_t spandsp_fax_stop_detect_session(switch_core_session_t *session);
|
||||
void spanfax_log_message(int level, const char *msg);
|
||||
switch_status_t load_configuration(switch_bool_t reload);
|
||||
void mod_spandsp_indicate_data(switch_core_session_t *session, switch_bool_t self, switch_bool_t on);
|
||||
|
||||
@@ -52,11 +52,12 @@ static void spandsp_dtmf_rx_realtime_callback(void *user_data, int code, int lev
|
||||
if (digit) {
|
||||
/* prevent duplicate DTMF */
|
||||
if (digit != pvt->last_digit || (pvt->samples - pvt->last_digit_end) > pvt->min_dup_digit_spacing) {
|
||||
switch_dtmf_t dtmf;
|
||||
switch_dtmf_t dtmf = {0};
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "DTMF BEGIN DETECTED: [%c]\n", digit);
|
||||
pvt->last_digit = digit;
|
||||
dtmf.digit = digit;
|
||||
dtmf.duration = switch_core_default_dtmf_duration(0);
|
||||
dtmf.source = SWITCH_DTMF_INBAND_AUDIO;
|
||||
switch_channel_queue_dtmf(switch_core_session_get_channel(pvt->session), &dtmf);
|
||||
pvt->digit_begin = pvt->samples;
|
||||
} else {
|
||||
@@ -154,48 +155,7 @@ switch_status_t spandsp_inband_dtmf_session(switch_core_session_t *session)
|
||||
/* private channel data */
|
||||
#define TONE_PRIVATE "mod_tone_detect_bug"
|
||||
|
||||
/**
|
||||
* Module global variables
|
||||
*/
|
||||
struct globals {
|
||||
/** Memory pool */
|
||||
switch_memory_pool_t *pool;
|
||||
/** Call progress tones mapped by descriptor name */
|
||||
switch_hash_t *tones;
|
||||
/** Default debug level */
|
||||
int debug;
|
||||
};
|
||||
typedef struct globals globals_t;
|
||||
static globals_t globals;
|
||||
|
||||
/******************************************************************************
|
||||
* TONE DETECTION WITH CADENCE
|
||||
*/
|
||||
|
||||
#define MAX_TONES 32
|
||||
#define STRLEN 128
|
||||
/**
|
||||
* Tone descriptor
|
||||
*
|
||||
* Defines a set of tones to look for
|
||||
*/
|
||||
struct tone_descriptor {
|
||||
/** The name of this descriptor set */
|
||||
const char *name;
|
||||
|
||||
/** Describes the tones to watch */
|
||||
super_tone_rx_descriptor_t *spandsp_tone_descriptor;
|
||||
|
||||
/** The mapping of tone id to key */
|
||||
char tone_keys[MAX_TONES][STRLEN];
|
||||
int idx;
|
||||
|
||||
};
|
||||
typedef struct tone_descriptor tone_descriptor_t;
|
||||
|
||||
static switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool);
|
||||
static int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *name);
|
||||
static switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max);
|
||||
|
||||
/**
|
||||
* Tone detector
|
||||
@@ -231,7 +191,7 @@ static switch_bool_t callprogress_detector_process_buffer(switch_media_bug_t *bu
|
||||
* @param memory_pool the pool to use
|
||||
* @return SWITCH_STATUS_SUCCESS if successful
|
||||
*/
|
||||
static switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool)
|
||||
switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool)
|
||||
{
|
||||
tone_descriptor_t *ldescriptor = NULL;
|
||||
ldescriptor = switch_core_alloc(memory_pool, sizeof(tone_descriptor_t));
|
||||
@@ -252,7 +212,7 @@ static switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, co
|
||||
* @param key the tone key - this will be returned by the detector upon match
|
||||
* @return the tone ID
|
||||
*/
|
||||
static int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *key)
|
||||
int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *key)
|
||||
{
|
||||
int id = super_tone_rx_add_tone(descriptor->spandsp_tone_descriptor);
|
||||
if (id >= MAX_TONES) {
|
||||
@@ -278,7 +238,7 @@ static int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *k
|
||||
* @param max the maximum tone duration in ms
|
||||
* @return SWITCH_STATUS_SUCCESS if successful
|
||||
*/
|
||||
static switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max)
|
||||
switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max)
|
||||
{
|
||||
if (super_tone_rx_add_element(descriptor->spandsp_tone_descriptor, tone_id, freq1, freq2, min, max) == 0) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -336,7 +296,7 @@ static switch_status_t tone_detector_create(tone_detector_t **detector, tone_des
|
||||
}
|
||||
memset(ldetector, 0, sizeof(tone_detector_t));
|
||||
ldetector->descriptor = descriptor;
|
||||
ldetector->debug = globals.debug;
|
||||
ldetector->debug = spandsp_globals.tonedebug;
|
||||
*detector = ldetector;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -408,7 +368,7 @@ switch_status_t callprogress_detector_start(switch_core_session_t *session, cons
|
||||
}
|
||||
|
||||
/* find the tone descriptor with the matching name and create the detector */
|
||||
descriptor = switch_core_hash_find(globals.tones, name);
|
||||
descriptor = switch_core_hash_find(spandsp_globals.tones, name);
|
||||
if (!descriptor) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "(%s) no tone descriptor defined with name '%s'. Update configuration. \n", switch_channel_get_name(channel), name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@@ -508,116 +468,11 @@ switch_status_t callprogress_detector_stop(switch_core_session_t *session)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process configuration file
|
||||
*/
|
||||
static switch_status_t do_config(void)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_xml_t cfg = NULL, xml = NULL, callprogress = NULL, xdescriptor = NULL;
|
||||
if (!(xml = switch_xml_open_cfg("spandsp.conf", &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not open spandsp.conf\n");
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* TODO make configuration param */
|
||||
globals.debug = 1;
|
||||
|
||||
/* Configure call progress detector */
|
||||
if ((callprogress = switch_xml_child(cfg, "descriptors"))) {
|
||||
for (xdescriptor = switch_xml_child(callprogress, "descriptor"); xdescriptor; xdescriptor = switch_xml_next(xdescriptor)) {
|
||||
const char *name = switch_xml_attr(xdescriptor, "name");
|
||||
const char *tone_name = NULL;
|
||||
switch_xml_t tone = NULL, element = NULL;
|
||||
tone_descriptor_t *descriptor = NULL;
|
||||
|
||||
/* create descriptor */
|
||||
if (zstr(name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <descriptor> name\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s\n", name);
|
||||
if (tone_descriptor_create(&descriptor, name, globals.pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to allocate tone_descriptor: %s\n", name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
switch_core_hash_insert(globals.tones, name, descriptor);
|
||||
|
||||
/* add tones to descriptor */
|
||||
for (tone = switch_xml_child(xdescriptor, "tone"); tone; tone = switch_xml_next(tone)) {
|
||||
int id = 0;
|
||||
tone_name = switch_xml_attr(tone, "name");
|
||||
if (zstr(tone_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <tone> name for <descriptor> %s\n", name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
id = tone_descriptor_add_tone(descriptor, tone_name);
|
||||
if (id == -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to add tone_descriptor: %s, tone: %s. (too many tones)\n", name, tone_name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
|
||||
/* add elements to tone */
|
||||
for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
|
||||
const char *freq1_attr = switch_xml_attr(element, "freq1");
|
||||
const char *freq2_attr = switch_xml_attr(element, "freq2");
|
||||
const char *min_attr = switch_xml_attr(element, "min");
|
||||
const char *max_attr = switch_xml_attr(element, "max");
|
||||
int freq1, freq2, min, max;
|
||||
if (zstr(freq1_attr)) {
|
||||
freq1 = 0;
|
||||
} else {
|
||||
freq1 = atoi(freq1_attr);
|
||||
}
|
||||
if (zstr(freq2_attr)) {
|
||||
freq2 = 0;
|
||||
} else {
|
||||
freq2 = atoi(freq2_attr);
|
||||
}
|
||||
if (zstr(min_attr)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing min in <element> of <descriptor> %s <tone> %s(%d)\n", name, tone_name, id);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
min = atoi(min_attr);
|
||||
if (zstr(max_attr)) {
|
||||
max = 0;
|
||||
} else {
|
||||
max = atoi(max_attr);
|
||||
}
|
||||
/* check params */
|
||||
if ((freq1 < 0 || freq2 < 0 || min < 0 || max < 0) || (freq1 == 0 && min == 0 && max == 0)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid element param.\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d), element (%d, %d, %d, %d)\n", name, tone_name, id, freq1, freq2, min, max);
|
||||
tone_descriptor_add_tone_element(descriptor, id, freq1, freq2, min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (xml) {
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when FreeSWITCH loads the module
|
||||
*/
|
||||
switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
|
||||
{
|
||||
memset(&globals, 0, sizeof(globals_t));
|
||||
globals.pool = pool;
|
||||
|
||||
switch_core_hash_init(&globals.tones, globals.pool);
|
||||
if (do_config() != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -627,7 +482,7 @@ switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module
|
||||
*/
|
||||
void mod_spandsp_dsp_shutdown(void)
|
||||
{
|
||||
switch_core_hash_destroy(&globals.tones);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,10 +39,19 @@
|
||||
#define LOCAL_FAX_MAX_DATAGRAM 400
|
||||
#define MAX_FEC_ENTRIES 4
|
||||
#define MAX_FEC_SPAN 4
|
||||
#define DEFAULT_FEC_ENTRIES 3
|
||||
#define DEFAULT_FEC_SPAN 3
|
||||
|
||||
#define SPANDSP_EVENT_TXFAXRESULT "spandsp::txfaxresult"
|
||||
#define SPANDSP_EVENT_RXFAXRESULT "spandsp::rxfaxresult"
|
||||
|
||||
#define SPANDSP_EVENT_TXFAXPAGERESULT "spandsp::txfaxpageresult"
|
||||
#define SPANDSP_EVENT_RXFAXPAGERESULT "spandsp::rxfaxpageresult"
|
||||
|
||||
#define SPANDSP_EVENT_TXFAXNEGOCIATERESULT "spandsp::txfaxnegociateresult"
|
||||
#define SPANDSP_EVENT_RXFAXNEGOCIATERESULT "spandsp::rxfaxnegociateresult"
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
OUR DEFINES AND STRUCTS
|
||||
*****************************************************************************/
|
||||
@@ -60,26 +69,6 @@ typedef enum {
|
||||
T38_MODE_REFUSED = -1,
|
||||
} t38_mode_t;
|
||||
|
||||
/* The global stuff */
|
||||
static struct {
|
||||
switch_memory_pool_t *pool;
|
||||
switch_mutex_t *mutex;
|
||||
|
||||
uint32_t total_sessions;
|
||||
|
||||
short int use_ecm;
|
||||
short int verbose;
|
||||
short int disable_v17;
|
||||
short int enable_t38;
|
||||
short int enable_t38_request;
|
||||
short int enable_t38_insist;
|
||||
char ident[20];
|
||||
char header[50];
|
||||
char *prepend_string;
|
||||
char *spool;
|
||||
switch_thread_cond_t *cond;
|
||||
switch_mutex_t *cond_mutex;
|
||||
} globals;
|
||||
|
||||
struct pvt_s {
|
||||
switch_core_session_t *session;
|
||||
@@ -96,6 +85,7 @@ struct pvt_s {
|
||||
char *filename;
|
||||
char *ident;
|
||||
char *header;
|
||||
char *timezone;
|
||||
|
||||
int use_ecm;
|
||||
int disable_v17;
|
||||
@@ -128,13 +118,13 @@ static struct {
|
||||
static void wake_thread(int force)
|
||||
{
|
||||
if (force) {
|
||||
switch_thread_cond_signal(globals.cond);
|
||||
switch_thread_cond_signal(spandsp_globals.cond);
|
||||
return;
|
||||
}
|
||||
|
||||
if (switch_mutex_trylock(globals.cond_mutex) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_thread_cond_signal(globals.cond);
|
||||
switch_mutex_unlock(globals.cond_mutex);
|
||||
if (switch_mutex_trylock(spandsp_globals.cond_mutex) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_thread_cond_signal(spandsp_globals.cond);
|
||||
switch_mutex_unlock(spandsp_globals.cond_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +196,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.cond_mutex);
|
||||
switch_mutex_lock(spandsp_globals.cond_mutex);
|
||||
|
||||
while(t38_state_list.thread_running) {
|
||||
|
||||
@@ -214,7 +204,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
|
||||
|
||||
if (!t38_state_list.head) {
|
||||
switch_mutex_unlock(t38_state_list.mutex);
|
||||
switch_thread_cond_wait(globals.cond, globals.cond_mutex);
|
||||
switch_thread_cond_wait(spandsp_globals.cond, spandsp_globals.cond_mutex);
|
||||
switch_core_timer_sync(&timer);
|
||||
continue;
|
||||
}
|
||||
@@ -230,7 +220,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
|
||||
switch_core_timer_next(&timer);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(globals.cond_mutex);
|
||||
switch_mutex_unlock(spandsp_globals.cond_mutex);
|
||||
|
||||
end:
|
||||
|
||||
@@ -252,9 +242,9 @@ static void launch_timer_thread(void)
|
||||
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
|
||||
switch_threadattr_create(&thd_attr, globals.pool);
|
||||
switch_threadattr_create(&thd_attr, spandsp_globals.pool);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_thread_create(&t38_state_list.thread, thd_attr, timer_thread_run, NULL, globals.pool);
|
||||
switch_thread_create(&t38_state_list.thread, thd_attr, timer_thread_run, NULL, spandsp_globals.pool);
|
||||
}
|
||||
|
||||
|
||||
@@ -264,12 +254,12 @@ static void launch_timer_thread(void)
|
||||
|
||||
static void counter_increment(void)
|
||||
{
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.total_sessions++;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
switch_mutex_lock(spandsp_globals.mutex);
|
||||
spandsp_globals.total_sessions++;
|
||||
switch_mutex_unlock(spandsp_globals.mutex);
|
||||
}
|
||||
|
||||
static void spanfax_log_message(int level, const char *msg)
|
||||
void spanfax_log_message(int level, const char *msg)
|
||||
{
|
||||
int fs_log_level;
|
||||
|
||||
@@ -297,6 +287,170 @@ static void spanfax_log_message(int level, const char *msg)
|
||||
}
|
||||
}
|
||||
|
||||
static int phase_b_handler(t30_state_t *s, void *user_data, int result)
|
||||
{
|
||||
t30_stats_t t30_stats;
|
||||
switch_core_session_t *session;
|
||||
switch_channel_t *channel;
|
||||
const char *local_ident;
|
||||
const char *far_ident;
|
||||
char *fax_transfer_rate = NULL;
|
||||
pvt_t *pvt;
|
||||
switch_event_t *event;
|
||||
|
||||
pvt = (pvt_t *) user_data;
|
||||
switch_assert(pvt);
|
||||
|
||||
session = pvt->session;
|
||||
switch_assert(session);
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_assert(channel);
|
||||
|
||||
t30_get_transfer_statistics(s, &t30_stats);
|
||||
|
||||
local_ident = switch_str_nil(t30_get_tx_ident(s));
|
||||
far_ident = switch_str_nil(t30_get_rx_ident(s));
|
||||
|
||||
fax_transfer_rate = switch_core_session_sprintf(session, "%i", t30_stats.bit_rate);
|
||||
if (fax_transfer_rate) {
|
||||
switch_channel_set_variable(channel, "fax_transfer_rate", fax_transfer_rate);
|
||||
}
|
||||
switch_channel_set_variable(channel, "fax_ecm_used", (t30_stats.error_correcting_mode) ? "on" : "off");
|
||||
switch_channel_set_variable(channel, "fax_local_station_id", local_ident);
|
||||
switch_channel_set_variable(channel, "fax_remote_station_id", far_ident);
|
||||
switch_channel_set_variable(channel, "fax_remote_country", switch_str_nil(t30_get_rx_country(s)));
|
||||
switch_channel_set_variable(channel, "fax_remote_vendor", switch_str_nil(t30_get_rx_vendor(s)));
|
||||
switch_channel_set_variable(channel, "fax_remote_model", switch_str_nil(t30_get_rx_model(s)));
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "=== Negotiation Result =======================================================\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote station id: %s\n", far_ident);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local station id: %s\n", local_ident);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer Rate: %i\n", t30_stats.bit_rate);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "ECM status %s\n", (t30_stats.error_correcting_mode) ? "on" : "off");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote country: %s\n", switch_str_nil(t30_get_rx_country(s)));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote vendor: %s\n", switch_str_nil(t30_get_rx_vendor(s)));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote model: %s\n", switch_str_nil(t30_get_rx_model(s)));
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "==============================================================================\n");
|
||||
|
||||
switch_channel_execute_on(channel, "execute_on_fax_phase_b");
|
||||
|
||||
/* Fire event */
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, pvt->app_mode == FUNCTION_TX ? SPANDSP_EVENT_TXFAXNEGOCIATERESULT : SPANDSP_EVENT_RXFAXNEGOCIATERESULT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-transfer-rate", fax_transfer_rate);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-ecm-used", (t30_stats.error_correcting_mode) ? "on" : "off");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-local-station-id", local_ident);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-station-id", far_ident);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-country", switch_str_nil(t30_get_rx_country(s)));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-vendor", switch_str_nil(t30_get_rx_vendor(s)));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-model", switch_str_nil(t30_get_rx_model(s)));
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return T30_ERR_OK;
|
||||
}
|
||||
|
||||
static int phase_d_handler(t30_state_t *s, void *user_data, int msg)
|
||||
{
|
||||
t4_stats_t t4_stats;
|
||||
char *fax_image_resolution = NULL;
|
||||
char *fax_image_size = NULL;
|
||||
char *fax_image_pixel_size = NULL;
|
||||
char *fax_bad_rows = NULL;
|
||||
char *fax_encoding = NULL;
|
||||
char *fax_longest_bad_row_run = NULL;
|
||||
char *fax_document_transferred_pages = NULL;
|
||||
switch_core_session_t *session;
|
||||
switch_channel_t *channel;
|
||||
pvt_t *pvt;
|
||||
switch_event_t *event;
|
||||
|
||||
pvt = (pvt_t *) user_data;
|
||||
switch_assert(pvt);
|
||||
|
||||
session = pvt->session;
|
||||
switch_assert(session);
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_assert(channel);
|
||||
|
||||
if (pvt->app_mode == FUNCTION_TX) {
|
||||
t4_tx_get_transfer_statistics(&s->t4.tx, &t4_stats);
|
||||
} else {
|
||||
t4_rx_get_transfer_statistics(&s->t4.rx, &t4_stats);
|
||||
}
|
||||
|
||||
/* Set Channel Variable */
|
||||
|
||||
fax_image_resolution = switch_core_session_sprintf(session, "%ix%i", t4_stats.x_resolution, t4_stats.y_resolution);
|
||||
if (fax_image_resolution) {
|
||||
switch_channel_set_variable(channel, "fax_image_resolution", fax_image_resolution);
|
||||
}
|
||||
|
||||
fax_image_pixel_size = switch_core_session_sprintf(session, "%ix%i", t4_stats.width, t4_stats.length);
|
||||
if (fax_image_pixel_size) {
|
||||
switch_channel_set_variable(channel, "fax_image_pixel_size", fax_image_pixel_size);;
|
||||
}
|
||||
|
||||
fax_image_size = switch_core_session_sprintf(session, "%d", t4_stats.line_image_size);
|
||||
if (fax_image_size) {
|
||||
switch_channel_set_variable(channel, "fax_image_size", fax_image_size);
|
||||
}
|
||||
|
||||
fax_bad_rows = switch_core_session_sprintf(session, "%d", t4_stats.bad_rows);
|
||||
if (fax_bad_rows) {
|
||||
switch_channel_set_variable(channel, "fax_bad_rows", fax_bad_rows);
|
||||
}
|
||||
|
||||
fax_longest_bad_row_run = switch_core_session_sprintf(session, "%d", t4_stats.longest_bad_row_run);
|
||||
if (fax_longest_bad_row_run) {
|
||||
switch_channel_set_variable(channel, "fax_longest_bad_row_run", fax_longest_bad_row_run);
|
||||
}
|
||||
|
||||
fax_encoding = switch_core_session_sprintf(session, "%d", t4_stats.encoding);
|
||||
if (fax_encoding) {
|
||||
switch_channel_set_variable(channel, "fax_encoding", fax_encoding);
|
||||
}
|
||||
|
||||
switch_channel_set_variable(channel, "fax_encoding_name", t4_encoding_to_str(t4_stats.encoding));
|
||||
|
||||
fax_document_transferred_pages = switch_core_session_sprintf(session, "%d", t4_stats.pages_transferred);
|
||||
if (fax_document_transferred_pages) {
|
||||
switch_channel_set_variable(channel, "fax_document_transferred_pages", fax_document_transferred_pages);
|
||||
}
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "==== Page %s===========================================================\n", pvt->app_mode == FUNCTION_TX ? "Sent ====": "Received ");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Page no = %d\n", t4_stats.pages_transferred);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Image size = %d x %d pixels\n", t4_stats.width, t4_stats.length);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Image resolution = %d/m x %d/m\n", t4_stats.x_resolution, t4_stats.y_resolution);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Compression = %s (%d)\n", t4_encoding_to_str(t4_stats.encoding), t4_stats.encoding);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Compressed image size = %d bytes\n", t4_stats.line_image_size);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad rows = %d\n", t4_stats.bad_rows);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Longest bad row run = %d\n", t4_stats.longest_bad_row_run);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "==============================================================================\n");
|
||||
|
||||
switch_channel_execute_on(channel, "execute_on_fax_phase_d");
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, pvt->app_mode == FUNCTION_TX ? SPANDSP_EVENT_TXFAXPAGERESULT : SPANDSP_EVENT_RXFAXPAGERESULT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-document-transferred-pages", fax_document_transferred_pages);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-image-resolution", fax_image_resolution);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-image-size", fax_image_size);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-image-pixel-size", fax_image_pixel_size);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-bad-rows", fax_bad_rows);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-longest-bad-row-run", fax_longest_bad_row_run);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-encoding", fax_encoding);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-encoding-name", t4_encoding_to_str(t4_stats.encoding));
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return T30_ERR_OK; /* I don't think this does anything */
|
||||
}
|
||||
|
||||
/*
|
||||
* Called at the end of the document
|
||||
*/
|
||||
@@ -316,6 +470,8 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
|
||||
char *fax_transfer_rate = NULL;
|
||||
char *fax_result_code = NULL;
|
||||
switch_event_t *event;
|
||||
const char *var;
|
||||
char *expanded;
|
||||
|
||||
pvt = (pvt_t *) user_data;
|
||||
switch_assert(pvt);
|
||||
@@ -432,14 +588,36 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "system_on_fax_result"))) {
|
||||
expanded = switch_channel_expand_variables(channel, var);
|
||||
switch_system(expanded, SWITCH_FALSE);
|
||||
if (expanded != var) {
|
||||
free(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
switch_channel_execute_on(channel, "execute_on_fax_result");
|
||||
|
||||
if (result == T30_ERR_OK) {
|
||||
if ((var = switch_channel_get_variable(channel, "system_on_fax_success"))) {
|
||||
expanded = switch_channel_expand_variables(channel, var);
|
||||
switch_system(expanded, SWITCH_FALSE);
|
||||
if (expanded != var) {
|
||||
free(expanded);
|
||||
}
|
||||
}
|
||||
switch_channel_execute_on(channel, "execute_on_fax_success");
|
||||
} else {
|
||||
if ((var = switch_channel_get_variable(channel, "system_on_fax_failure"))) {
|
||||
expanded = switch_channel_expand_variables(channel, var);
|
||||
switch_system(expanded, SWITCH_FALSE);
|
||||
if (expanded != var) {
|
||||
free(expanded);
|
||||
}
|
||||
}
|
||||
switch_channel_execute_on(channel, "execute_on_fax_failure");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
|
||||
@@ -494,6 +672,9 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
fax_state_t *fax;
|
||||
t38_terminal_state_t *t38;
|
||||
t30_state_t *t30;
|
||||
const char *tmp;
|
||||
int fec_entries = DEFAULT_FEC_ENTRIES;
|
||||
int fec_span = DEFAULT_FEC_SPAN;
|
||||
|
||||
|
||||
session = (switch_core_session_t *) pvt->session;
|
||||
@@ -502,6 +683,13 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_assert(channel);
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "t38_gateway_redundancy"))) {
|
||||
int tmp_value;
|
||||
tmp_value = atoi(tmp);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX changing redundancy from %d:%d to %d:%d\n", fec_span, fec_entries, tmp_value, tmp_value );
|
||||
fec_entries = tmp_value;
|
||||
fec_span = tmp_value;
|
||||
}
|
||||
|
||||
switch (trans_mode) {
|
||||
case AUDIO_MODE:
|
||||
@@ -562,7 +750,7 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
|
||||
pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state);
|
||||
|
||||
if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3,
|
||||
if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, fec_span, fec_entries,
|
||||
(udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@@ -607,7 +795,7 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
|
||||
pvt->t38_core = t38_gateway_get_t38_core_state(pvt->t38_gateway_state);
|
||||
|
||||
if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3,
|
||||
if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, fec_span, fec_entries,
|
||||
(udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n");
|
||||
t38_gateway_free(pvt->t38_gateway_state);
|
||||
@@ -655,8 +843,12 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
/* All the things which are common to audio and T.38 FAX setup */
|
||||
t30_set_tx_ident(t30, pvt->ident);
|
||||
t30_set_tx_page_header_info(t30, pvt->header);
|
||||
if (pvt->timezone && pvt->timezone[0])
|
||||
t30_set_tx_page_header_tz(t30, pvt->timezone);
|
||||
|
||||
t30_set_phase_e_handler(t30, phase_e_handler, pvt);
|
||||
t30_set_phase_d_handler(t30, phase_d_handler, pvt);
|
||||
t30_set_phase_b_handler(t30, phase_b_handler, pvt);
|
||||
|
||||
t30_set_supported_image_sizes(t30,
|
||||
T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH
|
||||
@@ -797,7 +989,7 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
|
||||
} else if ((v = switch_channel_get_variable(channel, "fax_enable_t38"))) {
|
||||
enabled = switch_true(v);
|
||||
} else {
|
||||
enabled = globals.enable_t38;
|
||||
enabled = spandsp_globals.enable_t38;
|
||||
}
|
||||
|
||||
if (!(enabled && t38_options)) {
|
||||
@@ -806,7 +998,9 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
|
||||
switch_channel_set_private(channel, "t38_options", NULL);
|
||||
} else {
|
||||
pvt->t38_mode = T38_MODE_NEGOTIATED;
|
||||
|
||||
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_NEGOTIATED);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "T38 SDP Origin = %s\n", t38_options->sdp_o_line);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "T38FaxVersion = %d\n", t38_options->T38FaxVersion);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "T38MaxBitRate = %d\n", t38_options->T38MaxBitRate);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "T38FaxFillBitRemoval = %d\n", t38_options->T38FaxFillBitRemoval);
|
||||
@@ -827,7 +1021,14 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
|
||||
t38_options->T38FaxVersion = 3;
|
||||
}
|
||||
t38_options->T38MaxBitRate = (pvt->disable_v17) ? 9600 : 14400;
|
||||
t38_options->T38FaxFillBitRemoval = 1;
|
||||
|
||||
/* cisco gets mad when we set this to one in a response where they set it to 0, are we allowed to hardcode this to 1 on responses? */
|
||||
/*
|
||||
if (!zstr(t38_options->sdp_o_line) && !switch_stristr("cisco", t38_options->sdp_o_line)) {
|
||||
t38_options->T38FaxFillBitRemoval = 1;
|
||||
}
|
||||
*/
|
||||
|
||||
t38_options->T38FaxTranscodingMMR = 0;
|
||||
t38_options->T38FaxTranscodingJBIG = 0;
|
||||
t38_options->T38FaxRateManagement = "transferredTCF";
|
||||
@@ -846,7 +1047,7 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
|
||||
if ((v = switch_channel_get_variable(channel, "fax_enable_t38_insist"))) {
|
||||
insist = switch_true(v);
|
||||
} else {
|
||||
insist = globals.enable_t38_insist;
|
||||
insist = spandsp_globals.enable_t38_insist;
|
||||
}
|
||||
|
||||
/* This will send the options back in a response */
|
||||
@@ -876,14 +1077,14 @@ static t38_mode_t request_t38(pvt_t *pvt)
|
||||
} else if ((v = switch_channel_get_variable(channel, "fax_enable_t38"))) {
|
||||
enabled = switch_true(v);
|
||||
} else {
|
||||
enabled = globals.enable_t38;
|
||||
enabled = spandsp_globals.enable_t38;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
if ((v = switch_channel_get_variable(channel, "fax_enable_t38_request"))) {
|
||||
enabled = switch_true(v);
|
||||
} else {
|
||||
enabled = globals.enable_t38_request;
|
||||
enabled = spandsp_globals.enable_t38_request;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,7 +1092,7 @@ static t38_mode_t request_t38(pvt_t *pvt)
|
||||
if ((v = switch_channel_get_variable(channel, "fax_enable_t38_insist"))) {
|
||||
insist = switch_true(v);
|
||||
} else {
|
||||
insist = globals.enable_t38_insist;
|
||||
insist = spandsp_globals.enable_t38_insist;
|
||||
}
|
||||
|
||||
if ((t38_options = switch_channel_get_private(channel, "t38_options"))) {
|
||||
@@ -973,19 +1174,19 @@ static pvt_t *pvt_init(switch_core_session_t *session, mod_spandsp_fax_applicati
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_use_ecm"))) {
|
||||
pvt->use_ecm = switch_true(tmp);
|
||||
} else {
|
||||
pvt->use_ecm = globals.use_ecm;
|
||||
pvt->use_ecm = spandsp_globals.use_ecm;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_disable_v17"))) {
|
||||
pvt->disable_v17 = switch_true(tmp);
|
||||
} else {
|
||||
pvt->disable_v17 = globals.disable_v17;
|
||||
pvt->disable_v17 = spandsp_globals.disable_v17;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_verbose"))) {
|
||||
pvt->verbose = switch_true(tmp);
|
||||
} else {
|
||||
pvt->verbose = globals.verbose;
|
||||
pvt->verbose = spandsp_globals.verbose;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_force_caller"))) {
|
||||
@@ -997,15 +1198,39 @@ static pvt_t *pvt_init(switch_core_session_t *session, mod_spandsp_fax_applicati
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_ident"))) {
|
||||
pvt->ident = switch_core_session_strdup(session, tmp);
|
||||
char *data = NULL;
|
||||
|
||||
data = strdup(tmp);
|
||||
switch_url_decode(data);
|
||||
pvt->ident = switch_core_session_strdup(session, data);
|
||||
|
||||
switch_safe_free(data);
|
||||
} else {
|
||||
pvt->ident = switch_core_session_strdup(session, globals.ident);
|
||||
pvt->ident = switch_core_session_strdup(session, spandsp_globals.ident);
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_header"))) {
|
||||
pvt->header = switch_core_session_strdup(session, tmp);
|
||||
char *data = NULL;
|
||||
|
||||
data = strdup(tmp);
|
||||
switch_url_decode(data);
|
||||
pvt->header = switch_core_session_strdup(session, data);
|
||||
|
||||
switch_safe_free(data);
|
||||
} else {
|
||||
pvt->header = switch_core_session_strdup(session, globals.header);
|
||||
pvt->header = switch_core_session_strdup(session, spandsp_globals.header);
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_timezone"))) {
|
||||
char *data = NULL;
|
||||
|
||||
data = strdup(tmp);
|
||||
switch_url_decode(data);
|
||||
pvt->timezone = switch_core_session_strdup(session, data);
|
||||
|
||||
switch_safe_free(data);
|
||||
} else {
|
||||
pvt->timezone = switch_core_session_strdup(session, spandsp_globals.timezone);
|
||||
}
|
||||
|
||||
if (pvt->app_mode == FUNCTION_TX) {
|
||||
@@ -1075,10 +1300,10 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
|
||||
time = switch_time_now();
|
||||
|
||||
if (!(prefix = switch_channel_get_variable(channel, "fax_prefix"))) {
|
||||
prefix = globals.prepend_string;
|
||||
prefix = spandsp_globals.prepend_string;
|
||||
}
|
||||
|
||||
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%ld.tif", globals.spool, prefix, globals.total_sessions, time))) {
|
||||
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%ld.tif", spandsp_globals.spool, prefix, spandsp_globals.total_sessions, time))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot automatically set fax RX destination file\n");
|
||||
goto done;
|
||||
}
|
||||
@@ -1192,6 +1417,7 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
|
||||
} else if (switch_channel_test_app_flag_key("T38", channel, CF_APP_T38)) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
pvt->t38_mode = T38_MODE_NEGOTIATED;
|
||||
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_NEGOTIATED);
|
||||
spanfax_init(pvt, T38_MODE);
|
||||
configure_t38(pvt);
|
||||
|
||||
@@ -1294,108 +1520,18 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
CONFIGURATION
|
||||
************************************************************************* */
|
||||
|
||||
void load_configuration(switch_bool_t reload)
|
||||
{
|
||||
switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL;
|
||||
|
||||
if ((xml = switch_xml_open_cfg("fax.conf", &cfg, NULL))) {
|
||||
if ((x_lists = switch_xml_child(cfg, "settings"))) {
|
||||
for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
|
||||
const char *name = switch_xml_attr(x_list, "name");
|
||||
const char *value = switch_xml_attr(x_list, "value");
|
||||
|
||||
if (zstr(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zstr(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "use-ecm")) {
|
||||
if (switch_true(value))
|
||||
globals.use_ecm = 1;
|
||||
else
|
||||
globals.use_ecm = 0;
|
||||
} else if (!strcmp(name, "verbose")) {
|
||||
if (switch_true(value))
|
||||
globals.verbose = 1;
|
||||
else
|
||||
globals.verbose = 0;
|
||||
} else if (!strcmp(name, "disable-v17")) {
|
||||
if (switch_true(value))
|
||||
globals.disable_v17 = 1;
|
||||
else
|
||||
globals.disable_v17 = 0;
|
||||
} else if (!strcmp(name, "enable-t38")) {
|
||||
if (switch_true(value)) {
|
||||
globals.enable_t38= 1;
|
||||
} else {
|
||||
globals.enable_t38 = 0;
|
||||
}
|
||||
} else if (!strcmp(name, "enable-t38-request")) {
|
||||
if (switch_true(value)) {
|
||||
globals.enable_t38_request = 1;
|
||||
} else {
|
||||
globals.enable_t38_request = 0;
|
||||
}
|
||||
} else if (!strcmp(name, "ident")) {
|
||||
strncpy(globals.ident, value, sizeof(globals.ident) - 1);
|
||||
} else if (!strcmp(name, "header")) {
|
||||
strncpy(globals.header, value, sizeof(globals.header) - 1);
|
||||
} else if (!strcmp(name, "spool-dir")) {
|
||||
globals.spool = switch_core_strdup(globals.pool, value);
|
||||
} else if (!strcmp(name, "file-prefix")) {
|
||||
globals.prepend_string = switch_core_strdup(globals.pool, value);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown parameter %s\n", name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
}
|
||||
|
||||
void mod_spandsp_fax_event_handler(switch_event_t *event)
|
||||
{
|
||||
load_configuration(1);
|
||||
}
|
||||
|
||||
|
||||
void mod_spandsp_fax_load(switch_memory_pool_t *pool)
|
||||
{
|
||||
uint32_t sanity = 200;
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
memset(&t38_state_list, 0, sizeof(t38_state_list));
|
||||
|
||||
globals.pool = pool;
|
||||
switch_mutex_init(&spandsp_globals.mutex, SWITCH_MUTEX_NESTED, spandsp_globals.pool);
|
||||
switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, spandsp_globals.pool);
|
||||
|
||||
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
switch_mutex_init(&globals.cond_mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
switch_thread_cond_create(&globals.cond, globals.pool);
|
||||
switch_mutex_init(&spandsp_globals.cond_mutex, SWITCH_MUTEX_NESTED, spandsp_globals.pool);
|
||||
switch_thread_cond_create(&spandsp_globals.cond, spandsp_globals.pool);
|
||||
|
||||
globals.enable_t38 = 1;
|
||||
globals.total_sessions = 0;
|
||||
globals.verbose = 1;
|
||||
globals.use_ecm = 1;
|
||||
globals.disable_v17 = 0;
|
||||
globals.prepend_string = switch_core_strdup(globals.pool, "fax");
|
||||
globals.spool = switch_core_strdup(globals.pool, "/tmp");
|
||||
strncpy(globals.ident, "SpanDSP Fax Ident", sizeof(globals.ident) - 1);
|
||||
strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1);
|
||||
|
||||
load_configuration(0);
|
||||
|
||||
|
||||
launch_timer_thread();
|
||||
|
||||
while(--sanity && !t38_state_list.thread_running) {
|
||||
@@ -1410,7 +1546,7 @@ void mod_spandsp_fax_shutdown(void)
|
||||
t38_state_list.thread_running = 0;
|
||||
wake_thread(1);
|
||||
switch_thread_join(&tstatus, t38_state_list.thread);
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
memset(&spandsp_globals, 0, sizeof(spandsp_globals));
|
||||
}
|
||||
|
||||
static const switch_state_handler_table_t t38_gateway_state_handlers;
|
||||
@@ -1474,13 +1610,14 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio
|
||||
spanfax_init(pvt, T38_GATEWAY_MODE);
|
||||
configure_t38(pvt);
|
||||
pvt->t38_mode = T38_MODE_NEGOTIATED;
|
||||
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_NEGOTIATED);
|
||||
} else {
|
||||
if (negotiate_t38(pvt) != T38_MODE_NEGOTIATED) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Could not negotiate T38\n", switch_channel_get_name(channel));
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
goto end_unlock;
|
||||
}
|
||||
|
||||
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_NEGOTIATED);
|
||||
spanfax_init(pvt, T38_GATEWAY_MODE);
|
||||
}
|
||||
|
||||
@@ -1570,6 +1707,8 @@ static switch_status_t t38_gateway_on_consume_media(switch_core_session_t *sessi
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridge-A-Unique-ID", switch_core_session_get_uuid(session));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridge-B-Unique-ID", peer_uuid);
|
||||
switch_channel_event_set_data(channel, event);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
@@ -1838,6 +1977,7 @@ typedef struct {
|
||||
char *data;
|
||||
char *key;
|
||||
int up;
|
||||
int tone_type;
|
||||
int total_hits;
|
||||
int hits;
|
||||
int sleep;
|
||||
@@ -1887,7 +2027,7 @@ static switch_bool_t tone_detect_callback(switch_media_bug_t *bug, void *user_da
|
||||
case SWITCH_ABC_TYPE_INIT:
|
||||
if (cont) {
|
||||
cont->bug_running = 1;
|
||||
modem_connect_tones_rx_init(&cont->rx_tones, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL);
|
||||
modem_connect_tones_rx_init(&cont->rx_tones, cont->tone_type, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
@@ -1995,17 +2135,22 @@ switch_status_t spandsp_fax_stop_detect_session(switch_core_session_t *session)
|
||||
}
|
||||
|
||||
switch_status_t spandsp_fax_detect_session(switch_core_session_t *session,
|
||||
const char *flags, time_t timeout,
|
||||
const char *flags, int timeout, int tone_type,
|
||||
int hits, const char *app, const char *data, switch_tone_detect_callback_t callback)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_status_t status;
|
||||
time_t to = 0;
|
||||
spandsp_fax_tone_container_t *cont = switch_channel_get_private(channel, "_fax_tone_detect_");
|
||||
switch_media_bug_flag_t bflags = 0;
|
||||
const char *var;
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
if (timeout) {
|
||||
to = switch_epoch_time_now(NULL) + timeout;
|
||||
}
|
||||
|
||||
if (cont) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max Tones Reached!\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@@ -2023,6 +2168,7 @@ switch_status_t spandsp_fax_detect_session(switch_core_session_t *session,
|
||||
cont->data = switch_core_session_strdup(session, data);
|
||||
}
|
||||
|
||||
cont->tone_type = tone_type;
|
||||
cont->callback = callback;
|
||||
cont->up = 1;
|
||||
cont->session = session;
|
||||
@@ -2066,7 +2212,7 @@ switch_status_t spandsp_fax_detect_session(switch_core_session_t *session,
|
||||
|
||||
|
||||
if ((status = switch_core_media_bug_add(session, "fax_tone_detect", "",
|
||||
tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
tone_detect_callback, cont, to, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
cont->bug_running = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH mod_fax.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Massimo Cetra <devel@navynet.it>
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Brian West <brian@freeswitch.org>
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Steve Underwood <steveu@coppice.org>
|
||||
* mod_spandsp_modem.h -- Fax modem applications provided by SpanDSP
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
#include "switch_private.h"
|
||||
#endif
|
||||
#if defined(HAVE_OPENPTY) || defined(HAVE_DEV_PTMX) || defined(HAVE_POSIX_OPENPT) || WIN32
|
||||
#define MODEM_SUPPORT 1
|
||||
#if !defined(HAVE_POSIX_OPENPT) && !defined(HAVE_DEV_PTMX) && !defined(WIN32)
|
||||
#define USE_OPENPTY 1
|
||||
#endif
|
||||
#ifndef _MOD_SPANDSP_MODEM_H
|
||||
#define _MOD_SPANDSP_MODEM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef __APPLE__
|
||||
#include <util.h>
|
||||
#include <sys/ioctl.h>
|
||||
#else
|
||||
#include <pty.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#ifndef WIN32
|
||||
#ifdef __UCLIBC__
|
||||
#else
|
||||
#if defined(HAVE_BYTESWAP_H)
|
||||
#include <byteswap.h>
|
||||
#elif defined(USE_SYS_ENDIAN_H)
|
||||
#include <sys/endian.h>
|
||||
#elif defined (__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16 OSSwapInt16
|
||||
#define bswap_32 OSSwapInt32
|
||||
#define bswap_64 OSSwapInt64
|
||||
#else
|
||||
#define bswap_16(value) \
|
||||
((((value) & 0xff) << 8) | ((value) >> 8))
|
||||
|
||||
#define bswap_32(value) \
|
||||
(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
|
||||
(uint32_t)bswap_16((uint16_t)((value) >> 16)))
|
||||
|
||||
#define bswap_64(value) \
|
||||
(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \
|
||||
<< 32) | \
|
||||
(uint64_t)bswap_32((uint32_t)((value) >> 32)))
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef WIN32
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <tiffio.h>
|
||||
#include <spandsp.h>
|
||||
|
||||
|
||||
typedef enum {
|
||||
MODEM_STATE_INIT,
|
||||
MODEM_STATE_ONHOOK,
|
||||
MODEM_STATE_OFFHOOK,
|
||||
MODEM_STATE_ACQUIRED,
|
||||
MODEM_STATE_RINGING,
|
||||
MODEM_STATE_ANSWERED,
|
||||
MODEM_STATE_DIALING,
|
||||
MODEM_STATE_CONNECTED,
|
||||
MODEM_STATE_HANGUP,
|
||||
MODEM_STATE_LAST
|
||||
} modem_state_t;
|
||||
|
||||
struct modem;
|
||||
|
||||
typedef int (*modem_control_handler_t)(struct modem *, const char *, int);
|
||||
|
||||
|
||||
typedef enum {
|
||||
MODEM_FLAG_RUNNING = ( 1 << 0),
|
||||
MODEM_FLAG_XOFF = ( 1 << 1)
|
||||
} modem_flags;
|
||||
|
||||
struct modem {
|
||||
t31_state_t *t31_state;
|
||||
char digits[512];
|
||||
modem_flags flags;
|
||||
#ifndef WIN32
|
||||
int master;
|
||||
#else
|
||||
HANDLE master;
|
||||
HANDLE threadAbort;
|
||||
#endif
|
||||
int slave;
|
||||
char *stty;
|
||||
char devlink[128];
|
||||
int id;
|
||||
modem_state_t state;
|
||||
modem_control_handler_t control_handler;
|
||||
void *user_data;
|
||||
switch_mutex_t *mutex;
|
||||
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
switch_time_t last_event;
|
||||
int slot;
|
||||
switch_thread_cond_t *cond;
|
||||
switch_mutex_t *cond_mutex;
|
||||
};
|
||||
|
||||
typedef struct modem modem_t;
|
||||
|
||||
char *modem_state2name(int state);
|
||||
int modem_close(struct modem *fm);
|
||||
switch_status_t modem_init(struct modem *fm, modem_control_handler_t control_handler);
|
||||
|
||||
#endif //MODEM_SUPPORT
|
||||
|
||||
switch_status_t modem_global_init(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
|
||||
void modem_global_shutdown(void);
|
||||
|
||||
#endif //_MOD_SPANDSP_MODEM_H
|
||||
@@ -30,6 +30,9 @@
|
||||
*/
|
||||
#include <switch.h>
|
||||
#define VALET_EVENT "valet_parking::info"
|
||||
#define VALET_PROTO "park"
|
||||
#define TOKEN_FREQ 5
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_valet_parking_load);
|
||||
|
||||
@@ -38,22 +41,34 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_valet_parking_load);
|
||||
*/
|
||||
SWITCH_MODULE_DEFINITION(mod_valet_parking, mod_valet_parking_load, NULL, NULL);
|
||||
|
||||
typedef struct {
|
||||
char ext[256];
|
||||
char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
time_t timeout;
|
||||
int bridged;
|
||||
time_t start_time;
|
||||
} valet_token_t;
|
||||
|
||||
typedef struct {
|
||||
switch_hash_t *hash;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
time_t last_timeout_check;
|
||||
char *name;
|
||||
} valet_lot_t;
|
||||
|
||||
static valet_lot_t globals = { 0 };
|
||||
|
||||
|
||||
static valet_lot_t *valet_find_lot(const char *name)
|
||||
static valet_lot_t *valet_find_lot(const char *name, switch_bool_t create)
|
||||
{
|
||||
valet_lot_t *lot;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (!(lot = switch_core_hash_find(globals.hash, name))) {
|
||||
lot = switch_core_hash_find(globals.hash, name);
|
||||
if (!lot && create) {
|
||||
switch_zmalloc(lot, sizeof(*lot));
|
||||
lot->name = strdup(name);
|
||||
switch_mutex_init(&lot->mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
switch_core_hash_init(&lot->hash, NULL);
|
||||
switch_core_hash_insert(globals.hash, name, lot);
|
||||
@@ -80,31 +95,304 @@ static switch_status_t valet_on_dtmf(switch_core_session_t *session, void *input
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int next_id(valet_lot_t *lot, int min, int max, int in)
|
||||
static void check_timeouts(void)
|
||||
{
|
||||
int i, r = 0, m;
|
||||
char buf[128] = "";
|
||||
switch_hash_index_t *hi;
|
||||
const void *var;
|
||||
void *val;
|
||||
time_t now;
|
||||
valet_lot_t *lot;
|
||||
switch_console_callback_match_t *matches = NULL;
|
||||
switch_console_callback_match_node_t *m;
|
||||
switch_hash_index_t *i_hi;
|
||||
const void *i_var;
|
||||
void *i_val;
|
||||
char *i_ext;
|
||||
valet_token_t *token;
|
||||
|
||||
if (!min)
|
||||
min = 1;
|
||||
now = switch_epoch_time_now(NULL);
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (now - globals.last_timeout_check < TOKEN_FREQ) {
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
globals.last_timeout_check = now;
|
||||
for (hi = switch_hash_first(NULL, globals.hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
switch_console_push_match(&matches, (const char *) var);
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
|
||||
if (matches) {
|
||||
for (m = matches->head; m; m = m->next) {
|
||||
|
||||
lot = valet_find_lot(m->val, SWITCH_FALSE);
|
||||
switch_mutex_lock(lot->mutex);
|
||||
|
||||
top:
|
||||
|
||||
for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) {
|
||||
switch_hash_this(i_hi, &i_var, NULL, &i_val);
|
||||
i_ext = (char *) i_var;
|
||||
token = (valet_token_t *) i_val;
|
||||
|
||||
if (token->timeout > 0 && (token->timeout < now || token->timeout == 1)) {
|
||||
switch_core_hash_delete(lot->hash, i_ext);
|
||||
switch_safe_free(token);
|
||||
goto top;
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
}
|
||||
|
||||
switch_console_free_matches(&matches);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int find_longest(valet_lot_t *lot, int min, int max)
|
||||
{
|
||||
|
||||
switch_hash_index_t *i_hi;
|
||||
const void *i_var;
|
||||
void *i_val;
|
||||
valet_token_t *token;
|
||||
int longest = 0, cur = 0, longest_ext = 0;
|
||||
time_t now = switch_epoch_time_now(NULL);
|
||||
|
||||
switch_mutex_lock(lot->mutex);
|
||||
for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) {
|
||||
int i;
|
||||
switch_hash_this(i_hi, &i_var, NULL, &i_val);
|
||||
token = (valet_token_t *) i_val;
|
||||
cur = (now - token->start_time);
|
||||
i = atoi(token->ext);
|
||||
|
||||
if (cur > longest && i >= min && i <= max) {
|
||||
longest = cur;
|
||||
longest_ext = i;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
|
||||
return longest_ext;
|
||||
}
|
||||
|
||||
static valet_token_t *next_id(switch_core_session_t *session, valet_lot_t *lot, int min, int max, int in)
|
||||
{
|
||||
int i, r = 0;
|
||||
char buf[256] = "";
|
||||
valet_token_t *token;
|
||||
|
||||
if (!min) {
|
||||
min = 1;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
|
||||
if (!in) {
|
||||
int longest = find_longest(lot, min, max);
|
||||
if (longest > 0) {
|
||||
switch_snprintf(buf, sizeof(buf), "%d", longest);
|
||||
switch_mutex_lock(lot->mutex);
|
||||
token = (valet_token_t *) switch_core_hash_find(lot->hash, buf);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
if (token) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = min; (i < max || max == 0); i++) {
|
||||
switch_snprintf(buf, sizeof(buf), "%d", i);
|
||||
m = !!switch_core_hash_find(lot->hash, buf);
|
||||
switch_mutex_lock(lot->mutex);
|
||||
token = (valet_token_t *) switch_core_hash_find(lot->hash, buf);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
|
||||
if ((in && !m) || (!in && m)) {
|
||||
if ((!in && token && !token->timeout)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (in && !token) {
|
||||
r = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
token = NULL;
|
||||
|
||||
if (r) {
|
||||
switch_snprintf(buf, sizeof(buf), "%d", r);
|
||||
switch_zmalloc(token, sizeof(*token));
|
||||
switch_set_string(token->uuid, switch_core_session_get_uuid(session));
|
||||
switch_set_string(token->ext, buf);
|
||||
token->start_time = switch_epoch_time_now(NULL);
|
||||
switch_mutex_lock(lot->mutex);
|
||||
switch_core_hash_insert(lot->hash, buf, token);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
return r;
|
||||
return token;
|
||||
}
|
||||
|
||||
static int valet_lot_count(valet_lot_t *lot)
|
||||
{
|
||||
switch_hash_index_t *i_hi;
|
||||
const void *i_var;
|
||||
void *i_val;
|
||||
valet_token_t *token;
|
||||
int count = 0;
|
||||
time_t now;
|
||||
|
||||
now = switch_epoch_time_now(NULL);
|
||||
|
||||
switch_mutex_lock(lot->mutex);
|
||||
for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) {
|
||||
switch_hash_this(i_hi, &i_var, NULL, &i_val);
|
||||
token = (valet_token_t *) i_val;
|
||||
if (token->timeout > 0 && (token->timeout < now || token->timeout == 1)) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int EC = 0;
|
||||
|
||||
static void valet_send_presence(const char *lot_name, valet_lot_t *lot, valet_token_t *token, switch_bool_t in)
|
||||
{
|
||||
|
||||
char *domain_name, *dup_lot_name = NULL, *dup_domain_name = NULL;
|
||||
switch_event_t *event;
|
||||
int count;
|
||||
|
||||
|
||||
dup_lot_name = strdup(lot_name);
|
||||
lot_name = dup_lot_name;
|
||||
|
||||
if ((domain_name = strchr(dup_lot_name, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
dup_domain_name = switch_core_get_variable_dup("domain");
|
||||
domain_name = dup_domain_name;
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
domain_name = "cluecon.com";
|
||||
}
|
||||
|
||||
count = valet_lot_count(lot);
|
||||
|
||||
if (count > 0) {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name);
|
||||
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d caller%s)", count, count == 1 ? "" : "s");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
} else {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name);
|
||||
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Empty");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (in) {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", token->ext);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", token->ext, domain_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", token->bridged == 0 ? "Holding" : "Active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", token->ext);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", token->bridged == 0 ? "outbound" : "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
} else {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", token->ext);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", token->ext, domain_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Empty");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", token->ext);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
switch_safe_free(dup_domain_name);
|
||||
switch_safe_free(dup_lot_name);
|
||||
|
||||
}
|
||||
|
||||
struct read_frame_data {
|
||||
const char *dp;
|
||||
const char *exten;
|
||||
const char *context;
|
||||
long to;
|
||||
};
|
||||
|
||||
static switch_status_t read_frame_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data)
|
||||
{
|
||||
struct read_frame_data *rf = (struct read_frame_data *) user_data;
|
||||
|
||||
if (--rf->to <= 0) {
|
||||
rf->to = -1;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VALET_APP_SYNTAX "<lotname> <extension>|[ask [<min>] [<max>] [<to>] [<prompt>]|auto in [min] [max]]"
|
||||
SWITCH_STANDARD_APP(valet_parking_function)
|
||||
@@ -116,7 +404,11 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
char dtmf_buf[128] = "";
|
||||
int is_auto = 0, play_announce = 1;
|
||||
const char *var;
|
||||
valet_token_t *token = NULL;
|
||||
struct read_frame_data rf = { 0 };
|
||||
long to_val = 0;
|
||||
|
||||
check_timeouts();
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "valet_announce_slot"))) {
|
||||
play_announce = switch_true(var);
|
||||
@@ -134,15 +426,16 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
switch_input_args_t args = { 0 };
|
||||
char dbuf[10];
|
||||
char *dest;
|
||||
int in = -1;
|
||||
|
||||
lot = valet_find_lot(lot_name);
|
||||
lot = valet_find_lot(lot_name, SWITCH_TRUE);
|
||||
switch_assert(lot);
|
||||
|
||||
if (!strcasecmp(ext, "auto")) {
|
||||
const char *io = argv[2];
|
||||
const char *min = argv[3];
|
||||
const char *max = argv[4];
|
||||
int min_i, max_i, id, in = -1;
|
||||
int min_i, max_i;
|
||||
|
||||
if (argc < 5) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", VALET_APP_SYNTAX);
|
||||
@@ -160,21 +453,21 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
|
||||
if (in < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", VALET_APP_SYNTAX);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
min_i = atoi(min);
|
||||
max_i = atoi(max);
|
||||
|
||||
if (!(id = next_id(lot, min_i, max_i, in))) {
|
||||
if (!(token = next_id(session, lot, min_i, max_i, in))) {
|
||||
switch_ivr_phrase_macro(session, in ? "valet_lot_full" : "valet_lot_empty", "", NULL, NULL);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s lot is %s.\n", switch_channel_get_name(channel), in ? "full" : "empty");
|
||||
return;
|
||||
}
|
||||
|
||||
switch_snprintf(dtmf_buf, sizeof(dtmf_buf), "%d", id);
|
||||
switch_snprintf(dtmf_buf, sizeof(dtmf_buf), "%s", token->ext);
|
||||
ext = dtmf_buf;
|
||||
|
||||
} else if (!strcasecmp(ext, "ask")) {
|
||||
const char *prompt = "ivr/ivr-enter_ext_pound.wav";
|
||||
int min = 1;
|
||||
@@ -219,37 +512,82 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_lock(lot->mutex);
|
||||
if ((uuid = switch_core_hash_find(lot->hash, ext))) {
|
||||
switch_core_session_t *b_session;
|
||||
if ((b_session = switch_core_session_locate(uuid))) {
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VALET_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "bridge");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridge-To-UUID", switch_core_session_get_uuid(session));
|
||||
switch_channel_event_set_data(switch_core_session_get_channel(b_session), event);
|
||||
switch_event_fire(&event);
|
||||
switch_core_session_rwunlock(b_session);
|
||||
if (!token || !in) {
|
||||
|
||||
switch_ivr_uuid_bridge(switch_core_session_get_uuid(session), uuid);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
return;
|
||||
if (!token) {
|
||||
switch_mutex_lock(lot->mutex);
|
||||
token = (valet_token_t *) switch_core_hash_find(lot->hash, ext);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
}
|
||||
|
||||
if (token && !token->bridged) {
|
||||
switch_core_session_t *b_session;
|
||||
|
||||
if (token->timeout) {
|
||||
const char *var = switch_channel_get_variable(channel, "valet_ticket");
|
||||
|
||||
if (!zstr(var)) {
|
||||
if (!strcmp(var, token->uuid)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Valet ticket %s accepted.\n", var);
|
||||
token->timeout = 0;
|
||||
switch_channel_set_variable(channel, "valet_ticket", NULL);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid token %s\n", token->uuid);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(token->uuid) && (b_session = switch_core_session_locate(token->uuid))) {
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VALET_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "bridge");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridge-To-UUID", switch_core_session_get_uuid(session));
|
||||
switch_channel_event_set_data(switch_core_session_get_channel(b_session), event);
|
||||
switch_event_fire(&event);
|
||||
switch_core_session_rwunlock(b_session);
|
||||
token->timeout = 0;
|
||||
token->bridged = 1;
|
||||
|
||||
switch_ivr_uuid_bridge(switch_core_session_get_uuid(session), token->uuid);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token) {
|
||||
switch_mutex_lock(lot->mutex);
|
||||
switch_core_hash_delete(lot->hash, token->ext);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
memset(token, 0, sizeof(*token));
|
||||
} else {
|
||||
switch_zmalloc(token, sizeof(*token));
|
||||
}
|
||||
switch_set_string(token->uuid, switch_core_session_get_uuid(session));
|
||||
switch_set_string(token->ext, ext);
|
||||
token->start_time = switch_epoch_time_now(NULL);
|
||||
switch_mutex_lock(lot->mutex);
|
||||
switch_core_hash_insert(lot->hash, ext, token);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
}
|
||||
|
||||
if (!(tmp = switch_channel_get_variable(channel, "valet_hold_music"))) {
|
||||
tmp = switch_channel_get_hold_music(channel);
|
||||
}
|
||||
if (tmp)
|
||||
|
||||
if (tmp) {
|
||||
music = tmp;
|
||||
}
|
||||
|
||||
if (!strcasecmp(music, "silence")) {
|
||||
music = "silence_stream://-1";
|
||||
}
|
||||
|
||||
dest = switch_core_session_sprintf(session, "set:valet_hold_music=%s,sleep:1000,valet_park:%s %s", music, lot_name, ext);
|
||||
|
||||
dest = switch_core_session_sprintf(session, "set:valet_ticket=%s,set:valet_hold_music=%s,sleep:1000,valet_park:%s %s",
|
||||
token->uuid, music, lot_name, ext);
|
||||
switch_channel_set_variable(channel, "inline_destination", dest);
|
||||
|
||||
if (is_auto) {
|
||||
@@ -260,18 +598,20 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
switch_core_session_t *b_session;
|
||||
|
||||
if ((b_session = switch_core_session_locate(uuid))) {
|
||||
token->timeout = switch_epoch_time_now(NULL) + TOKEN_FREQ;
|
||||
if (play_announce) {
|
||||
switch_ivr_sleep(session, 1500, SWITCH_TRUE, NULL);
|
||||
switch_ivr_phrase_macro(session, "valet_announce_ext", tmp, NULL, NULL);
|
||||
}
|
||||
switch_ivr_session_transfer(b_session, dest, "inline", NULL);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
switch_core_session_rwunlock(b_session);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (play_announce) {
|
||||
switch_ivr_sleep(session, 1500, SWITCH_TRUE, NULL);
|
||||
switch_ivr_phrase_macro(session, "valet_announce_ext", tmp, NULL, NULL);
|
||||
}
|
||||
}
|
||||
@@ -285,26 +625,60 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
valet_send_presence(lot_name, lot, token, SWITCH_TRUE);
|
||||
|
||||
if ((rf.exten = switch_channel_get_variable(channel, "valet_parking_orbit_exten"))) {
|
||||
to_val = 60;
|
||||
}
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "valet_parking_timeout"))) {
|
||||
long tmp = atol(var);
|
||||
|
||||
if (tmp > 0) {
|
||||
to_val = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (to_val) {
|
||||
switch_codec_implementation_t read_impl;
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
rf.to = (1000 / (read_impl.microseconds_per_packet / 1000)) * to_val;
|
||||
rf.dp = switch_channel_get_variable(channel, "valet_parking_orbit_dialplan");
|
||||
rf.context = switch_channel_get_variable(channel, "valet_parking_orbit_context");
|
||||
}
|
||||
|
||||
switch_core_hash_insert(lot->hash, ext, switch_core_session_get_uuid(session));
|
||||
|
||||
args.input_callback = valet_on_dtmf;
|
||||
args.buf = dbuf;
|
||||
args.buflen = sizeof(dbuf);
|
||||
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
if (rf.to) {
|
||||
args.read_frame_callback = read_frame_callback;
|
||||
args.user_data = &rf;
|
||||
}
|
||||
|
||||
|
||||
while(switch_channel_ready(channel)) {
|
||||
switch_status_t pstatus = switch_ivr_play_file(session, NULL, music, &args);
|
||||
|
||||
if (rf.to == -1) {
|
||||
if (!zstr(rf.exten)) {
|
||||
switch_ivr_session_transfer(session, rf.exten, rf.dp, rf.context);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pstatus == SWITCH_STATUS_BREAK || pstatus == SWITCH_STATUS_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_lock(lot->mutex);
|
||||
switch_core_hash_delete(lot->hash, ext);
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
if (token) {
|
||||
token->timeout = 1;
|
||||
valet_send_presence(lot_name, lot, token, SWITCH_FALSE);
|
||||
token = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VALET_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name);
|
||||
@@ -316,6 +690,13 @@ SWITCH_STANDARD_APP(valet_parking_function)
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", VALET_APP_SYNTAX);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (token) {
|
||||
token->timeout = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(valet_info_function)
|
||||
@@ -334,7 +715,6 @@ SWITCH_STANDARD_API(valet_info_function)
|
||||
const void *i_var;
|
||||
void *i_val;
|
||||
char *i_ext;
|
||||
char *i_uuid;
|
||||
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
name = (char *) var;
|
||||
@@ -345,12 +725,20 @@ SWITCH_STANDARD_API(valet_info_function)
|
||||
|
||||
stream->write_function(stream, " <lot name=\"%s\">\n", name);
|
||||
|
||||
switch_mutex_lock(lot->mutex);
|
||||
for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) {
|
||||
valet_token_t *token;
|
||||
|
||||
switch_hash_this(i_hi, &i_var, NULL, &i_val);
|
||||
i_ext = (char *) i_var;
|
||||
i_uuid = (char *) i_val;
|
||||
stream->write_function(stream, " <extension uuid=\"%s\">%s</extension>\n", i_uuid, i_ext);
|
||||
token = (valet_token_t *) i_val;
|
||||
|
||||
if (!token->timeout) {
|
||||
stream->write_function(stream, " <extension uuid=\"%s\">%s</extension>\n", token->uuid, i_ext);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
|
||||
stream->write_function(stream, " </lot>\n");
|
||||
}
|
||||
|
||||
@@ -361,6 +749,143 @@ SWITCH_STANDARD_API(valet_info_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void pres_event_handler(switch_event_t *event)
|
||||
{
|
||||
char *to = switch_event_get_header(event, "to");
|
||||
char *dup_to = NULL, *lot_name, *dup_lot_name = NULL, *domain_name;
|
||||
valet_lot_t *lot;
|
||||
int found = 0;
|
||||
|
||||
if (!to || strncasecmp(to, "park+", 5) || !strchr(to, '@')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(dup_to = strdup(to))) {
|
||||
return;
|
||||
}
|
||||
|
||||
lot_name = dup_to + 5;
|
||||
|
||||
if ((domain_name = strchr(lot_name, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
}
|
||||
|
||||
dup_lot_name = switch_mprintf("%q@%q", lot_name, domain_name);
|
||||
|
||||
if ((lot = valet_find_lot(lot_name, SWITCH_FALSE)) || (dup_lot_name && (lot = valet_find_lot(dup_lot_name, SWITCH_FALSE)))) {
|
||||
int count = valet_lot_count(lot);
|
||||
|
||||
if (count) {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name);
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d caller%s)", count, count == 1 ? "" : "s");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
found++;
|
||||
}
|
||||
} else {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name);
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Empty");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch_console_callback_match_t *matches = NULL;
|
||||
switch_console_callback_match_node_t *m;
|
||||
switch_hash_index_t *hi;
|
||||
const void *var;
|
||||
void *val;
|
||||
const char *nvar;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
for (hi = switch_hash_first(NULL, globals.hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
nvar = (const char *) var;
|
||||
|
||||
if (!strchr(nvar, '@') || switch_stristr(domain_name, nvar)) {
|
||||
switch_console_push_match(&matches, nvar);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (matches) {
|
||||
valet_token_t *token;
|
||||
|
||||
for (m = matches->head; !found && m; m = m->next) {
|
||||
lot = valet_find_lot(m->val, SWITCH_FALSE);
|
||||
switch_mutex_lock(lot->mutex);
|
||||
|
||||
if ((token = (valet_token_t *) switch_core_hash_find(lot->hash, lot_name)) && !token->timeout) {
|
||||
found++;
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name);
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", token->bridged == 0 ? "Holding" : "Active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", token->bridged == 0 ? "early" : "confirmed");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", token->bridged == 0 ? "outbound" : "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_unlock(lot->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found && switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name);
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Empty");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
switch_safe_free(dup_to);
|
||||
switch_safe_free(dup_lot_name);
|
||||
}
|
||||
|
||||
/* Macro expands to: switch_status_t mod_valet_parking_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_valet_parking_load)
|
||||
{
|
||||
@@ -373,6 +898,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_valet_parking_load)
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL);
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
|
||||
globals.pool = pool;
|
||||
switch_core_hash_init(&globals.hash, NULL);
|
||||
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
@@ -45,6 +45,7 @@ SWITCH_MODULE_DEFINITION(mod_voicemail, mod_voicemail_load, mod_voicemail_shutdo
|
||||
#define VM_EVENT_MAINT "vm::maintenance"
|
||||
|
||||
#define VM_MAX_GREETINGS 9
|
||||
#define VM_EVENT_QUEUE_SIZE 50000
|
||||
|
||||
static switch_status_t voicemail_inject(const char *data, switch_core_session_t *session);
|
||||
|
||||
@@ -53,6 +54,9 @@ static struct {
|
||||
switch_hash_t *profile_hash;
|
||||
int debug;
|
||||
int message_query_exact_match;
|
||||
int32_t threads;
|
||||
int32_t running;
|
||||
switch_queue_t *event_queue;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
} globals;
|
||||
@@ -299,6 +303,8 @@ static char *vm_index_list[] = {
|
||||
"create index voicemail_msgs_idx5 on voicemail_msgs(in_folder)",
|
||||
"create index voicemail_msgs_idx6 on voicemail_msgs(read_flags)",
|
||||
"create index voicemail_msgs_idx7 on voicemail_msgs(forwarded_by)",
|
||||
"create index voicemail_msgs_idx8 on voicemail_msgs(read_epoch)",
|
||||
"create index voicemail_msgs_idx9 on voicemail_msgs(flags)",
|
||||
"create index voicemail_prefs_idx1 on voicemail_prefs(username)",
|
||||
"create index voicemail_prefs_idx2 on voicemail_prefs(domain)",
|
||||
NULL
|
||||
@@ -621,7 +627,7 @@ vm_profile_t *profile_set_config(vm_profile_t *profile)
|
||||
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "email_email-from", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE,
|
||||
&profile->email_from, NULL, &profile->config_str_pool, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "email_date-fmt", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE,
|
||||
&profile->date_fmt, "%A, %B %d %Y, %I %M %p", &profile->config_str_pool, NULL, NULL);
|
||||
&profile->date_fmt, "%A, %B %d %Y, %I:%M %p", &profile->config_str_pool, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "odbc-dsn", SWITCH_CONFIG_STRING, 0, &profile->odbc_dsn, NULL, &profile->config_str_pool, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM_CALLBACK(profile->config[i++], "email_template-file", SWITCH_CONFIG_CUSTOM, CONFIG_RELOADABLE,
|
||||
NULL, NULL, profile, vm_config_email_callback, NULL, NULL);
|
||||
@@ -849,6 +855,7 @@ struct call_control {
|
||||
switch_file_handle_t *fh;
|
||||
char buf[4];
|
||||
int noexit;
|
||||
int playback_controls_active;
|
||||
};
|
||||
typedef struct call_control cc_t;
|
||||
|
||||
@@ -867,7 +874,13 @@ static switch_status_t control_playback(switch_core_session_t *session, void *in
|
||||
|| dtmf->digit == *cc->profile->prev_msg_key || dtmf->digit == *cc->profile->next_msg_key
|
||||
|| dtmf->digit == *cc->profile->repeat_msg_key
|
||||
|| dtmf->digit == *cc->profile->terminator_key || dtmf->digit == *cc->profile->skip_info_key
|
||||
|| dtmf->digit == *cc->profile->email_key || dtmf->digit == *cc->profile->forward_key)) {
|
||||
|| dtmf->digit == *cc->profile->forward_key)) {
|
||||
*cc->buf = dtmf->digit;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if (!cc->playback_controls_active
|
||||
&& (dtmf->digit == *cc->profile->email_key)) {
|
||||
*cc->buf = dtmf->digit;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
@@ -900,12 +913,17 @@ static switch_status_t control_playback(switch_core_session_t *session, void *in
|
||||
|
||||
if (dtmf->digit == *cc->profile->rew_key) {
|
||||
int samps = -48000;
|
||||
switch_core_file_seek(fh, &pos, samps, SEEK_CUR);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
if (!cc->noexit && dtmf->digit == *cc->profile->terminator_key) {
|
||||
*cc->buf = dtmf->digit;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
int target_pos = fh->offset_pos + samps;
|
||||
if (target_pos < 1) {
|
||||
/* too close to beginning of the file, just restart instead of rewind */
|
||||
unsigned int seekpos = 0;
|
||||
fh->speed = 0;
|
||||
switch_core_file_seek(fh, &seekpos, 0, SEEK_SET);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
switch_core_file_seek(fh, &pos, samps, SEEK_CUR);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1160,6 +1178,8 @@ static switch_status_t create_file(switch_core_session_t *session, vm_profile_t
|
||||
args.buf = input;
|
||||
args.buflen = sizeof(input);
|
||||
|
||||
unlink(file_path);
|
||||
|
||||
switch_ivr_record_file(session, &fh, file_path, &args, profile->max_record_len);
|
||||
|
||||
if (switch_file_exists(file_path, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
|
||||
@@ -1529,6 +1549,9 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = cid_buf;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending display update [%s] to %s\n",
|
||||
cid_buf, switch_channel_get_name(channel));
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
if (!zstr(cbt->cid_number) && (vm_announce_cid = switch_channel_get_variable(channel, "vm_announce_cid"))) {
|
||||
@@ -1562,9 +1585,11 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
|
||||
*cc.buf = '\0';
|
||||
memset(&fh, 0, sizeof(fh));
|
||||
cc.fh = &fh;
|
||||
cc.playback_controls_active = 1;
|
||||
if (switch_file_exists(cbt->file_path, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
|
||||
TRY_CODE(switch_ivr_play_file(session, &fh, cbt->file_path, &args));
|
||||
}
|
||||
cc.playback_controls_active = 0;
|
||||
}
|
||||
|
||||
if (!*cc.buf && (profile->play_date_announcement == VM_DATE_LAST)) {
|
||||
@@ -1670,7 +1695,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
|
||||
switch_time_t l_duration = 0;
|
||||
switch_core_time_duration_t duration;
|
||||
char duration_str[80];
|
||||
|
||||
char *formatted_cid_num = NULL;
|
||||
if (!strcasecmp(cbt->read_flags, URGENT_FLAG_STRING)) {
|
||||
priority = 1;
|
||||
}
|
||||
@@ -1681,6 +1706,8 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
|
||||
switch_time_exp_lt(&tm, switch_time_make(atol(cbt->created_epoch), 0));
|
||||
switch_strftime(date, &retsize, sizeof(date), profile->date_fmt, &tm);
|
||||
|
||||
formatted_cid_num = switch_format_number(cbt->cid_number);
|
||||
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", total_new_messages);
|
||||
switch_channel_set_variable(channel, "voicemail_total_new_messages", tmp);
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", total_saved_messages);
|
||||
@@ -1693,6 +1720,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
|
||||
switch_channel_set_variable(channel, "voicemail_account", cbt->user);
|
||||
switch_channel_set_variable(channel, "voicemail_domain", cbt->domain);
|
||||
switch_channel_set_variable(channel, "voicemail_caller_id_number", cbt->cid_number);
|
||||
switch_channel_set_variable(channel, "voicemail_formatted_caller_id_number", formatted_cid_num);
|
||||
switch_channel_set_variable(channel, "voicemail_caller_id_name", cbt->cid_name);
|
||||
switch_channel_set_variable(channel, "voicemail_file_path", cbt->file_path);
|
||||
switch_channel_set_variable(channel, "voicemail_read_flags", cbt->read_flags);
|
||||
@@ -1700,6 +1728,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", priority);
|
||||
switch_channel_set_variable(channel, "voicemail_priority", tmp);
|
||||
message_len = atoi(cbt->message_len);
|
||||
switch_safe_free(formatted_cid_num);
|
||||
|
||||
l_duration = switch_time_make(atol(cbt->message_len), 0);
|
||||
switch_core_measure_time(l_duration, &duration);
|
||||
@@ -1819,7 +1848,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
uint32_t timeout, attempts = 0, retries = 0;
|
||||
int failed = 0;
|
||||
msg_type_t play_msg_type = MSG_NONE;
|
||||
char *dir_path = NULL, *file_path = NULL;
|
||||
char *dir_path = NULL, *file_path = NULL, *tmp_file_path = NULL;
|
||||
int total_new_messages = 0;
|
||||
int total_saved_messages = 0;
|
||||
int total_new_urgent_messages = 0;
|
||||
@@ -1833,6 +1862,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
switch_input_args_t args = { 0 };
|
||||
const char *caller_id_name = NULL;
|
||||
const char *caller_id_number = NULL;
|
||||
int auth_only = 0, authed = 0;
|
||||
|
||||
if (!(caller_id_name = switch_channel_get_variable(channel, "effective_caller_id_name"))) {
|
||||
caller_id_name = caller_profile->caller_id_name;
|
||||
@@ -1842,6 +1872,13 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
caller_id_number = caller_profile->caller_id_number;
|
||||
}
|
||||
|
||||
if (auth == 2) {
|
||||
auth_only = 1;
|
||||
auth = 0;
|
||||
} else {
|
||||
auth_only = switch_true(switch_channel_get_variable(channel, "vm_auth_only"));
|
||||
}
|
||||
|
||||
timeout = profile->digit_timeout;
|
||||
attempts = profile->max_login_attempts;
|
||||
status = switch_ivr_phrase_macro(session, VM_HELLO_MACRO, NULL, NULL, &args);
|
||||
@@ -1932,7 +1969,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
if (!informed) {
|
||||
switch_snprintf(msg_count, sizeof(msg_count), "0:new");
|
||||
TRY_CODE(switch_ivr_phrase_macro(session, VM_MESSAGE_COUNT_MACRO, msg_count, NULL, &folder_args));
|
||||
switch_snprintf(msg_count, sizeof(msg_count), "%d:saved", total_saved_messages + total_saved_urgent_messages);
|
||||
switch_snprintf(msg_count, sizeof(msg_count), "%d:saved", total_saved_messages);
|
||||
TRY_CODE(switch_ivr_phrase_macro(session, VM_MESSAGE_COUNT_MACRO, msg_count, NULL, &folder_args));
|
||||
informed++;
|
||||
}
|
||||
@@ -2002,10 +2039,10 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
"username='%s' and domain='%s' and flags='save'",
|
||||
(long) switch_epoch_time_now(NULL), myid, domain_name);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_snprintf(sql, sizeof(sql), "select file_path from voicemail_msgs where username='%s' and domain='%s' and flags='delete'", myid,
|
||||
switch_snprintfv(sql, sizeof(sql), "select file_path from voicemail_msgs where username='%q' and domain='%q' and flags='delete'", myid,
|
||||
domain_name);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, unlink_callback, NULL);
|
||||
switch_snprintf(sql, sizeof(sql), "delete from voicemail_msgs where username='%s' and domain='%s' and flags='delete'", myid, domain_name);
|
||||
switch_snprintfv(sql, sizeof(sql), "delete from voicemail_msgs where username='%q' and domain='%q' and flags='delete'", myid, domain_name);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
vm_check_state = VM_CHECK_FOLDER_SUMMARY;
|
||||
|
||||
@@ -2099,13 +2136,19 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
} else {
|
||||
switch_event_t *params;
|
||||
file_path = switch_mprintf("%s%sgreeting_%d.%s", dir_path, SWITCH_PATH_SEPARATOR, num, profile->file_ext);
|
||||
tmp_file_path = switch_mprintf("%s%sgreeting_%d_TMP.%s", dir_path, SWITCH_PATH_SEPARATOR, num, profile->file_ext);
|
||||
unlink(tmp_file_path);
|
||||
|
||||
TRY_CODE(create_file(session, profile, VM_RECORD_GREETING_MACRO, file_path, &message_len, SWITCH_TRUE, NULL, NULL));
|
||||
switch_file_rename(tmp_file_path, file_path, switch_core_session_get_pool(session));
|
||||
|
||||
sql =
|
||||
switch_mprintf("update voicemail_prefs set greeting_path='%s' where username='%s' and domain='%s'", file_path, myid,
|
||||
domain_name);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(sql);
|
||||
switch_safe_free(file_path);
|
||||
switch_safe_free(tmp_file_path);
|
||||
|
||||
switch_event_create_subclass(¶ms, SWITCH_EVENT_CUSTOM, VM_EVENT_MAINT);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-Action", "record-greeting");
|
||||
@@ -2146,10 +2189,14 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
} else if (!strcmp(input, profile->record_name_key)) {
|
||||
switch_event_t *params;
|
||||
file_path = switch_mprintf("%s%srecorded_name.%s", dir_path, SWITCH_PATH_SEPARATOR, profile->file_ext);
|
||||
tmp_file_path = switch_mprintf("%s%srecorded_name_TMP.%s", dir_path, SWITCH_PATH_SEPARATOR, profile->file_ext);
|
||||
unlink(tmp_file_path);
|
||||
TRY_CODE(create_file(session, profile, VM_RECORD_NAME_MACRO, file_path, &message_len, SWITCH_FALSE, NULL, NULL));
|
||||
switch_file_rename(tmp_file_path, file_path, switch_core_session_get_pool(session));
|
||||
sql = switch_mprintf("update voicemail_prefs set name_path='%s' where username='%s' and domain='%s'", file_path, myid, domain_name);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(file_path);
|
||||
switch_safe_free(tmp_file_path);
|
||||
switch_safe_free(sql);
|
||||
|
||||
switch_event_create_subclass(¶ms, SWITCH_EVENT_CUSTOM, VM_EVENT_MAINT);
|
||||
@@ -2241,6 +2288,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
|
||||
switch_event_create(¶ms, SWITCH_EVENT_GENERAL);
|
||||
switch_assert(params);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "voicemail-lookup");
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "destination_number", caller_profile->destination_number);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "caller_id_number", caller_id_number);
|
||||
|
||||
@@ -2281,7 +2329,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
}
|
||||
|
||||
thepass = thehash = NULL;
|
||||
switch_snprintf(sql, sizeof(sql), "select * from voicemail_prefs where username='%s' and domain='%s'", myid, domain_name);
|
||||
switch_snprintfv(sql, sizeof(sql), "select * from voicemail_prefs where username='%q' and domain='%q'", myid, domain_name);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, prefs_callback, &cbt);
|
||||
|
||||
x_params = switch_xml_child(x_user, "variables");
|
||||
@@ -2407,6 +2455,10 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
}
|
||||
}
|
||||
|
||||
authed = 1;
|
||||
|
||||
if (auth_only) goto end;
|
||||
|
||||
vm_check_state = VM_CHECK_FOLDER_SUMMARY;
|
||||
} else {
|
||||
goto failed;
|
||||
@@ -2431,7 +2483,15 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
|
||||
end:
|
||||
|
||||
if (switch_channel_ready(channel)) {
|
||||
switch_safe_free(file_path);
|
||||
|
||||
if (tmp_file_path) {
|
||||
unlink(tmp_file_path);
|
||||
free(tmp_file_path);
|
||||
tmp_file_path = NULL;
|
||||
}
|
||||
|
||||
if (switch_channel_ready(channel) && (!auth_only || !authed)) {
|
||||
if (failed) {
|
||||
status = switch_ivr_phrase_macro(session, VM_ABORT_MACRO, NULL, NULL, NULL);
|
||||
}
|
||||
@@ -2442,6 +2502,15 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
|
||||
switch_xml_free(x_user);
|
||||
x_user = NULL;
|
||||
}
|
||||
|
||||
if (auth_only) {
|
||||
if (authed) {
|
||||
switch_channel_set_variable(channel, "user_pin_authenticated", "true");
|
||||
} else {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_USER_CHALLENGE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2645,6 +2714,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
switch_time_exp_t tm;
|
||||
char date[80] = "";
|
||||
switch_size_t retsize;
|
||||
char *formatted_cid_num = NULL;
|
||||
|
||||
message_count(profile, myid, domain_name, myfolder, &total_new_messages, &total_saved_messages,
|
||||
&total_new_urgent_messages, &total_saved_urgent_messages);
|
||||
@@ -2654,6 +2724,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
switch_strftime(date, &retsize, sizeof(date), profile->date_fmt, &tm);
|
||||
}
|
||||
|
||||
formatted_cid_num = switch_format_number(caller_id_number);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_current_folder", myfolder);
|
||||
switch_snprintf(tmpvar, sizeof(tmpvar), "%d", total_new_messages);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_total_new_messages", tmpvar);
|
||||
@@ -2666,11 +2737,14 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_account", myid);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_domain", domain_name);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_caller_id_number", caller_id_number);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_formatted_caller_id_number", formatted_cid_num);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_caller_id_name", caller_id_name);
|
||||
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_safe_free(formatted_cid_num);
|
||||
|
||||
switch_snprintf(tmpvar, sizeof(tmpvar), "%d", priority);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "voicemail_priority", tmpvar);
|
||||
if (vm_email) {
|
||||
@@ -2747,6 +2821,10 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
|
||||
|
||||
if (send_notify) {
|
||||
if (zstr(vm_notify_email)) {
|
||||
vm_notify_email = vm_email;
|
||||
}
|
||||
|
||||
if (zstr(profile->notify_email_headers)) {
|
||||
headers = switch_mprintf("From: FreeSWITCH mod_voicemail <%s@%s>\n"
|
||||
"Subject: Voicemail from %s %s\nX-Priority: %d", myid, domain_name, caller_id_name, caller_id_number, priority);
|
||||
@@ -2815,7 +2893,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
|
||||
failed:
|
||||
|
||||
if (del_file && file_path) {
|
||||
if (del_file && file_path && switch_file_exists(file_path, pool)) {
|
||||
if (unlink(file_path) != 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", file_path);
|
||||
}
|
||||
@@ -3093,10 +3171,10 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
int ok = 1;
|
||||
switch_event_t *locate_params = NULL;
|
||||
const char *email_addr = NULL;
|
||||
|
||||
|
||||
switch_event_create(&locate_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_assert(locate_params);
|
||||
switch_event_add_header_string(locate_params, SWITCH_STACK_BOTTOM, "action", "voicemail-lookup");
|
||||
|
||||
if (switch_xml_locate_user_merged("id", id, domain_name, switch_channel_get_variable(channel, "network_addr"),
|
||||
&x_user, locate_params) == SWITCH_STATUS_SUCCESS) {
|
||||
@@ -3189,7 +3267,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch_snprintf(sql, sizeof(sql), "select * from voicemail_prefs where username='%s' and domain='%s'", id, domain_name);
|
||||
switch_snprintfv(sql, sizeof(sql), "select * from voicemail_prefs where username='%q' and domain='%q'", id, domain_name);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, prefs_callback, &cbt);
|
||||
|
||||
if (!vm_ext) {
|
||||
@@ -3291,7 +3369,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
callback.buf = disk_usage;
|
||||
callback.len = sizeof(disk_usage);
|
||||
|
||||
switch_snprintf(sqlstmt, sizeof(sqlstmt), "select sum(message_len) from voicemail_msgs where username='%s' and domain='%s'", id, domain_name);
|
||||
switch_snprintfv(sqlstmt, sizeof(sqlstmt), "select sum(message_len) from voicemail_msgs where username='%q' and domain='%q'", id, domain_name);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sqlstmt, sql2str_callback, &callback);
|
||||
|
||||
if (atoi(disk_usage) >= disk_quota) {
|
||||
@@ -3405,6 +3483,9 @@ SWITCH_STANDARD_APP(voicemail_function)
|
||||
} else if (argv[x] && !strcasecmp(argv[x], "auth")) {
|
||||
auth++;
|
||||
x++;
|
||||
} else if (argv[x] && !strcasecmp(argv[x], "auth_only")) {
|
||||
auth = 2;
|
||||
x++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -3597,7 +3678,7 @@ SWITCH_STANDARD_API(prefs_api_function)
|
||||
|
||||
}
|
||||
|
||||
switch_snprintf(sql, sizeof(sql), "select * from voicemail_prefs where username='%s' and domain='%s'", id, domain);
|
||||
switch_snprintfv(sql, sizeof(sql), "select * from voicemail_prefs where username='%q' and domain='%q'", id, domain);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, prefs_callback, &cbt);
|
||||
|
||||
if (!strcasecmp(how, "greeting_path")) {
|
||||
@@ -3629,16 +3710,14 @@ SWITCH_STANDARD_API(prefs_api_function)
|
||||
switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, "MWI-Message-Account", account); \
|
||||
switch_event_add_header(new_event, SWITCH_STACK_BOTTOM, "MWI-Voice-Message", "%d/%d (%d/%d)", \
|
||||
+total_new_messages, total_saved_messages, total_new_urgent_messages, total_saved_urgent_messages); \
|
||||
created++; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
static void message_query_handler(switch_event_t *event)
|
||||
static void actual_message_query_handler(switch_event_t *event)
|
||||
{
|
||||
char *account = switch_event_get_header(event, "message-account");
|
||||
int created = 0;
|
||||
switch_event_t *new_event = NULL;
|
||||
char *dup = NULL;
|
||||
int total_new_messages = 0;
|
||||
@@ -3677,6 +3756,10 @@ static void message_query_handler(switch_event_t *event)
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
profile = (vm_profile_t *) val;
|
||||
parse_profile();
|
||||
|
||||
if (new_event) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3685,7 +3768,7 @@ static void message_query_handler(switch_event_t *event)
|
||||
|
||||
}
|
||||
|
||||
if (!created) {
|
||||
if (!new_event) {
|
||||
if (switch_event_create(&new_event, SWITCH_EVENT_MESSAGE_WAITING) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, "MWI-Messages-Waiting", "no");
|
||||
switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, "MWI-Message-Account", account);
|
||||
@@ -3707,6 +3790,101 @@ static void message_query_handler(switch_event_t *event)
|
||||
|
||||
}
|
||||
|
||||
static int EVENT_THREAD_RUNNING = 0;
|
||||
static int EVENT_THREAD_STARTED = 0;
|
||||
|
||||
void *SWITCH_THREAD_FUNC vm_event_thread_run(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
void *pop;
|
||||
int done = 0;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (!EVENT_THREAD_RUNNING) {
|
||||
EVENT_THREAD_RUNNING++;
|
||||
globals.threads++;
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (done) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Started\n");
|
||||
|
||||
while (globals.running == 1) {
|
||||
int count = 0;
|
||||
|
||||
if (switch_queue_trypop(globals.event_queue, &pop) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_t *event = (switch_event_t *) pop;
|
||||
|
||||
if (!pop) {
|
||||
break;
|
||||
}
|
||||
actual_message_query_handler(event);
|
||||
switch_event_destroy(&event);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
switch_yield(100000);
|
||||
}
|
||||
}
|
||||
|
||||
while (switch_queue_trypop(globals.event_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
switch_event_t *event = (switch_event_t *) pop;
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Ended\n");
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.threads--;
|
||||
EVENT_THREAD_RUNNING = EVENT_THREAD_STARTED = 0;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vm_event_thread_start(void)
|
||||
{
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
int done = 0;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (!EVENT_THREAD_STARTED) {
|
||||
EVENT_THREAD_STARTED++;
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch_threadattr_create(&thd_attr, globals.pool);
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_threadattr_priority_increase(thd_attr);
|
||||
switch_thread_create(&thread, thd_attr, vm_event_thread_run, NULL, globals.pool);
|
||||
}
|
||||
|
||||
void vm_event_handler(switch_event_t *event)
|
||||
{
|
||||
switch_event_t *cloned_event;
|
||||
|
||||
switch_event_dup(&cloned_event, event);
|
||||
switch_assert(cloned_event);
|
||||
switch_queue_push(globals.event_queue, cloned_event);
|
||||
|
||||
if (!EVENT_THREAD_STARTED) {
|
||||
vm_event_thread_start();
|
||||
}
|
||||
}
|
||||
|
||||
struct holder {
|
||||
vm_profile_t *profile;
|
||||
@@ -4318,7 +4496,7 @@ static int api_list_callback(void *pArg, int argc, char **argv, char **columnNam
|
||||
{
|
||||
switch_stream_handle_t *stream = (switch_stream_handle_t *) pArg;
|
||||
|
||||
if (!strcasecmp(argv[9], "xml")) {
|
||||
if (!strcasecmp(argv[10], "xml")) {
|
||||
stream->write_function(stream, " <message>\n");
|
||||
stream->write_function(stream, " <created_epoch>%s</created_epoch>\n", argv[0]);
|
||||
stream->write_function(stream, " <read_epoch>%s</read_epoch>\n", argv[1]);
|
||||
@@ -4329,9 +4507,10 @@ static int api_list_callback(void *pArg, int argc, char **argv, char **columnNam
|
||||
stream->write_function(stream, " <uuid>%s</uuid>\n", argv[6]);
|
||||
stream->write_function(stream, " <cid-name>%s</cid-name>\n", argv[7]);
|
||||
stream->write_function(stream, " <cid-number>%s</cid-number>\n", argv[8]);
|
||||
stream->write_function(stream, " <message-len>%s</message-len>\n", argv[9]);
|
||||
stream->write_function(stream, " </message>\n");
|
||||
} else {
|
||||
stream->write_function(stream, "%s:%s:%s:%s:%s:%s:%s:%s:%s\n", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
|
||||
stream->write_function(stream, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -4375,11 +4554,11 @@ SWITCH_STANDARD_API(voicemail_list_api_function)
|
||||
|
||||
if (id && domain && profile_name && (profile = get_profile(profile_name))) {
|
||||
if (uuid) {
|
||||
sql = switch_mprintf("select created_epoch, read_epoch, username, domain, in_folder, file_path, uuid, cid_name, cid_number, "
|
||||
sql = switch_mprintf("select created_epoch, read_epoch, username, domain, in_folder, file_path, uuid, cid_name, cid_number, message_len, "
|
||||
"'%q' from voicemail_msgs where username='%q' and domain='%q' and uuid='%q'",
|
||||
format, id, domain, uuid);
|
||||
} else {
|
||||
sql = switch_mprintf("select created_epoch, read_epoch, username, domain, in_folder, file_path, uuid, cid_name, cid_number, "
|
||||
sql = switch_mprintf("select created_epoch, read_epoch, username, domain, in_folder, file_path, uuid, cid_name, cid_number, message_len, "
|
||||
"'%q' from voicemail_msgs where username='%q' and domain='%q'",
|
||||
format, id, domain);
|
||||
}
|
||||
@@ -4390,7 +4569,6 @@ SWITCH_STANDARD_API(voicemail_list_api_function)
|
||||
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, api_list_callback, stream);
|
||||
switch_safe_free(sql);
|
||||
update_mwi(profile, id, domain, "inbox");
|
||||
|
||||
if (!strcasecmp(format, "xml")) {
|
||||
stream->write_function(stream, "</voicemail>\n");
|
||||
@@ -4762,13 +4940,6 @@ SWITCH_STANDARD_API(vm_fsdb_pref_recname_set_function)
|
||||
vm_execute_sql2str(profile, profile->mutex, sql, res, sizeof(res));
|
||||
switch_safe_free(sql);
|
||||
|
||||
if (atoi(res) == 0) {
|
||||
sql = switch_mprintf("INSERT INTO voicemail_prefs (username, domain, name_path) VALUES('%q', '%q', '%q')", id, domain, file_path);
|
||||
} else {
|
||||
sql = switch_mprintf("UPDATE voicemail_prefs SET name_path = '%q' WHERE username = '%q' AND domain = '%q'", file_path, id, domain);
|
||||
}
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(sql);
|
||||
{
|
||||
char *dir_path = switch_core_sprintf(pool, "%s%svoicemail%s%s%s%s%s%s", SWITCH_GLOBAL_dirs.storage_dir,
|
||||
SWITCH_PATH_SEPARATOR,
|
||||
@@ -4783,6 +4954,14 @@ SWITCH_STANDARD_API(vm_fsdb_pref_recname_set_function)
|
||||
}
|
||||
|
||||
switch_file_rename(file_path, final_file_path, pool);
|
||||
if (atoi(res) == 0) {
|
||||
sql = switch_mprintf("INSERT INTO voicemail_prefs (username, domain, name_path) VALUES('%q', '%q', '%q')", id, domain, final_file_path);
|
||||
} else {
|
||||
sql = switch_mprintf("UPDATE voicemail_prefs SET name_path = '%q' WHERE username = '%q' AND domain = '%q'", final_file_path, id, domain);
|
||||
}
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
||||
}
|
||||
profile_rwunlock(profile);
|
||||
@@ -4857,14 +5036,14 @@ done:
|
||||
|
||||
/* Message API */
|
||||
|
||||
#define VM_FSDB_MSG_LIST_USAGE "<format> <profile> <domain> <user>"
|
||||
#define VM_FSDB_MSG_LIST_USAGE "<format> <profile> <domain> <user> <folder> <filter>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_list_function)
|
||||
{
|
||||
char *sql;
|
||||
msg_lst_callback_t cbt = { 0 };
|
||||
char *ebuf = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL, *folder = NULL, *msg_type = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
@@ -4885,8 +5064,12 @@ SWITCH_STANDARD_API(vm_fsdb_msg_list_function)
|
||||
domain = argv[2];
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
if (argv[4])
|
||||
folder = argv[4]; /* TODO add Support */
|
||||
if (argv[5])
|
||||
msg_type = argv[5];
|
||||
|
||||
if (!profile_name || !domain || !id) {
|
||||
if (!profile_name || !domain || !id || !folder || !msg_type) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
@@ -4895,8 +5078,15 @@ SWITCH_STANDARD_API(vm_fsdb_msg_list_function)
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
sql = switch_mprintf("SELECT uuid FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND read_epoch = 0 ORDER BY read_flags, created_epoch", id, domain);
|
||||
|
||||
if (!strcasecmp(msg_type, "not-read")) {
|
||||
sql = switch_mprintf("SELECT uuid FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND read_epoch = 0 ORDER BY read_flags, created_epoch", id, domain);
|
||||
} else if (!strcasecmp(msg_type, "new")) {
|
||||
sql = switch_mprintf("SELECT uuid FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND flags='' ORDER BY read_flags, created_epoch", id, domain);
|
||||
} else if (!strcasecmp(msg_type, "save")) {
|
||||
sql = switch_mprintf("SELECT uuid FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND flags='save' ORDER BY read_flags, created_epoch", id, domain);
|
||||
} else {
|
||||
sql = switch_mprintf("SELECT uuid FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND read_epoch != 0 ORDER BY read_flags, created_epoch", id, domain);
|
||||
}
|
||||
memset(&cbt, 0, sizeof(cbt));
|
||||
|
||||
switch_event_create(&cbt.my_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
@@ -5396,7 +5586,7 @@ done:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_COUNT_USAGE "<format> <profile> <domain> <user>"
|
||||
#define VM_FSDB_MSG_COUNT_USAGE "<format> <profile> <domain> <user> <folder>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_count_function)
|
||||
{
|
||||
char *sql;
|
||||
@@ -5404,7 +5594,7 @@ SWITCH_STANDARD_API(vm_fsdb_msg_count_function)
|
||||
switch_event_t *my_params = NULL;
|
||||
char *ebuf = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL, *folder = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
@@ -5425,8 +5615,10 @@ SWITCH_STANDARD_API(vm_fsdb_msg_count_function)
|
||||
domain = argv[2];
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
if (argv[4])
|
||||
folder = argv[4];
|
||||
|
||||
if (!profile_name || !domain || !id) {
|
||||
if (!profile_name || !domain || !id || !folder) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
@@ -5437,11 +5629,11 @@ SWITCH_STANDARD_API(vm_fsdb_msg_count_function)
|
||||
}
|
||||
|
||||
sql = switch_mprintf(
|
||||
"SELECT 1, read_flags, count(read_epoch) FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND in_folder = '%q' AND read_epoch = 0 GROUP BY read_flags "
|
||||
"SELECT 1, read_flags, count(read_epoch) FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND in_folder = '%q' AND flags = '' AND in_folder = '%q' GROUP BY read_flags "
|
||||
"UNION "
|
||||
"SELECT 0, read_flags, count(read_epoch) FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND in_folder = '%q' AND read_epoch <> 0 GROUP BY read_flags;",
|
||||
id, domain, "inbox",
|
||||
id, domain, "inbox");
|
||||
"SELECT 0, read_flags, count(read_epoch) FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND in_folder = '%q' AND flags = 'save' AND in_folder= '%q' GROUP BY read_flags;",
|
||||
id, domain, "inbox", folder,
|
||||
id, domain, "inbox", folder);
|
||||
|
||||
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, message_count_callback, &cbt);
|
||||
@@ -5482,14 +5674,20 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load)
|
||||
switch_core_hash_init(&globals.profile_hash, globals.pool);
|
||||
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.running = 1;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_queue_create(&globals.event_queue, VM_EVENT_QUEUE_SIZE, globals.pool);
|
||||
|
||||
if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
|
||||
globals.running = 0;
|
||||
return status;
|
||||
}
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_MESSAGE_QUERY, SWITCH_EVENT_SUBCLASS_ANY, message_query_handler, NULL)
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_MESSAGE_QUERY, SWITCH_EVENT_SUBCLASS_ANY, vm_event_handler, NULL)
|
||||
!= SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
@@ -5534,9 +5732,23 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_voicemail_shutdown)
|
||||
void *val = NULL;
|
||||
const void *key;
|
||||
switch_ssize_t keylen;
|
||||
int sanity = 0;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (globals.running == 1) {
|
||||
globals.running = 0;
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_event_free_subclass(VM_EVENT_MAINT);
|
||||
switch_event_unbind_callback(message_query_handler);
|
||||
switch_event_unbind_callback(vm_event_handler);
|
||||
|
||||
while (globals.threads) {
|
||||
switch_cond_next();
|
||||
if (++sanity >= 60000) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
while ((hi = switch_hash_first(NULL, globals.profile_hash))) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FLITE=flite-1.3.99
|
||||
FLITE=flite-1.5.1
|
||||
|
||||
FLITE_DIR=$(switch_srcdir)/libs/$(FLITE)
|
||||
FLITE_BUILDDIR=$(switch_builddir)/libs/$(FLITE)
|
||||
FLITE_DIR=$(switch_srcdir)/libs/$(FLITE)-current
|
||||
FLITE_BUILDDIR=$(switch_builddir)/libs/$(FLITE)-current
|
||||
|
||||
FLITE_LIBDIR=$(FLITE_BUILDDIR)/build/libs
|
||||
FLITE_A=$(FLITE_LIBDIR)/libflite_cmu_us_awb.a \
|
||||
@@ -18,11 +18,11 @@ include $(BASE)/build/modmake.rules
|
||||
|
||||
$(MODNAME).lo: $(FLITE_A)
|
||||
$(FLITE_DIR):
|
||||
$(GETLIB) $(FLITE)-latest.tar.gz
|
||||
$(GETLIB) $(FLITE)-current.tar.bz2
|
||||
|
||||
$(FLITE_BUILDDIR)/Makefile: $(FLITE_DIR)
|
||||
mkdir -p $(FLITE_BUILDDIR)
|
||||
cd $(FLITE_BUILDDIR) && $(DEFAULT_VARS) $(FLITE_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(FLITE_DIR) --without-audio --with-pic --disable-shared
|
||||
cd $(FLITE_BUILDDIR) && $(DEFAULT_VARS) $(FLITE_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(FLITE_DIR) --with-audio=none --with-pic --disable-shared
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(FLITE_A): $(FLITE_DIR) $(FLITE_BUILDDIR)/Makefile
|
||||
|
||||
@@ -12,7 +12,7 @@ POCKETSPHINX_LA=$(POCKETSPHINX_BUILDDIR)/src/libpocketsphinx/libpocketsphinx.la
|
||||
SPHINXMODEL=communicator_semi_6000_20080321
|
||||
|
||||
LOCAL_CFLAGS=-I$(SPHINXBASE_DIR)/include -I$(POCKETSPHINX_DIR)/include
|
||||
LOCAL_LIBADD=$(SPHINXBASE_LA) $(SPHINXBASE_LA2) $(POCKETSPHINX_LA)
|
||||
LOCAL_LIBADD=$(POCKETSPHINX_LA) $(SPHINXBASE_LA) $(SPHINXBASE_LA2)
|
||||
BASE=../../../..
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
|
||||
@@ -7,5 +7,5 @@ LOCAL_LIBADD=$(SILK_LA)
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
$(SILK_LA): $(SILK_DIR)/.update
|
||||
cd $(SILK_BUILDDIR) && $(MAKE)
|
||||
cd $(SILK_BUILDDIR) && ./configure --disable-shared && make clean && $(MAKE)
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
@@ -192,7 +192,9 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
context->encoder_object.sampleRate = codec->implementation->actual_samples_per_second;
|
||||
|
||||
context->encoder_object.API_sampleRate = codec->implementation->actual_samples_per_second;
|
||||
context->encoder_object.maxInternalSampleRate = codec->implementation->actual_samples_per_second;
|
||||
context->encoder_object.packetSize = codec->implementation->samples_per_packet;
|
||||
context->encoder_object.useInBandFEC = silk_codec_settings.useinbandfec;
|
||||
context->encoder_object.complexity = 0;
|
||||
@@ -210,7 +212,7 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
|
||||
if (SKP_Silk_SDK_InitDecoder(context->dec_state)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
context->decoder_object.sampleRate = codec->implementation->actual_samples_per_second;
|
||||
context->decoder_object.API_sampleRate = codec->implementation->actual_samples_per_second;
|
||||
}
|
||||
|
||||
codec->private_info = context;
|
||||
@@ -241,22 +243,22 @@ void printSilkError(SKP_int16 ret){
|
||||
case SKP_SILK_ENC_PAYLOAD_BUF_TOO_SHORT:
|
||||
message = "Allocated payload buffer too short";
|
||||
break;
|
||||
case SKP_SILK_ENC_WRONG_LOSS_RATE:
|
||||
case SKP_SILK_ENC_INVALID_LOSS_RATE:
|
||||
message = " Loss rate not between 0 and 100 % ";
|
||||
break;
|
||||
case SKP_SILK_ENC_WRONG_COMPLEXITY_SETTING:
|
||||
case SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING:
|
||||
message = "Complexity setting not valid, use 0 ,1 or 2";
|
||||
break;
|
||||
case SKP_SILK_ENC_WRONG_INBAND_FEC_SETTING:
|
||||
case SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING:
|
||||
message = "Inband FEC setting not valid, use 0 or 1 ";
|
||||
break;
|
||||
case SKP_SILK_ENC_WRONG_DTX_SETTING:
|
||||
case SKP_SILK_ENC_INVALID_DTX_SETTING:
|
||||
message = "DTX setting not valid, use 0 or 1";
|
||||
break;
|
||||
case SKP_SILK_ENC_INTERNAL_ERROR:
|
||||
message = "Internal Encoder Error ";
|
||||
break;
|
||||
case SKP_SILK_DEC_WRONG_SAMPLING_FREQUENCY:
|
||||
case SKP_SILK_DEC_INVALID_SAMPLING_FREQUENCY:
|
||||
message = "Output sampling frequency lower than internal decoded sampling frequency";
|
||||
break;
|
||||
case SKP_SILK_DEC_PAYLOAD_TOO_LARGE:
|
||||
@@ -269,7 +271,7 @@ void printSilkError(SKP_int16 ret){
|
||||
message = "unknown";
|
||||
break;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," Silk Error message= %s\n",message);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR," Silk Error: %s\n",message);
|
||||
}
|
||||
|
||||
static switch_status_t switch_silk_encode(switch_codec_t *codec,
|
||||
@@ -296,6 +298,7 @@ static switch_status_t switch_silk_encode(switch_codec_t *codec,
|
||||
if (ret) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SKP_Silk_Encode returned %d!\n", ret);
|
||||
printSilkError(ret);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
*encoded_data_len += nBytes;
|
||||
samples-=pktsz;
|
||||
@@ -330,6 +333,8 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec,
|
||||
&len);
|
||||
if (ret){
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SKP_Silk_Decode returned %d!\n", ret);
|
||||
printSilkError(ret);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
target += len;
|
||||
|
||||
@@ -81,12 +81,20 @@ static switch_status_t exec_app(switch_core_session_t *session, const char *app,
|
||||
|
||||
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_xml_t xcond, xaction, xexpression, xregex;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
char *exten_name = (char *) switch_xml_attr(xexten, "name");
|
||||
int proceed = 0;
|
||||
int proceed = 0, save_proceed = 0;
|
||||
char *expression_expanded = NULL, *field_expanded = NULL;
|
||||
switch_regex_t *re = NULL;
|
||||
switch_regex_t *re = NULL, *save_re = NULL;
|
||||
int offset = 0;
|
||||
const char *tzoff = switch_channel_get_variable(channel, "tod_tz_offset");
|
||||
|
||||
if (!zstr(tzoff) && switch_is_number(tzoff)) {
|
||||
offset = atoi(tzoff);
|
||||
} else {
|
||||
tzoff = NULL;
|
||||
}
|
||||
|
||||
if (!exten_name) {
|
||||
exten_name = "_anon_";
|
||||
@@ -95,13 +103,14 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *
|
||||
for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next) {
|
||||
char *field = NULL;
|
||||
char *do_break_a = NULL;
|
||||
char *expression = 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 = switch_xml_std_datetime_check(xcond);
|
||||
int time_match = switch_xml_std_datetime_check(xcond, tzoff ? &offset : NULL);
|
||||
|
||||
switch_safe_free(field_expanded);
|
||||
switch_safe_free(expression_expanded);
|
||||
@@ -114,17 +123,6 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *
|
||||
|
||||
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")) {
|
||||
@@ -147,41 +145,188 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *
|
||||
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",
|
||||
"Dialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n",
|
||||
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;
|
||||
|
||||
if (field) {
|
||||
if (strchr(field, '$')) {
|
||||
if ((field_expanded = switch_channel_expand_variables(channel, field)) == field) {
|
||||
field_expanded = NULL;
|
||||
field_data = field;
|
||||
switch_channel_del_variable_prefix(channel, "DP_REGEX_MATCH");
|
||||
|
||||
for (xregex = switch_xml_child(xcond, "regex"); xregex; xregex = xregex->next) {
|
||||
time_match = switch_xml_std_datetime_check(xregex, tzoff ? &offset : NULL);
|
||||
|
||||
if (time_match == 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG,
|
||||
"Dialplan: %s Date/Time Match (PASS) [%s]\n",
|
||||
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,
|
||||
"Dialplan: %s Date/TimeMatch (FAIL) [%s]\n",
|
||||
switch_channel_get_name(channel), exten_name);
|
||||
}
|
||||
|
||||
|
||||
if ((xexpression = switch_xml_child(xregex, "expression"))) {
|
||||
expression = switch_str_nil(xexpression->txt);
|
||||
} else {
|
||||
field_data = field_expanded;
|
||||
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,
|
||||
"Dialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n",
|
||||
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,
|
||||
"Dialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n",
|
||||
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,
|
||||
"Dialplan: %s Absolute Condition [%s] match=%s\n", switch_channel_get_name(channel), exten_name, all ? "all" : "any");
|
||||
pass++;
|
||||
if (!all && !xor) break;
|
||||
} else if (time_match == 1) {
|
||||
pass++;
|
||||
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 {
|
||||
field_data = switch_caller_get_field_by_name(caller_profile, field);
|
||||
}
|
||||
if (!field_data) {
|
||||
field_data = "";
|
||||
if ((all && !fail) || (!all && pass)) {
|
||||
anti_action = SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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 {
|
||||
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");
|
||||
expression = (char *) switch_xml_attr_soft(xcond, "expression");
|
||||
}
|
||||
} 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 ((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,
|
||||
"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 (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");
|
||||
|
||||
@@ -145,6 +145,12 @@
|
||||
<Project>{e727e8f6-935d-46fe-8b0e-37834748a0e3}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\libs\win32\openssl\libeay32.2010.vcxproj">
|
||||
<Project>{d331904d-a00a-4694-a5a3-fcff64ab5dbe}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\libs\win32\openssl\ssleay32.2010.vcxproj">
|
||||
<Project>{b4b62169-5ad4-4559-8707-3d933ac5db39}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#define DL_EVENT_LOGIN_FAILURE "dingaling::login_failure"
|
||||
#define DL_EVENT_CONNECTED "dingaling::connected"
|
||||
#define MDL_CHAT_PROTO "jingle"
|
||||
#define MDL_CHAT_FROM_GUESS "auto_from"
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_dingaling_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_dingaling_shutdown);
|
||||
@@ -489,14 +490,30 @@ static void pres_event_handler(switch_event_t *event)
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
static switch_status_t chat_send(const char *proto, const char *from, const char *to, const char *subject,
|
||||
const char *body, const char *type, const char *hint)
|
||||
static switch_status_t chat_send(switch_event_t *message_event)
|
||||
{
|
||||
char *user, *host, *f_user = NULL, *ffrom = NULL, *f_host = NULL, *f_resource = NULL;
|
||||
mdl_profile_t *profile = NULL;
|
||||
const char *proto;
|
||||
const char *from;
|
||||
const char *from_full;
|
||||
const char *to_full;
|
||||
const char *to;
|
||||
const char *body;
|
||||
const char *hint;
|
||||
const char *profile_name;
|
||||
|
||||
proto = switch_event_get_header(message_event, "proto");
|
||||
from = switch_event_get_header(message_event, "from");
|
||||
from_full = switch_event_get_header(message_event, "from_full");
|
||||
to_full = switch_event_get_header(message_event, "to_full");
|
||||
to = switch_event_get_header(message_event, "to");
|
||||
body = switch_event_get_body(message_event);
|
||||
hint = switch_event_get_header(message_event, "hint");
|
||||
profile_name = switch_event_get_header(message_event, "ldl_profile");
|
||||
|
||||
switch_assert(proto != NULL);
|
||||
|
||||
|
||||
if (from && (f_user = strdup(from))) {
|
||||
if ((f_host = strchr(f_user, '@'))) {
|
||||
*f_host++ = '\0';
|
||||
@@ -506,12 +523,18 @@ static switch_status_t chat_send(const char *proto, const char *from, const char
|
||||
}
|
||||
}
|
||||
|
||||
if (to && (user = strdup(to))) {
|
||||
if ((profile_name && (profile = switch_core_hash_find(globals.profile_hash, profile_name)))) {
|
||||
from = from_full;
|
||||
to = to_full;
|
||||
|
||||
ldl_handle_send_msg(profile->handle, (char *) from, (char *) to, NULL, switch_str_nil(body));
|
||||
} else if (to && (user = strdup(to))) {
|
||||
if ((host = strchr(user, '@'))) {
|
||||
*host++ = '\0';
|
||||
}
|
||||
|
||||
if (f_host && (profile = switch_core_hash_find(globals.profile_hash, f_host))) {
|
||||
if (f_host && ((profile_name && (profile = switch_core_hash_find(globals.profile_hash, profile_name)))
|
||||
|| (profile = switch_core_hash_find(globals.profile_hash, f_host)))) {
|
||||
|
||||
if (!strcmp(proto, MDL_CHAT_PROTO)) {
|
||||
from = hint;
|
||||
@@ -528,7 +551,12 @@ static switch_status_t chat_send(const char *proto, const char *from, const char
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
ldl_handle_send_msg(profile->handle, (char *) from, (char *) to, NULL, switch_str_nil(body));
|
||||
if (!(profile->user_flags & LDL_FLAG_COMPONENT) && !strcmp(f_user, MDL_CHAT_FROM_GUESS)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using auto_from jid address for profile %s\n", profile->name);
|
||||
ldl_handle_send_msg(profile->handle, NULL, (char *) to, NULL, switch_str_nil(body));
|
||||
} else {
|
||||
ldl_handle_send_msg(profile->handle, (char *) from, (char *) to, NULL, switch_str_nil(body));
|
||||
}
|
||||
switch_safe_free(ffrom);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile %s\n", f_host ? f_host : "NULL");
|
||||
@@ -1575,8 +1603,10 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
|
||||
channel_answer_channel(session);
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_BRIDGE:
|
||||
rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_STICK);
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
|
||||
rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_UNSTICK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2876,6 +2906,8 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
|
||||
char *proto = MDL_CHAT_PROTO;
|
||||
char *pproto = NULL, *ffrom = NULL;
|
||||
char *hint;
|
||||
switch_event_t *event;
|
||||
char *from_user, *from_host;
|
||||
#ifdef AUTO_REPLY
|
||||
if (profile->auto_reply) {
|
||||
ldl_handle_send_msg(handle,
|
||||
@@ -2902,10 +2934,45 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
|
||||
from = ffrom;
|
||||
}
|
||||
|
||||
if (strcasecmp(proto, MDL_CHAT_PROTO)) { /* yes no ! on purpose */
|
||||
switch_core_chat_send(proto, MDL_CHAT_PROTO, from, to, subject, switch_str_nil(msg), NULL, hint);
|
||||
from_user = strdup(from);
|
||||
if ((from_host = strchr(from_user, '@'))) {
|
||||
*from_host++ = '\0';
|
||||
}
|
||||
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", from);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_user", from_user);
|
||||
if (from_host) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_host", from_host);
|
||||
}
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", to);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", subject);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "text/plain");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hint", hint);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_full", hint);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "ldl_profile", profile->name);
|
||||
|
||||
if (msg) {
|
||||
switch_event_add_body(event, "%s", msg);
|
||||
}
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
switch_safe_free(from_user);
|
||||
|
||||
if (!zstr(msg)) {
|
||||
if (strcasecmp(proto, MDL_CHAT_PROTO)) { /* yes no ! on purpose */
|
||||
switch_core_chat_send(proto, event);
|
||||
}
|
||||
|
||||
switch_core_chat_send("GLOBAL", event);
|
||||
}
|
||||
|
||||
switch_event_destroy(&event);
|
||||
|
||||
switch_safe_free(pproto);
|
||||
switch_safe_free(ffrom);
|
||||
}
|
||||
|
||||
@@ -31,5 +31,6 @@ Enjoy
|
||||
|
||||
-giovanni
|
||||
|
||||
|
||||
< gmaruzz at gmail dot com >
|
||||
|
||||
|
||||
@@ -928,7 +928,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
while (p && *p) {
|
||||
switch_dtmf_t dtmf;
|
||||
switch_dtmf_t dtmf = {0};
|
||||
dtmf.digit = *p;
|
||||
dtmf.duration = SWITCH_DEFAULT_DTMF_DURATION;
|
||||
switch_channel_queue_dtmf(channel, &dtmf);
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
fix stale calls then fax send/recv in some circumstance
|
||||
remove SWITCH_RTP_FLAG_AUTO_CNG - works incorrectly.
|
||||
moves the switch_rtp_request_port() call from the contructor to FSH323Connection::CreateRealTimeLogicalChannel() - fix
|
||||
rtp port leak. tnx to Peter Olsson.
|
||||
fix log printing
|
||||
fix small interoperability issues if remote endpoint send progress twice
|
||||
make sure dtmfinband gets initialized
|
||||
make gk-identifier and gk-interface settings optional (documentation sayed that about gk-identifier already)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*
|
||||
* mod_h323.cpp -- H323 endpoint
|
||||
*
|
||||
* Version 0.0.57
|
||||
* Version 0.0.58
|
||||
*/
|
||||
|
||||
//#define DEBUG_RTP_PACKETS
|
||||
@@ -201,10 +201,14 @@ SWITCH_END_EXTERN_C
|
||||
|
||||
void h_timer(unsigned sec)
|
||||
{
|
||||
#ifdef WIN32
|
||||
switch_sleep(sec * 1000000);
|
||||
#else
|
||||
timeval timeout;
|
||||
timeout.tv_sec = sec;
|
||||
timeout.tv_usec = 0;
|
||||
select(0, NULL, NULL, NULL, &timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -413,7 +417,7 @@ bool FSH323EndPoint::Initialise(switch_loadable_module_interface_t *iface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_fax_old_asn) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "--->fax_old_asn\n");
|
||||
SetT38_IFP_PRE();
|
||||
@@ -714,6 +718,7 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran
|
||||
, m_rtp_resetting(0)
|
||||
, m_isRequst_fax(false)
|
||||
, m_channel_hangup(false)
|
||||
, m_RTPlocalPort(0)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"======>FSH323Connection::FSH323Connection [%p]\n",this);
|
||||
|
||||
@@ -739,8 +744,6 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran
|
||||
|
||||
switch_channel_set_state(m_fsChannel, CS_INIT);
|
||||
}
|
||||
|
||||
m_RTPlocalPort = switch_rtp_request_port((const char *)m_RTPlocalIP.AsString());
|
||||
}
|
||||
|
||||
FSH323Connection::~FSH323Connection()
|
||||
@@ -974,6 +977,9 @@ H323Channel* FSH323Connection::CreateRealTimeLogicalChannel(const H323Capability
|
||||
|
||||
H323TransportAddress m_h323transportadd = GetSignallingChannel()->GetLocalAddress();
|
||||
m_h323transportadd.GetIpAddress(m_RTPlocalIP);
|
||||
if (!m_RTPlocalPort) {
|
||||
m_RTPlocalPort = switch_rtp_request_port((const char *)m_RTPlocalIP.AsString());
|
||||
}
|
||||
|
||||
return new FSH323_ExternalRTPChannel(*this, capability, dir, sessionID,m_RTPlocalIP,m_RTPlocalPort);
|
||||
}
|
||||
@@ -1096,7 +1102,7 @@ bool FSH323Connection::OnSendReleaseComplete(H323SignalPDU & pdu)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"======>FSH323Connection::OnSendReleaseComplete cause = %u\n",(switch_call_cause_t)pdu.GetQ931().GetCause());
|
||||
|
||||
switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
switch_channel_hangup(m_fsChannel, (switch_call_cause_t) pdu.GetQ931().GetCause());
|
||||
return H323Connection::OnSendReleaseComplete(pdu);
|
||||
}
|
||||
|
||||
@@ -1331,7 +1337,19 @@ void FSH323Connection::OnModeChanged(const H245_ModeDescription & newMode)
|
||||
const char *uuid = switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
if (uuid != NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"uuid:%s\n",uuid);
|
||||
switch_channel_set_private(switch_core_session_get_channel(switch_core_session_locate(switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE))), "t38_options", t38_options);
|
||||
|
||||
switch_core_session_t *session = switch_core_session_locate(switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE));
|
||||
if (session) {
|
||||
switch_channel_t * channel = switch_core_session_get_channel(session);
|
||||
if (channel) {
|
||||
switch_channel_set_private(channel, "t38_options", t38_options);
|
||||
}else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no channel?\n");
|
||||
}
|
||||
switch_core_session_rwunlock(session);
|
||||
}else{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no session\n");
|
||||
}
|
||||
|
||||
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
@@ -1885,6 +1903,7 @@ FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel(FSH323Connection& connectio
|
||||
, m_capability(&capability)
|
||||
, m_RTPlocalPort(dataPort)
|
||||
, m_sessionID(sessionID)
|
||||
, m_rtp_resetting(0)
|
||||
{
|
||||
m_RTPlocalIP = (const char *)ip.AsString();
|
||||
SetExternalAddress(H323TransportAddress(ip, dataPort), H323TransportAddress(ip, dataPort+1));
|
||||
@@ -2044,9 +2063,6 @@ PBoolean FSH323_ExternalRTPChannel::Start()
|
||||
, GetMainTypes[m_capability->GetMainType()],(const char*)(m_capability->GetFormatName()),this);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"%s initialise %s codec %s for connection [%p]\n",switch_channel_get_name(m_fsChannel),((GetDirection() == IsReceiver)? " read" : " write")
|
||||
, GetMainTypes[m_capability->GetMainType()],(const char*)(m_capability->GetFormatName()),this);
|
||||
|
||||
if (GetDirection() == IsReceiver) {
|
||||
//m_readFrame.rate = tech_pvt->read_codec.implementation->actual_samples_per_second;
|
||||
|
||||
@@ -2111,7 +2127,7 @@ PBoolean FSH323_ExternalRTPChannel::Start()
|
||||
|
||||
bool ch_port = false;
|
||||
if (tech_pvt->rtp_session != NULL){
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------------->old remot port = %d new remote port = %d\n",switch_rtp_get_remote_port(tech_pvt->rtp_session),m_RTPremotePort);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------------->old remote port = %d new remote port = %d\n",switch_rtp_get_remote_port(tech_pvt->rtp_session),m_RTPremotePort);
|
||||
if ((switch_rtp_get_remote_port(tech_pvt->rtp_session) != m_RTPremotePort) && (GetDirection() != IsReceiver) && (m_conn->m_rtp_resetting == 1)){
|
||||
ch_port = true;
|
||||
m_conn->m_startRTP = false;
|
||||
@@ -2129,7 +2145,7 @@ PBoolean FSH323_ExternalRTPChannel::Start()
|
||||
}
|
||||
|
||||
if ((!m_conn->m_startRTP)) {
|
||||
flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT|SWITCH_RTP_FLAG_AUTO_CNG|SWITCH_RTP_FLAG_RAW_WRITE);
|
||||
flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT|SWITCH_RTP_FLAG_RAW_WRITE);
|
||||
|
||||
if (mod_h323_globals.use_rtp_timer) {
|
||||
flags |= SWITCH_RTP_FLAG_USE_TIMER;
|
||||
@@ -2399,9 +2415,13 @@ static switch_status_t on_hangup(switch_core_session_t *session)
|
||||
switch_mutex_lock(tech_pvt->h323_mutex);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_unlock\n");
|
||||
switch_mutex_unlock(tech_pvt->h323_mutex);
|
||||
|
||||
while (tech_pvt->active_connection){
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Wait clear h323 connection\n");
|
||||
h_timer(1);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H323 connection was cleared successfully\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
*
|
||||
* mod_h323.h -- H323 endpoint
|
||||
*
|
||||
* Version 0.0.57
|
||||
* Version 0.0.58
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
|
||||
|
||||
@@ -1399,6 +1399,8 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
|
||||
case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
|
||||
case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
|
||||
case SWITCH_CAUSE_INVALID_GATEWAY:
|
||||
case SWITCH_CAUSE_INVALID_URL:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
|
||||
case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
|
||||
@@ -1430,7 +1432,9 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
|
||||
case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
|
||||
case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_INVALID_PROFILE:
|
||||
case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_GATEWAY_DOWN:
|
||||
case SWITCH_CAUSE_FACILITY_REJECTED:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
|
||||
case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
|
||||
@@ -1448,6 +1452,8 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
|
||||
case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
|
||||
case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
|
||||
case SWITCH_CAUSE_INVALID_GATEWAY:
|
||||
case SWITCH_CAUSE_INVALID_URL:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
|
||||
case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
|
||||
@@ -1480,6 +1486,7 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
|
||||
case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_GATEWAY_DOWN:
|
||||
case SWITCH_CAUSE_FACILITY_REJECTED:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
|
||||
case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
|
||||
@@ -1497,6 +1504,8 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
|
||||
case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
|
||||
case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
|
||||
case SWITCH_CAUSE_INVALID_GATEWAY:
|
||||
case SWITCH_CAUSE_INVALID_URL:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
|
||||
case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
|
||||
@@ -1529,6 +1538,7 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
|
||||
case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_GATEWAY_DOWN:
|
||||
case SWITCH_CAUSE_FACILITY_REJECTED:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
|
||||
case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
|
||||
@@ -1553,6 +1563,8 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
|
||||
case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
|
||||
case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
|
||||
case SWITCH_CAUSE_INVALID_GATEWAY:
|
||||
case SWITCH_CAUSE_INVALID_URL:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
|
||||
case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
|
||||
@@ -1585,6 +1597,7 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
|
||||
case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_GATEWAY_DOWN:
|
||||
case SWITCH_CAUSE_FACILITY_REJECTED:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
|
||||
case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
|
||||
@@ -1622,6 +1635,8 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
|
||||
case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
|
||||
case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
|
||||
case SWITCH_CAUSE_INVALID_GATEWAY:
|
||||
case SWITCH_CAUSE_INVALID_URL:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
|
||||
case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
|
||||
@@ -1629,6 +1644,7 @@ int BoardE1::KhompPvtR2::callFailFromCause(int cause)
|
||||
case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
|
||||
case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
|
||||
case SWITCH_CAUSE_GATEWAY_DOWN:
|
||||
case SWITCH_CAUSE_FACILITY_REJECTED:
|
||||
case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
|
||||
case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
|
||||
|
||||
@@ -84,6 +84,7 @@ struct private_object {
|
||||
char *other_uuid;
|
||||
switch_queue_t *frame_queue;
|
||||
int64_t packet_count;
|
||||
int first_cng;
|
||||
};
|
||||
|
||||
typedef struct private_object private_t;
|
||||
@@ -115,6 +116,7 @@ static void clear_queue(private_t *tech_pvt)
|
||||
switch_frame_t *frame = (switch_frame_t *) pop;
|
||||
switch_frame_free(&frame);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, switch_codec_t *codec)
|
||||
@@ -174,7 +176,7 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
|
||||
tech_pvt->cng_frame.datalen = 2;
|
||||
|
||||
tech_pvt->bowout_frame_count = (tech_pvt->read_codec.implementation->actual_samples_per_second /
|
||||
tech_pvt->read_codec.implementation->samples_per_packet) * 3;
|
||||
tech_pvt->read_codec.implementation->samples_per_packet) * 2;
|
||||
|
||||
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
|
||||
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
|
||||
@@ -594,11 +596,16 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
*frame = tech_pvt->write_frame;
|
||||
tech_pvt->packet_count++;
|
||||
switch_clear_flag(tech_pvt->write_frame, SFF_CNG);
|
||||
tech_pvt->first_cng = 0;
|
||||
} else {
|
||||
*frame = &tech_pvt->cng_frame;
|
||||
tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
|
||||
tech_pvt->cng_frame.datalen = tech_pvt->read_codec.implementation->decoded_bytes_per_packet;
|
||||
switch_set_flag((&tech_pvt->cng_frame), SFF_CNG);
|
||||
if (!tech_pvt->first_cng) {
|
||||
switch_yield(tech_pvt->read_codec.implementation->samples_per_packet);
|
||||
tech_pvt->first_cng = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -644,33 +651,56 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) &&
|
||||
switch_channel_test_flag(tech_pvt->other_channel, CF_BRIDGED) &&
|
||||
switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) &&
|
||||
switch_channel_test_flag(tech_pvt->other_channel, CF_ANSWERED) && !--tech_pvt->bowout_frame_count <= 0) {
|
||||
switch_channel_test_flag(tech_pvt->other_channel, CF_ANSWERED) && --tech_pvt->bowout_frame_count <= 0) {
|
||||
const char *a_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
const char *b_uuid = switch_channel_get_variable(tech_pvt->other_channel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
const char *vetoa, *vetob;
|
||||
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT);
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT);
|
||||
|
||||
vetoa = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout");
|
||||
vetob = switch_channel_get_variable(tech_pvt->other_tech_pvt->channel, "loopback_bowout");
|
||||
|
||||
if ((!vetoa || switch_true(vetoa)) && (!vetob || switch_true(vetob))) {
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
|
||||
switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
|
||||
switch_core_session_t *br_a, *br_b;
|
||||
switch_channel_t *ch_a = NULL, *ch_b = NULL;
|
||||
int good_to_go = 0;
|
||||
|
||||
if ((br_a = switch_core_session_locate(a_uuid))) {
|
||||
ch_a = switch_core_session_get_channel(br_a);
|
||||
}
|
||||
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT_USED);
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT_USED);
|
||||
if ((br_b = switch_core_session_locate(b_uuid))) {
|
||||
ch_b = switch_core_session_get_channel(br_b);
|
||||
}
|
||||
|
||||
if (ch_a && ch_b && switch_channel_test_flag(ch_a, CF_BRIDGED) && switch_channel_test_flag(ch_b, CF_BRIDGED)) {
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT);
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT);
|
||||
|
||||
if (a_uuid && b_uuid) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
|
||||
"%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel));
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
|
||||
switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
|
||||
|
||||
/* channel_masquerade eat your heart out....... */
|
||||
switch_ivr_uuid_bridge(a_uuid, b_uuid);
|
||||
switch_mutex_unlock(tech_pvt->mutex);
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT_USED);
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT_USED);
|
||||
|
||||
if (a_uuid && b_uuid) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
|
||||
"%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel));
|
||||
|
||||
/* channel_masquerade eat your heart out....... */
|
||||
switch_ivr_uuid_bridge(a_uuid, b_uuid);
|
||||
good_to_go = 1;
|
||||
switch_mutex_unlock(tech_pvt->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
if (br_a) switch_core_session_rwunlock(br_a);
|
||||
if (br_b) switch_core_session_rwunlock(br_b);
|
||||
|
||||
if (good_to_go) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,15 +832,20 @@ static switch_status_t loopback_bowout_on_execute_state_handler(switch_core_sess
|
||||
switch_core_session_read_lock(tech_pvt->other_session);
|
||||
b_channel = switch_core_session_get_channel(tech_pvt->other_session);
|
||||
|
||||
/* Wait for b_channel to be fully bridged */
|
||||
switch_channel_wait_for_flag(b_channel, CF_BRIDGED, SWITCH_TRUE, 5000, NULL);
|
||||
|
||||
uuid = switch_channel_get_variable(b_channel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
|
||||
if (uuid && (other_session = switch_core_session_locate(uuid))) {
|
||||
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
|
||||
switch_caller_profile_t *cp, *clone;
|
||||
|
||||
|
||||
switch_channel_wait_for_state(other_channel, NULL, CS_EXCHANGE_MEDIA);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->other_session), SWITCH_LOG_INFO, "Replacing loopback channel: %s with real channel: %s\n",
|
||||
switch_channel_get_name(b_channel), switch_channel_get_name(other_channel));
|
||||
|
||||
|
||||
if ((cp = switch_channel_get_caller_profile(channel))) {
|
||||
clone = switch_caller_profile_clone(other_session, cp);
|
||||
clone->originator_caller_profile = NULL;
|
||||
@@ -831,7 +866,7 @@ static switch_status_t loopback_bowout_on_execute_state_handler(switch_core_sess
|
||||
switch_core_session_rwunlock(tech_pvt->other_session);
|
||||
|
||||
switch_core_event_hook_remove_state_change(session, loopback_bowout_on_execute_state_handler);
|
||||
|
||||
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1324,7 +1324,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_load)
|
||||
globals.read_frame.buflen = sizeof(globals.databuf);
|
||||
globals.cng_frame.data = globals.cngbuf;
|
||||
globals.cng_frame.buflen = sizeof(globals.cngbuf);
|
||||
globals.cng_frame.datalen = switch_samples_per_packet(globals.sample_rate, globals.codec_ms) * 2;
|
||||
switch_set_flag((&globals.cng_frame), SFF_CNG);
|
||||
globals.flags = GFLAG_EAR | GFLAG_MOUTH;
|
||||
/* dual streams makes portaudio on solaris choke */
|
||||
@@ -1750,6 +1749,8 @@ static switch_status_t load_config(void)
|
||||
globals.codec_ms = 20;
|
||||
}
|
||||
|
||||
globals.cng_frame.datalen = switch_samples_per_packet(globals.sample_rate, globals.codec_ms) * 2;
|
||||
|
||||
if (!globals.ring_interval) {
|
||||
globals.ring_interval = 5;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
|
||||
}
|
||||
if (PaUtil_WriteRingBuffer(&data->inFIFOs[c], chanSamples, numBytes) != numBytes) {
|
||||
PaUtil_FlushRingBuffer(&data->inFIFOs[c]);
|
||||
PaUtil_WriteRingBuffer(&data->inFIFOs[c], inputBuffer, numBytes);
|
||||
PaUtil_WriteRingBuffer(&data->inFIFOs[c], chanSamples, numBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +266,6 @@ switch_status_t rtmp_on_hangup(switch_core_session_t *session)
|
||||
rtmp_notify_call_state(session);
|
||||
rtmp_send_onhangup(session);
|
||||
|
||||
switch_mutex_lock(tech_pvt->rtmp_session->count_mutex);
|
||||
tech_pvt->rtmp_session->active_sessions--;
|
||||
switch_mutex_unlock(tech_pvt->rtmp_session->count_mutex);
|
||||
|
||||
switch_core_hash_delete_wrlock(tech_pvt->rtmp_session->session_hash, switch_core_session_get_uuid(session), tech_pvt->rtmp_session->session_rwlock);
|
||||
|
||||
switch_mutex_lock(tech_pvt->rtmp_session->profile->mutex);
|
||||
@@ -279,6 +275,10 @@ switch_status_t rtmp_on_hangup(switch_core_session_t *session)
|
||||
}
|
||||
switch_mutex_unlock(tech_pvt->rtmp_session->profile->mutex);
|
||||
|
||||
switch_mutex_lock(tech_pvt->rtmp_session->count_mutex);
|
||||
tech_pvt->rtmp_session->active_sessions--;
|
||||
switch_mutex_unlock(tech_pvt->rtmp_session->count_mutex);
|
||||
|
||||
#ifndef RTMP_DONT_HOLD
|
||||
if (switch_channel_test_flag(channel, CF_HOLD)) {
|
||||
switch_channel_mark_hold(channel, SWITCH_FALSE);
|
||||
@@ -407,6 +407,7 @@ switch_status_t rtmp_read_frame(switch_core_session_t *session, switch_frame_t *
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
cng:
|
||||
|
||||
data = (switch_byte_t *) tech_pvt->read_frame.data;
|
||||
data[0] = 65;
|
||||
data[1] = 0;
|
||||
@@ -414,7 +415,7 @@ cng:
|
||||
tech_pvt->read_frame.flags = SFF_CNG;
|
||||
tech_pvt->read_frame.codec = &tech_pvt->read_codec;
|
||||
|
||||
switch_core_timer_sync(&tech_pvt->timer);
|
||||
//switch_core_timer_sync(&tech_pvt->timer);
|
||||
|
||||
*frame = &tech_pvt->read_frame;
|
||||
|
||||
@@ -515,13 +516,13 @@ switch_status_t rtmp_receive_message(switch_core_session_t *session, switch_core
|
||||
const char *name = msg->string_array_arg[0], *number = msg->string_array_arg[1];
|
||||
char *arg = NULL;
|
||||
char *argv[2] = { 0 };
|
||||
int argc;
|
||||
//int argc;
|
||||
|
||||
if (zstr(name) && !zstr(msg->string_arg)) {
|
||||
arg = strdup(msg->string_arg);
|
||||
switch_assert(arg);
|
||||
|
||||
argc = switch_separate_string(arg, '|', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_separate_string(arg, '|', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
name = argv[0];
|
||||
number = argv[1];
|
||||
|
||||
|
||||
@@ -520,6 +520,7 @@ struct rtmp_private {
|
||||
const char *auth;
|
||||
|
||||
uint16_t maxlen;
|
||||
int over_size;
|
||||
};
|
||||
|
||||
struct rtmp_reg;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Mathieu Rene <mrene@avgs.ca>
|
||||
* Joao Mesquita <jmesquita@freeswitch.org>
|
||||
*
|
||||
* rtmp.c -- RTMP Protocol Handler
|
||||
*
|
||||
@@ -104,7 +105,9 @@ void rtmp_handle_control(rtmp_session_t *rsession, int amfnumber)
|
||||
void rtmp_handle_invoke(rtmp_session_t *rsession, int amfnumber)
|
||||
{
|
||||
rtmp_state_t *state = &rsession->amfstate[amfnumber];
|
||||
//amf0_data *dump;
|
||||
#ifdef RTMP_DEBUG_IO
|
||||
amf0_data *dump;
|
||||
#endif
|
||||
int i = 0;
|
||||
buffer_helper_t helper = { state->buf, 0, state->origlen };
|
||||
int64_t transaction_id;
|
||||
@@ -188,9 +191,15 @@ switch_status_t rtmp_check_auth(rtmp_session_t *rsession, const char *user, cons
|
||||
switch_xml_t xml = NULL, x_param, x_params;
|
||||
switch_bool_t allow_empty_password = SWITCH_FALSE;
|
||||
const char *passwd = NULL;
|
||||
switch_bool_t disallow_multiple_registration = SWITCH_FALSE;
|
||||
switch_event_t *locate_params;
|
||||
|
||||
switch_event_create(&locate_params, SWITCH_EVENT_GENERAL);
|
||||
switch_assert(locate_params);
|
||||
switch_event_add_header_string(locate_params, SWITCH_STACK_BOTTOM, "source", "mod_rtmp");
|
||||
|
||||
/* Locate user */
|
||||
if (switch_xml_locate_user_merged("id", user, domain, NULL, &xml, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_xml_locate_user_merged("id", user, domain, NULL, &xml, locate_params) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_WARNING, "Authentication failed. No such user %s@%s\n", user, domain);
|
||||
goto done;
|
||||
}
|
||||
@@ -206,6 +215,9 @@ switch_status_t rtmp_check_auth(rtmp_session_t *rsession, const char *user, cons
|
||||
if (!strcasecmp(var, "allow-empty-password")) {
|
||||
allow_empty_password = switch_true(val);
|
||||
}
|
||||
if (!strcasecmp(var, "disallow-multiple-registration")) {
|
||||
disallow_multiple_registration = switch_true(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +238,36 @@ switch_status_t rtmp_check_auth(rtmp_session_t *rsession, const char *user, cons
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_WARNING, "Authentication failed for %s@%s\n", user, domain);
|
||||
}
|
||||
|
||||
if (disallow_multiple_registration) {
|
||||
switch_hash_index_t *hi;
|
||||
switch_thread_rwlock_rdlock(rsession->profile->session_rwlock);
|
||||
for (hi = switch_hash_first(NULL, rsession->profile->session_hash); hi; hi = switch_hash_next(hi)) {
|
||||
void *val;
|
||||
const void *key;
|
||||
switch_ssize_t keylen;
|
||||
rtmp_session_t *item;
|
||||
switch_hash_this(hi, &key, &keylen, &val);
|
||||
|
||||
item = (rtmp_session_t *)val;
|
||||
if (rtmp_session_check_user(item, user, domain) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Logging out %s@%s on RTMP sesssion [%s]\n", user, domain, item->uuid);
|
||||
if (rtmp_session_logout(item, user, domain) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_ERROR, "Unable to logout %s@%s on RTMP sesssion [%s]\n", user, domain, item->uuid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
switch_thread_rwlock_unlock(rsession->profile->session_rwlock);
|
||||
}
|
||||
|
||||
done:
|
||||
if (xml) {
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
switch_event_destroy(&locate_params);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -604,7 +641,7 @@ switch_status_t rtmp_send_message(rtmp_session_t *rsession, uint8_t amfnumber, u
|
||||
}
|
||||
end:
|
||||
switch_mutex_unlock(rsession->socket_mutex);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Returns SWITCH_STATUS_SUCCESS of the connection is still active or SWITCH_STATUS_FALSE to tear it down */
|
||||
@@ -850,10 +887,18 @@ switch_status_t rtmp_handle_data(rtmp_session_t *rsession)
|
||||
uint16_t len = state->origlen;
|
||||
|
||||
switch_mutex_lock(rsession->tech_pvt->readbuf_mutex);
|
||||
if (rsession->tech_pvt->maxlen && switch_buffer_inuse(rsession->tech_pvt->readbuf) > rsession->tech_pvt->maxlen * 3) {
|
||||
if (rsession->tech_pvt->maxlen && switch_buffer_inuse(rsession->tech_pvt->readbuf) > rsession->tech_pvt->maxlen * 40) {
|
||||
rsession->tech_pvt->over_size++;
|
||||
} else {
|
||||
rsession->tech_pvt->over_size = 0;
|
||||
}
|
||||
if (rsession->tech_pvt->over_size > 10) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"%s buffer > %u for 10 consecutive packets... Flushing buffer\n",
|
||||
switch_core_session_get_name(rsession->tech_pvt->session), rsession->tech_pvt->maxlen * 40);
|
||||
switch_buffer_zero(rsession->tech_pvt->readbuf);
|
||||
#ifdef RTMP_DEBUG_IO
|
||||
fprintf(rsession->io_debug_in, "[chunk_stream=%d type=0x%x ts=%d stream_id=0x%x] FLUSH BUFFER [exceeded %u]\n", rsession->amfnumber, state->type, (int)state->ts, state->stream_id, rsession->tech_pvt->maxlen * 3);
|
||||
fprintf(rsession->io_debug_in, "[chunk_stream=%d type=0x%x ts=%d stream_id=0x%x] FLUSH BUFFER [exceeded %u]\n", rsession->amfnumber, state->type, (int)state->ts, state->stream_id, rsession->tech_pvt->maxlen * 5);
|
||||
#endif
|
||||
}
|
||||
switch_buffer_write(rsession->tech_pvt->readbuf, &len, 2);
|
||||
|
||||
@@ -301,7 +301,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_makeCall)
|
||||
amf_object_to_event(argv[3], &event);
|
||||
}
|
||||
|
||||
if (rtmp_session_create_call(rsession, &newsession, 0, RTMP_DEFAULT_STREAM_AUDIO, number, user, domain, event) != SWITCH_CAUSE_NONE) {
|
||||
if (rtmp_session_create_call(rsession, &newsession, 0, RTMP_DEFAULT_STREAM_AUDIO, number, user, domain, event) != SWITCH_CAUSE_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_ERROR, "Couldn't create call.\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,10 @@ static switch_status_t rtmp_tcp_read(rtmp_session_t *rsession, unsigned char *bu
|
||||
switch_size_t olen = *len;
|
||||
#endif
|
||||
switch_assert(*len > 0 && *len < 1024000);
|
||||
status = switch_socket_recv(io_pvt->socket, (char*)buf, len);
|
||||
|
||||
do {
|
||||
status = switch_socket_recv(io_pvt->socket, (char*)buf, len);
|
||||
} while(status != SWITCH_STATUS_SUCCESS && SWITCH_STATUS_IS_BREAK(status));
|
||||
|
||||
#ifdef RTMP_DEBUG_IO
|
||||
{
|
||||
@@ -143,7 +146,7 @@ static switch_status_t rtmp_tcp_write(rtmp_session_t *rsession, const unsigned c
|
||||
|
||||
status = switch_socket_send_nonblock(io_pvt->socket, (char*)buf, len);
|
||||
|
||||
if (*len < orig_len) {
|
||||
if (*len > 0 && *len < orig_len) {
|
||||
|
||||
if (rsession->state >= RS_DESTROY) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@@ -197,10 +200,10 @@ void *SWITCH_THREAD_FUNC rtmp_io_tcp_thread(switch_thread_t *thread, void *obj)
|
||||
switch_mutex_unlock(io->mutex);
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_TIMEOUT) {
|
||||
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "pollset_poll failed\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "pollset_poll failed\n");
|
||||
continue;
|
||||
} else if (status == SWITCH_STATUS_TIMEOUT) {
|
||||
switch_yield(1);
|
||||
switch_cond_next();
|
||||
}
|
||||
|
||||
for (i = 0; i < numfds; i++) {
|
||||
@@ -219,6 +222,10 @@ void *SWITCH_THREAD_FUNC rtmp_io_tcp_thread(switch_thread_t *thread, void *obj)
|
||||
if (switch_socket_opt_set(newsocket, SWITCH_SO_NONBLOCK, TRUE)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't set socket as non-blocking\n");
|
||||
}
|
||||
|
||||
if (switch_socket_opt_set(newsocket, SWITCH_SO_TCP_NODELAY, 1)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't disable Nagle.\n");
|
||||
}
|
||||
|
||||
if (rtmp_session_request(io->base.profile, &newsession) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTMP session request failed\n");
|
||||
@@ -314,6 +321,9 @@ switch_status_t rtmp_tcp_init(rtmp_profile_t *profile, const char *bindaddr, rtm
|
||||
if (switch_socket_opt_set(io_tcp->listen_socket, SWITCH_SO_REUSEADDR, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
if (switch_socket_opt_set(io_tcp->listen_socket, SWITCH_SO_TCP_NODELAY, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
if (switch_socket_bind(io_tcp->listen_socket, sa)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
*/
|
||||
|
||||
#include "skypopen.h"
|
||||
#define MDL_CHAT_PROTO "skype"
|
||||
#define SKYPE_CHAT_PROTO "skype"
|
||||
|
||||
#ifdef WIN32
|
||||
/***************/
|
||||
@@ -838,7 +838,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
|
||||
if (switch_test_flag(tech_pvt, TFLAG_PROGRESS)) {
|
||||
//DEBUGA_SKYPE("CHANNEL READ FRAME in TFLAG_PROGRESS goto CNG\n", SKYPOPEN_P_LOG);
|
||||
switch_sleep(MS_SKYPOPEN * 1000);
|
||||
//switch_sleep(MS_SKYPOPEN * 1000);
|
||||
goto cng;
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
DEBUGA_SKYPE("skypopen_audio_read going back to read\n", SKYPOPEN_P_LOG);
|
||||
goto read;
|
||||
}
|
||||
DEBUGA_SKYPE("skypopen_audio_read Silence\n", SKYPOPEN_P_LOG);
|
||||
DEBUGA_SKYPE("READ BUFFER EMPTY, skypopen_audio_read Silence\n", SKYPOPEN_P_LOG);
|
||||
memset(tech_pvt->read_frame.data, 255, BYTES_PER_FRAME);
|
||||
tech_pvt->read_frame.datalen = BYTES_PER_FRAME;
|
||||
|
||||
@@ -943,7 +943,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
if(channel){
|
||||
|
||||
while (p && *p) {
|
||||
switch_dtmf_t dtmf;
|
||||
switch_dtmf_t dtmf = {0};
|
||||
dtmf.digit = *p;
|
||||
dtmf.duration = SWITCH_DEFAULT_DTMF_DURATION;
|
||||
switch_channel_queue_dtmf(channel, &dtmf);
|
||||
@@ -1022,17 +1022,16 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
|
||||
switch_mutex_lock(tech_pvt->mutex_audio_cli);
|
||||
if (switch_buffer_freespace(tech_pvt->write_buffer) < frame->datalen) {
|
||||
DEBUGA_SKYPE("NO SPACE WRITE: %d\n", SKYPOPEN_P_LOG, frame->datalen);
|
||||
switch_buffer_zero(tech_pvt->write_buffer);
|
||||
no_space = 1;
|
||||
}
|
||||
switch_buffer_write(tech_pvt->write_buffer, frame->data, frame->datalen);
|
||||
switch_mutex_unlock(tech_pvt->mutex_audio_cli);
|
||||
if (no_space) {
|
||||
switch_sleep(MS_SKYPOPEN * 1000);
|
||||
} else {
|
||||
tech_pvt->begin_to_write = 1;
|
||||
//switch_sleep(MS_SKYPOPEN * 1000);
|
||||
DEBUGA_SKYPE("NO SPACE in WRITE BUFFER: there was no space for %d\n", SKYPOPEN_P_LOG, frame->datalen);
|
||||
}
|
||||
tech_pvt->begin_to_write = 1;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1859,17 +1858,35 @@ static switch_status_t load_config(int reload_type)
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
static switch_status_t chat_send(const char *proto, const char *from, const char *to, const char *subject, const char *body, const char *type,
|
||||
const char *hint)
|
||||
static switch_status_t chat_send(switch_event_t *message_event)
|
||||
|
||||
{
|
||||
char *user = NULL, *host, *f_user = NULL, *f_host = NULL, *f_resource = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
int i = 0, found = 0, tried = 0;
|
||||
char skype_msg[1024];
|
||||
|
||||
const char *proto;
|
||||
const char *from;
|
||||
const char *to;
|
||||
const char *subject;
|
||||
const char *body;
|
||||
//const char *type;
|
||||
const char *hint;
|
||||
|
||||
proto = switch_event_get_header(message_event, "proto");
|
||||
from = switch_event_get_header(message_event, "from");
|
||||
to = switch_event_get_header(message_event, "to");
|
||||
subject = switch_event_get_header(message_event, "subject");
|
||||
body = switch_event_get_body(message_event);
|
||||
//type = switch_event_get_header(message_event, "type");
|
||||
hint = switch_event_get_header(message_event, "hint");
|
||||
|
||||
switch_assert(proto != NULL);
|
||||
|
||||
DEBUGA_SKYPE("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=%s, hint=%s)\n", SKYPOPEN_P_LOG, proto, from, to, subject, body, type,
|
||||
//DEBUGA_SKYPE("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=%s, hint=%s)\n", SKYPOPEN_P_LOG, proto, from, to, subject, body, type,
|
||||
// hint ? hint : "NULL");
|
||||
DEBUGA_SKYPE("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, hint=%s)\n", SKYPOPEN_P_LOG, proto, from, to, subject, body,
|
||||
hint ? hint : "NULL");
|
||||
|
||||
if (!to || !strlen(to)) {
|
||||
@@ -1896,7 +1913,9 @@ static switch_status_t chat_send(const char *proto, const char *from, const char
|
||||
*host++ = '\0';
|
||||
}
|
||||
|
||||
DEBUGA_SKYPE("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=%s, hint=%s)\n", SKYPOPEN_P_LOG, proto, from, to, subject, body, type,
|
||||
//DEBUGA_SKYPE("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=%s, hint=%s)\n", SKYPOPEN_P_LOG, proto, from, to, subject, body, type,
|
||||
// hint ? hint : "NULL");
|
||||
DEBUGA_SKYPE("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, hint=%s)\n", SKYPOPEN_P_LOG, proto, from, to, subject, body,
|
||||
hint ? hint : "NULL");
|
||||
if (hint && strlen(hint)) {
|
||||
//in hint we receive the interface name to use
|
||||
@@ -1999,7 +2018,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skypopen_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "skypopen", "Skypopen interface commands", skypopen_function, SKYPOPEN_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "skypopen_chat", "Skypopen_chat interface remote_skypename TEXT", skypopen_chat_function,
|
||||
SKYPOPEN_CHAT_SYNTAX);
|
||||
SWITCH_ADD_CHAT(chat_interface, MDL_CHAT_PROTO, chat_send);
|
||||
SWITCH_ADD_CHAT(chat_interface, SKYPE_CHAT_PROTO, chat_send);
|
||||
|
||||
if (switch_event_reserve_subclass(MY_EVENT_INCOMING_CHATMESSAGE) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass!\n");
|
||||
@@ -2945,7 +2964,7 @@ int incoming_chatmessage(private_t *tech_pvt, int which)
|
||||
session = switch_core_session_locate(tech_pvt->session_uuid_str);
|
||||
}
|
||||
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SKYPE_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", tech_pvt->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hint", tech_pvt->chatmessages[which].from_dispname);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", tech_pvt->chatmessages[which].from_handle);
|
||||
@@ -2972,7 +2991,7 @@ int incoming_chatmessage(private_t *tech_pvt, int which)
|
||||
if (!event_sent_to_esl) {
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SKYPE_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", tech_pvt->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hint", tech_pvt->chatmessages[which].from_dispname);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", tech_pvt->chatmessages[which].from_handle);
|
||||
@@ -2998,6 +3017,33 @@ int incoming_chatmessage(private_t *tech_pvt, int which)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static switch_status_t compat_chat_send(const char *proto, const char *from, const char *to,
|
||||
const char *subject, const char *body, const char *type, const char *hint)
|
||||
{
|
||||
switch_event_t *message_event;
|
||||
switch_status_t status;
|
||||
|
||||
if (switch_event_create(&message_event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(message_event, SWITCH_STACK_BOTTOM, "proto", proto);
|
||||
switch_event_add_header_string(message_event, SWITCH_STACK_BOTTOM, "from", from);
|
||||
switch_event_add_header_string(message_event, SWITCH_STACK_BOTTOM, "to", to);
|
||||
switch_event_add_header_string(message_event, SWITCH_STACK_BOTTOM, "subject", subject);
|
||||
switch_event_add_header_string(message_event, SWITCH_STACK_BOTTOM, "type", type);
|
||||
switch_event_add_header_string(message_event, SWITCH_STACK_BOTTOM, "hint", hint);
|
||||
|
||||
if (body) {
|
||||
switch_event_add_body(message_event, "%s", body);
|
||||
}
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
status = chat_send(message_event);
|
||||
switch_event_destroy(&message_event);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(skypopen_chat_function)
|
||||
{
|
||||
@@ -3038,11 +3084,11 @@ SWITCH_STANDARD_API(skypopen_chat_function)
|
||||
goto end;
|
||||
} else {
|
||||
|
||||
NOTICA("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=NULL, hint=%s)\n", SKYPOPEN_P_LOG, MDL_CHAT_PROTO, tech_pvt->skype_user,
|
||||
NOTICA("chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=NULL, hint=%s)\n", SKYPOPEN_P_LOG, SKYPE_CHAT_PROTO, tech_pvt->skype_user,
|
||||
argv[1], "SIMPLE MESSAGE", switch_str_nil((char *) &cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]), tech_pvt->name);
|
||||
|
||||
chat_send(MDL_CHAT_PROTO, tech_pvt->skype_user, argv[1], "SIMPLE MESSAGE",
|
||||
switch_str_nil((char *) &cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]), NULL, tech_pvt->name);
|
||||
compat_chat_send(SKYPE_CHAT_PROTO, tech_pvt->skype_user, argv[1], "SIMPLE MESSAGE",
|
||||
switch_str_nil((char *) &cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]), NULL, tech_pvt->name);
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -146,7 +146,11 @@ struct skypopen_listitem {
|
||||
|
||||
/* The list of devices, and a lock to protect it */
|
||||
static LIST_HEAD(skypopen_c_list);
|
||||
#ifdef WANT_DEFINE_SPINLOCK
|
||||
static DEFINE_SPINLOCK(skypopen_c_lock);
|
||||
#else // WANT_DEFINE_SPINLOCK
|
||||
static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED;
|
||||
#endif // WANT_DEFINE_SPINLOCK
|
||||
|
||||
/* Look for a device or create one if missing */
|
||||
static struct skypopen_dev *skypopen_c_lookfor_device(dev_t key)
|
||||
@@ -283,6 +287,7 @@ static ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t
|
||||
* The ioctl() implementation
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UNLOCKED_IOCTL
|
||||
static int skypopen_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -302,13 +307,38 @@ static int skypopen_ioctl(struct inode *inode, struct file *filp,
|
||||
}
|
||||
|
||||
}
|
||||
#else// HAVE_UNLOCKED_IOCTL
|
||||
static long skypopen_unlocked_ioctl(struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
int __user *p = argp;
|
||||
|
||||
switch (cmd) {
|
||||
case OSS_GETVERSION:
|
||||
return put_user(SOUND_VERSION, p);
|
||||
case SNDCTL_DSP_GETBLKSIZE:
|
||||
return put_user(SKYPOPEN_BLK, p);
|
||||
case SNDCTL_DSP_GETFMTS:
|
||||
return put_user(28731, p);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif// HAVE_UNLOCKED_IOCTL
|
||||
|
||||
struct file_operations skypopen_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = skypopen_read,
|
||||
.write = skypopen_write,
|
||||
#ifndef HAVE_UNLOCKED_IOCTL
|
||||
.ioctl = skypopen_ioctl,
|
||||
#else// HAVE_UNLOCKED_IOCTL
|
||||
.unlocked_ioctl = skypopen_unlocked_ioctl,
|
||||
#endif// HAVE_UNLOCKED_IOCTL
|
||||
.open = skypopen_c_open,
|
||||
.release = skypopen_c_release,
|
||||
};
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#define WANT_HRTIMER
|
||||
#endif /* HRTIMER */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
|
||||
#define WANT_DEFINE_SPINLOCK
|
||||
#endif /* DEFINE_SPINLOCK */
|
||||
|
||||
#define SKYPOPEN_BLK 1920
|
||||
#define SKYPOPEN_SLEEP 20
|
||||
|
||||
|
||||
@@ -540,6 +540,7 @@ int skypopen_signaling_read(private_t *tech_pvt)
|
||||
DEBUGA_SKYPE("Skype FAILED on skype_call %s. Let's wait for the FAILED message.\n", SKYPOPEN_P_LOG, id);
|
||||
}
|
||||
#if 0
|
||||
#ifndef WIN32
|
||||
if (!strcasecmp(prop, "DURATION")) { /* each 20 seconds, we zero the buffers and sync the timers */
|
||||
if (!((atoi(value) % 20))) {
|
||||
if (tech_pvt->read_buffer) {
|
||||
@@ -565,6 +566,7 @@ int skypopen_signaling_read(private_t *tech_pvt)
|
||||
DEBUGA_SKYPE("Synching audio on skype_call: %s.\n", SKYPOPEN_P_LOG, id);
|
||||
}
|
||||
}
|
||||
#endif //WIN32
|
||||
#endif //0
|
||||
if (!strcasecmp(prop, "DURATION") && (!strcasecmp(value, "1"))) {
|
||||
if (strcasecmp(id, tech_pvt->skype_call_id)) {
|
||||
@@ -882,19 +884,21 @@ void *skypopen_do_tcp_srv_thread_func(void *obj)
|
||||
|| tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
|
||||
|| tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPOPEN_STATE_UP)) {
|
||||
|
||||
unsigned int fdselect;
|
||||
//unsigned int fdselect;
|
||||
int rt=1;
|
||||
fd_set fs;
|
||||
//fd_set fs;
|
||||
//struct timeval to;
|
||||
int nospace;
|
||||
|
||||
if (!(running && tech_pvt->running))
|
||||
break;
|
||||
#if 0
|
||||
fdselect = fd;
|
||||
FD_ZERO(&fs);
|
||||
FD_SET(fdselect, &fs);
|
||||
//to.tv_usec = MS_SKYPOPEN * 1000 * 3;
|
||||
//to.tv_sec = 0;
|
||||
to.tv_usec = MS_SKYPOPEN * 1000 * 3;
|
||||
to.tv_sec = 0;
|
||||
#endif //0
|
||||
|
||||
if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) {
|
||||
switch_core_timer_next(&tech_pvt->timer_read_srv);
|
||||
@@ -935,7 +939,7 @@ void *skypopen_do_tcp_srv_thread_func(void *obj)
|
||||
}
|
||||
switch_mutex_unlock(tech_pvt->mutex_audio_srv);
|
||||
if (nospace) {
|
||||
DEBUGA_SKYPE("NO SPACE READ: there was no space for: %d\n", SKYPOPEN_P_LOG, len);
|
||||
DEBUGA_SKYPE("NO SPACE in READ BUFFER: there was no space for: %d\n", SKYPOPEN_P_LOG, len);
|
||||
}
|
||||
} else if (len == 0) {
|
||||
DEBUGA_SKYPE("CLOSED\n", SKYPOPEN_P_LOG);
|
||||
@@ -1080,7 +1084,7 @@ void *skypopen_do_tcp_cli_thread_func(void *obj)
|
||||
}
|
||||
switch_mutex_lock(tech_pvt->mutex_audio_cli);
|
||||
if (tech_pvt->write_buffer && switch_buffer_inuse(tech_pvt->write_buffer)) {
|
||||
bytes_to_write = switch_buffer_read(tech_pvt->write_buffer, cli_out, BYTES_PER_FRAME * 2);
|
||||
bytes_to_write = switch_buffer_read(tech_pvt->write_buffer, cli_out, BYTES_PER_FRAME);
|
||||
}
|
||||
switch_mutex_unlock(tech_pvt->mutex_audio_cli);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
|
||||
SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
|
||||
|
||||
mod_LTLIBRARIES = mod_sofia.la
|
||||
mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c sip-dig.c mod_sofia.h
|
||||
mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h
|
||||
mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS)
|
||||
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
|
||||
mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user