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:
Moises Silva
2011-12-17 17:42:34 -05:00
615 changed files with 41286 additions and 47127 deletions
+2 -3
View File
@@ -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;
+1
View File
@@ -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"
+3
View File
@@ -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 */
+10
View File
@@ -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
View File
@@ -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);
+2
View File
@@ -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:
+9 -2
View File
@@ -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
View File
@@ -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
+9 -1
View File
@@ -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,
+26 -2
View File
@@ -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
+37 -14
View File
@@ -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); \
+23 -2
View File
@@ -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 */
+1
View File
@@ -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);\
+17
View File
@@ -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
+3 -10
View File
@@ -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
View File
@@ -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)
+18
View File
@@ -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:
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+148 -27
View File
@@ -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
View File
@@ -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)
+9 -10
View File
@@ -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;
}
+2 -2
View File
@@ -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");
+361 -114
View File
@@ -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(&params);
@@ -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];
}
}
}
+42 -5
View File
@@ -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);
}
}
+1 -1
View File
@@ -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);
+204 -145
View File
@@ -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);
+2 -1
View File
@@ -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:
+57 -3
View File
@@ -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);
@@ -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
+123 -42
View File
@@ -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)
+88 -14
View File
@@ -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;
}
+6 -7
View File
@@ -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
+35 -25
View File
@@ -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
-135
View File
@@ -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;
}
-53
View File
@@ -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_ */
-250
View File
@@ -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
*/
-30
View File
@@ -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);
-743
View File
@@ -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
*/
-32
View File
@@ -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>
-397
View File
@@ -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 -->
-175
View File
@@ -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);
}
-16
View File
@@ -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>
+535
View File
@@ -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 -1
View File
@@ -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;
}
+5 -5
View File
@@ -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>
+299 -11
View File
@@ -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;
}
+67 -1
View File
@@ -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;
}
+297 -151
View File
@@ -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(&params, 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(&params, 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(&params, 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))) {
+5 -5
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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)
+13 -8
View File
@@ -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);
}
+1
View File
@@ -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);
+5
View File
@@ -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)
+31 -11
View File
@@ -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;
}
+1 -1
View File
@@ -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:
+52 -17
View File
@@ -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;
}
+1 -1
View File
@@ -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);
}
}
}
+8 -7
View File
@@ -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];
+1
View File
@@ -520,6 +520,7 @@ struct rtmp_private {
const char *auth;
uint16_t maxlen;
int over_size;
};
struct rtmp_reg;
+50 -5
View File
@@ -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);
+1 -1
View File
@@ -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");
}
+14 -4
View File
@@ -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;
}
+64 -18
View File
@@ -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 {
+30
View File
@@ -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);
+1 -1
View File
@@ -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