mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 12:42:02 +00:00
Merge remote branch 'fsorig/master'
Conflicts: src/mod/applications/mod_commands/mod_commands.c src/mod/endpoints/mod_portaudio/mod_portaudio.c src/mod/endpoints/mod_portaudio/pablio.c
This commit is contained in:
@@ -240,6 +240,7 @@ struct switch_runtime {
|
||||
uint32_t debug_level;
|
||||
uint32_t runlevel;
|
||||
uint32_t tipping_point;
|
||||
uint32_t microseconds_per_tick;
|
||||
int32_t timer_affinity;
|
||||
switch_profile_timer_t *profile_timer;
|
||||
double profile_time;
|
||||
@@ -248,9 +249,12 @@ struct switch_runtime {
|
||||
int max_sql_buffer_len;
|
||||
switch_dbtype_t odbc_dbtype;
|
||||
char hostname[256];
|
||||
char *switchname;
|
||||
int multiple_registrations;
|
||||
uint32_t max_db_handles;
|
||||
uint32_t db_handle_timeout;
|
||||
int curl_count;
|
||||
int ssl_count;
|
||||
};
|
||||
|
||||
extern struct switch_runtime runtime;
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
*
|
||||
* - Linux (x86 & x86_64)
|
||||
* - Windows (MSVC 2008 & VC++ EE 2008)
|
||||
* - Windows (MSVC 2010 & VC++ EE 2010)
|
||||
* - Mac OS X (intel & ppc )
|
||||
* - FreeBSD 6
|
||||
*
|
||||
@@ -176,6 +177,10 @@
|
||||
* mod_pocketsphinx
|
||||
* - PocketSphinx (http://www.speech.cs.cmu.edu/pocketsphinx/)
|
||||
*
|
||||
* mod_unimrcp
|
||||
* - MRCP (http://www.unimrcp.org/)
|
||||
*
|
||||
*
|
||||
* Codecs
|
||||
* mod_speex
|
||||
* - libspeex (http://www.speex.org/)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Eliot Gable <egable@gmail.com>
|
||||
*
|
||||
* switch_apr.h -- APR includes header
|
||||
*
|
||||
@@ -144,6 +145,8 @@ SWITCH_DECLARE(int) switch_snprintf(_Out_z_cap_(len)
|
||||
|
||||
SWITCH_DECLARE(int) switch_vasprintf(_Out_opt_ char **buf, _In_z_ _Printf_format_string_ const char *format, _In_ va_list ap);
|
||||
|
||||
SWITCH_DECLARE(int) switch_vsnprintf(char *buf, switch_size_t len, const char *format, va_list ap);
|
||||
|
||||
SWITCH_DECLARE(char *) switch_copy_string(_Out_z_cap_(dst_size)
|
||||
char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size);
|
||||
|
||||
@@ -410,6 +413,65 @@ SWITCH_DECLARE(switch_status_t) switch_mutex_trylock(switch_mutex_t *lock);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup switch_atomic Multi-Threaded Adtomic Operations Routines
|
||||
* @ingroup switch_apr
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Opaque type used for the atomic operations */
|
||||
#ifdef apr_atomic_t
|
||||
typedef apr_atomic_t switch_atomic_t;
|
||||
#else
|
||||
typedef uint32_t switch_atomic_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Some architectures require atomic operations internal structures to be
|
||||
* initialized before use.
|
||||
* @param pool The memory pool to use when initializing the structures.
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_atomic_init(switch_memory_pool_t *pool);
|
||||
|
||||
/**
|
||||
* Uses an atomic operation to read the uint32 value at the location specified
|
||||
* by mem.
|
||||
* @param mem The location of memory which stores the value to read.
|
||||
*/
|
||||
SWITCH_DECLARE(uint32_t) switch_atomic_read(volatile switch_atomic_t *mem);
|
||||
|
||||
/**
|
||||
* Uses an atomic operation to set a uint32 value at a specified location of
|
||||
* memory.
|
||||
* @param mem The location of memory to set.
|
||||
* @param val The uint32 value to set at the memory location.
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_atomic_set(volatile switch_atomic_t *mem, uint32_t val);
|
||||
|
||||
/**
|
||||
* Uses an atomic operation to add the uint32 value to the value at the
|
||||
* specified location of memory.
|
||||
* @param mem The location of the value to add to.
|
||||
* @param val The uint32 value to add to the value at the memory location.
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_atomic_add(volatile switch_atomic_t *mem, uint32_t val);
|
||||
|
||||
/**
|
||||
* Uses an atomic operation to increment the value at the specified memroy
|
||||
* location.
|
||||
* @param mem The location of the value to increment.
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_atomic_inc(volatile switch_atomic_t *mem);
|
||||
|
||||
/**
|
||||
* Uses an atomic operation to decrement the value at the specified memroy
|
||||
* location.
|
||||
* @param mem The location of the value to decrement.
|
||||
*/
|
||||
SWITCH_DECLARE(int) switch_atomic_dec(volatile switch_atomic_t *mem);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup switch_thread_rwlock Thread Read/Write lock Routines
|
||||
* @ingroup switch_apr
|
||||
|
||||
@@ -56,6 +56,15 @@
|
||||
#include <switch.h>
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
typedef struct profile_node_s {
|
||||
char *var;
|
||||
char *val;
|
||||
struct profile_node_s *next;
|
||||
} profile_node_t;
|
||||
|
||||
|
||||
|
||||
/*! \brief Call Specific Data
|
||||
*/
|
||||
struct switch_caller_profile {
|
||||
@@ -110,6 +119,7 @@ SWITCH_BEGIN_EXTERN_C
|
||||
switch_memory_pool_t *pool;
|
||||
struct switch_caller_profile *next;
|
||||
switch_call_direction_t direction;
|
||||
profile_node_t *soft;
|
||||
};
|
||||
|
||||
/*! \brief An Abstract Representation of a dialplan Application */
|
||||
|
||||
@@ -49,6 +49,7 @@ SWITCH_BEGIN_EXTERN_C struct switch_channel_timetable {
|
||||
switch_time_t hungup;
|
||||
switch_time_t transferred;
|
||||
switch_time_t resurrected;
|
||||
switch_time_t bridged;
|
||||
struct switch_channel_timetable *next;
|
||||
};
|
||||
|
||||
@@ -250,6 +251,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel,
|
||||
const char *varname, const char *value, switch_bool_t var_check);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_add_variable_var_check(switch_channel_t *channel,
|
||||
const char *varname, const char *value, switch_bool_t var_check, switch_stack_t stack);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_printf(switch_channel_t *channel, const char *varname, const char *fmt, ...);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_name_printf(switch_channel_t *channel, const char *val, const char *fmt, ...);
|
||||
|
||||
@@ -283,8 +286,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_printf(switch_cha
|
||||
\param varname the name of the variable
|
||||
\return the value of the requested variable
|
||||
*/
|
||||
SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup);
|
||||
#define switch_channel_get_variable(_c, _v) switch_channel_get_variable_dup(_c, _v, SWITCH_TRUE)
|
||||
SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup, int idx);
|
||||
#define switch_channel_get_variable(_c, _v) switch_channel_get_variable_dup(_c, _v, SWITCH_TRUE, -1)
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_get_variables(switch_channel_t *channel, switch_event_t **event);
|
||||
|
||||
@@ -315,6 +318,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension);
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_flip_cid(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in);
|
||||
|
||||
/*!
|
||||
@@ -596,7 +600,7 @@ SWITCH_DECLARE(int) switch_channel_test_app_flag_key(const char *app, switch_cha
|
||||
#define switch_channel_clear_app_flag(_c, _f) switch_channel_clear_app_flag_key(__FILE__, _c, _f)
|
||||
#define switch_channel_test_app_flag(_c, _f) switch_channel_test_app_flag_key(__FILE__, _c, _f)
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_set_bridge_time(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(switch_core_session_t *) switch_channel_get_session(switch_channel_t *channel);
|
||||
@@ -614,6 +618,9 @@ 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_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
||||
@@ -57,6 +57,7 @@ SWITCH_BEGIN_EXTERN_C
|
||||
struct switch_app_log {
|
||||
char *app;
|
||||
char *arg;
|
||||
switch_time_t stamp;
|
||||
struct switch_app_log *next;
|
||||
};
|
||||
|
||||
@@ -434,6 +435,9 @@ 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
|
||||
@@ -762,6 +766,7 @@ SWITCH_DECLARE(char *) switch_core_get_variable(_In_z_ const char *varname);
|
||||
SWITCH_DECLARE(char *) switch_core_get_variable_dup(_In_z_ const char *varname);
|
||||
SWITCH_DECLARE(char *) switch_core_get_variable_pdup(_In_z_ const char *varname, switch_memory_pool_t *pool);
|
||||
SWITCH_DECLARE(const char *) switch_core_get_hostname(void);
|
||||
SWITCH_DECLARE(const char *) switch_core_get_switchname(void);
|
||||
|
||||
/*!
|
||||
\brief Add a global variable to the core
|
||||
@@ -1183,7 +1188,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(_In_ switch_core_s
|
||||
///\ingroup core1
|
||||
///\{
|
||||
/*!
|
||||
\brief Initilize a hash table
|
||||
\brief Initialize a hash table
|
||||
\param hash a NULL pointer to a hash table to aim at the new hash
|
||||
\param pool the pool to use for the new hash
|
||||
\return SWITCH_STATUS_SUCCESS if the hash is created
|
||||
@@ -1940,6 +1945,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
|
||||
\return 0 on success
|
||||
*/
|
||||
SWITCH_DECLARE(int32_t) set_high_priority(void);
|
||||
SWITCH_DECLARE(int32_t) set_normal_priority(void);
|
||||
|
||||
/*!
|
||||
\brief Change user and/or group of the running process
|
||||
@@ -2050,6 +2056,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token);
|
||||
#define switch_check_network_list_ip(_ip_str, _list_name) switch_check_network_list_ip_token(_ip_str, _list_name, NULL)
|
||||
SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable);
|
||||
SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable);
|
||||
SWITCH_DECLARE(void) switch_time_set_nanosleep(switch_bool_t enable);
|
||||
SWITCH_DECLARE(void) switch_time_set_matrix(switch_bool_t enable);
|
||||
SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable);
|
||||
@@ -2203,6 +2210,7 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand
|
||||
SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute(switch_cache_db_handle_t *dbh, const char *sql, uint32_t retries);
|
||||
SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans(switch_cache_db_handle_t *dbh, char *sql, uint32_t retries);
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_set_signal_handlers(void);
|
||||
SWITCH_DECLARE(uint32_t) switch_core_debug_level(void);
|
||||
SWITCH_DECLARE(void) switch_cache_db_flush_handles(void);
|
||||
SWITCH_DECLARE(const char *) switch_core_banner(void);
|
||||
@@ -2238,6 +2246,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_del_registration(const char *user, c
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force);
|
||||
|
||||
|
||||
SWITCH_DECLARE(char *) switch_say_file_handle_get_variable(switch_say_file_handle_t *sh, const char *var);
|
||||
SWITCH_DECLARE(char *) switch_say_file_handle_get_path(switch_say_file_handle_t *sh);
|
||||
SWITCH_DECLARE(char *) switch_say_file_handle_detach_path(switch_say_file_handle_t *sh);
|
||||
SWITCH_DECLARE(void) switch_say_file_handle_destroy(switch_say_file_handle_t **sh);
|
||||
SWITCH_DECLARE(switch_status_t) switch_say_file_handle_create(switch_say_file_handle_t **sh, const char *ext, switch_event_t **var_event);
|
||||
SWITCH_DECLARE(void) switch_say_file(switch_say_file_handle_t *sh, const char *fmt, ...);
|
||||
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2010, 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):
|
||||
*
|
||||
*
|
||||
* switch_curl.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SWITCH_CURL_H
|
||||
#define __SWITCH_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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* 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:
|
||||
*/
|
||||
|
||||
@@ -67,6 +67,10 @@ SWITCH_BEGIN_EXTERN_C
|
||||
char *name;
|
||||
/*! the header value */
|
||||
char *value;
|
||||
/*! array space */
|
||||
char **array;
|
||||
/*! array index */
|
||||
int idx;
|
||||
/*! hash of the header name */
|
||||
unsigned long hash;
|
||||
struct switch_event_header *next;
|
||||
@@ -99,7 +103,8 @@ struct switch_event {
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
EF_UNIQ_HEADERS = (1 << 0)
|
||||
EF_UNIQ_HEADERS = (1 << 0),
|
||||
EF_CONTAINS_ARRAYS = (1 << 1),
|
||||
} switch_event_flag_t;
|
||||
|
||||
|
||||
@@ -146,7 +151,10 @@ SWITCH_DECLARE(switch_status_t) switch_event_set_priority(switch_event_t *event,
|
||||
\param header_name the name of the header to read
|
||||
\return the value of the requested header
|
||||
*/
|
||||
_Ret_opt_z_ SWITCH_DECLARE(char *) switch_event_get_header(switch_event_t *event, const char *header_name);
|
||||
|
||||
_Ret_opt_z_ SWITCH_DECLARE(switch_event_header_t *) switch_event_get_header_ptr(switch_event_t *event, const char *header_name);
|
||||
_Ret_opt_z_ SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t *event, const char *header_name, int idx);
|
||||
#define switch_event_get_header(_e, _h) switch_event_get_header_idx(_e, _h, -1)
|
||||
|
||||
#define switch_event_get_header_nil(e, h) switch_str_nil(switch_event_get_header(e,h))
|
||||
|
||||
@@ -285,7 +293,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_free_subclass_detailed(const char *
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, char **str, switch_bool_t encode);
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *event, char **str);
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_create_json(switch_event_t **event, const char *json);
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a, char b, char c, switch_event_t **event, char **new_data);
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a, char b, char c, switch_event_t **event, char **new_data, switch_bool_t dup);
|
||||
|
||||
#ifndef SWIG
|
||||
/*!
|
||||
|
||||
@@ -865,6 +865,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_say(switch_core_session_t *session,
|
||||
const char *say_gender,
|
||||
switch_input_args_t *args);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_say_string(switch_core_session_t *session,
|
||||
const char *lang,
|
||||
const char *ext,
|
||||
const char *tosay,
|
||||
const char *module_name,
|
||||
const char *say_type,
|
||||
const char *say_method,
|
||||
const char *say_gender,
|
||||
char **rstr);
|
||||
|
||||
SWITCH_DECLARE(switch_say_method_t) switch_ivr_get_say_method_by_name(const char *name);
|
||||
SWITCH_DECLARE(switch_say_gender_t) switch_ivr_get_say_gender_by_name(const char *name);
|
||||
SWITCH_DECLARE(switch_say_type_t) switch_ivr_get_say_type_by_name(const char *name);
|
||||
|
||||
@@ -103,29 +103,9 @@ struct switch_stream_handle {
|
||||
};
|
||||
|
||||
struct switch_io_event_hooks;
|
||||
struct switch_say_file_handle;
|
||||
|
||||
|
||||
|
||||
typedef switch_call_cause_t (*switch_io_outgoing_channel_t)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef switch_call_cause_t (*switch_io_outgoing_channel_t)
|
||||
(switch_core_session_t *, switch_event_t *, switch_caller_profile_t *, switch_core_session_t **, switch_memory_pool_t **, switch_originate_flag_t,
|
||||
switch_call_cause_t *);
|
||||
typedef switch_status_t (*switch_io_read_frame_t) (switch_core_session_t *, switch_frame_t **, switch_io_flag_t, int);
|
||||
@@ -490,6 +470,7 @@ struct switch_say_interface {
|
||||
const char *interface_name;
|
||||
/*! function to pass down to the module */
|
||||
switch_say_callback_t say_function;
|
||||
switch_say_string_callback_t say_string_function;
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
int refs;
|
||||
switch_mutex_t *reflock;
|
||||
|
||||
@@ -56,7 +56,7 @@ SWITCH_DECLARE(const char *) switch_nat_get_type(void);
|
||||
\param pool the memory pool to use for long term allocations
|
||||
\note Generally called by the core_init
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_nat_init(switch_memory_pool_t *pool);
|
||||
SWITCH_DECLARE(void) switch_nat_init(switch_memory_pool_t *pool, switch_bool_t mapping);
|
||||
|
||||
/*!
|
||||
\brief Initilize the rest of the NAT Traversal System
|
||||
@@ -86,6 +86,11 @@ SWITCH_DECLARE(void) switch_nat_republish(void);
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_nat_reinit(void);
|
||||
|
||||
/*!
|
||||
\brief Update the setting if port mapping will be created
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_nat_set_mapping(switch_bool_t mapping);
|
||||
|
||||
/*!
|
||||
\brief Maps a port through the NAT Traversal System
|
||||
\param port Internal port to map
|
||||
|
||||
@@ -223,15 +223,15 @@ typedef intptr_t switch_ssize_t;
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef WIN64
|
||||
#define SWITCH_SSIZE_T_FMT "I64d"
|
||||
#define SWITCH_SIZE_T_FMT "I64d"
|
||||
#define SWITCH_SSIZE_T_FMT "lld"
|
||||
#define SWITCH_SIZE_T_FMT "lld"
|
||||
#else
|
||||
#define SWITCH_SSIZE_T_FMT "d"
|
||||
#define SWITCH_SIZE_T_FMT "d"
|
||||
#endif
|
||||
|
||||
#define SWITCH_INT64_T_FMT "I64d"
|
||||
#define SWITCH_UINT64_T_FMT "I64u"
|
||||
#define SWITCH_INT64_T_FMT "lld"
|
||||
#define SWITCH_UINT64_T_FMT "llu"
|
||||
|
||||
#ifndef TIME_T_FMT
|
||||
#define TIME_T_FMT SWITCH_INT64_T_FMT
|
||||
|
||||
@@ -70,6 +70,10 @@ SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const cha
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_regex_match_partial(const char *target, const char *expression, int *partial_match);
|
||||
|
||||
SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data,
|
||||
int *ovector, const char *var, switch_cap_callback_t callback, void *user_data);
|
||||
|
||||
SWITCH_DECLARE(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data);
|
||||
|
||||
#define switch_regex_safe_free(re) if (re) {\
|
||||
switch_regex_free(re);\
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2010, 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):
|
||||
*
|
||||
*
|
||||
* switch_ssl.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SWITCH_SSL_H
|
||||
#define __SWITCH_SSL_H
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
static switch_mutex_t **ssl_mutexes;
|
||||
static switch_memory_pool_t *ssl_pool = NULL;
|
||||
|
||||
|
||||
static inline void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
switch_mutex_lock(ssl_mutexes[type]);
|
||||
}
|
||||
else {
|
||||
switch_mutex_unlock(ssl_mutexes[type]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long switch_ssl_ssl_thread_id(void)
|
||||
{
|
||||
return (unsigned long) switch_thread_self();
|
||||
}
|
||||
|
||||
static inline void switch_ssl_init_ssl_locks(void)
|
||||
{
|
||||
|
||||
int ssl_count = switch_core_ssl_count(NULL);
|
||||
int i, num;
|
||||
|
||||
if (ssl_count == 0) {
|
||||
num = CRYPTO_num_locks();
|
||||
|
||||
ssl_mutexes = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(switch_mutex_t*));
|
||||
switch_assert(ssl_mutexes != NULL);
|
||||
|
||||
switch_core_new_memory_pool(&ssl_pool);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
switch_mutex_init(&(ssl_mutexes[i]), SWITCH_MUTEX_NESTED, ssl_pool);
|
||||
switch_assert(ssl_mutexes[i] != NULL);
|
||||
}
|
||||
|
||||
CRYPTO_set_id_callback(switch_ssl_ssl_thread_id);
|
||||
CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))switch_ssl_ssl_lock_callback);
|
||||
}
|
||||
|
||||
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) {
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
if (ssl_mutexes[i]) {
|
||||
switch_mutex_destroy(ssl_mutexes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
OPENSSL_free(ssl_mutexes);
|
||||
}
|
||||
|
||||
switch_core_ssl_count(&ssl_count);
|
||||
|
||||
}
|
||||
#else
|
||||
static inline void switch_ssl_init_ssl_locks(void) { return; }
|
||||
static inline void switch_ssl_destroy_ssl_locks(void) { return; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -36,6 +36,7 @@
|
||||
#define SWITCH_TYPES_H
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_ENT_ORIGINATE_DELIM ":_:"
|
||||
#define SWITCH_BLANK_STRING ""
|
||||
@@ -135,6 +136,7 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#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_CALL_TIMEOUT_VARIABLE "call_timeout"
|
||||
#define SWITCH_HOLDING_UUID_VARIABLE "holding_uuid"
|
||||
#define SWITCH_SOFT_HOLDING_UUID_VARIABLE "soft_holding_uuid"
|
||||
@@ -264,7 +266,8 @@ typedef enum {
|
||||
SCF_VERBOSE_EVENTS = (1 << 11),
|
||||
SCF_USE_WIN32_MONOTONIC = (1 << 12),
|
||||
SCF_AUTO_SCHEMAS = (1 << 13),
|
||||
SCF_MINIMAL = (1 << 14)
|
||||
SCF_MINIMAL = (1 << 14),
|
||||
SCF_USE_NAT_MAPPING = (1 << 15)
|
||||
} switch_core_flag_enum_t;
|
||||
typedef uint32_t switch_core_flag_t;
|
||||
|
||||
@@ -486,6 +489,7 @@ typedef struct {
|
||||
switch_size_t dtmf_packet_count;
|
||||
switch_size_t cng_packet_count;
|
||||
switch_size_t flush_packet_count;
|
||||
switch_size_t largest_jb_size;
|
||||
} switch_rtp_numbers_t;
|
||||
|
||||
|
||||
@@ -515,7 +519,6 @@ typedef enum {
|
||||
SWITCH_RTP_FLAG_NOBLOCK - Do not block
|
||||
SWITCH_RTP_FLAG_IO - IO is ready
|
||||
SWITCH_RTP_FLAG_USE_TIMER - Timeout Reads and replace with a CNG Frame
|
||||
SWITCH_RTP_FLAG_TIMER_RECLOCK - Resync the timer to the current clock on slips
|
||||
SWITCH_RTP_FLAG_SECURE - Secure RTP
|
||||
SWITCH_RTP_FLAG_AUTOADJ - Auto-Adjust the dest based on the source
|
||||
SWITCH_RTP_FLAG_RAW_WRITE - Try to forward packets unscathed
|
||||
@@ -532,7 +535,7 @@ typedef enum {
|
||||
SWITCH_RTP_FLAG_NOBLOCK = (1 << 0),
|
||||
SWITCH_RTP_FLAG_IO = (1 << 1),
|
||||
SWITCH_RTP_FLAG_USE_TIMER = (1 << 2),
|
||||
SWITCH_RTP_FLAG_TIMER_RECLOCK = (1 << 3),
|
||||
SWITCH_RTP_FLAG_RTCP_PASSTHRU = (1 << 3),
|
||||
SWITCH_RTP_FLAG_SECURE_SEND = (1 << 4),
|
||||
SWITCH_RTP_FLAG_SECURE_RECV = (1 << 5),
|
||||
SWITCH_RTP_FLAG_AUTOADJ = (1 << 6),
|
||||
@@ -542,7 +545,7 @@ typedef enum {
|
||||
SWITCH_RTP_FLAG_BREAK = (1 << 10),
|
||||
SWITCH_RTP_FLAG_UDPTL = (1 << 11),
|
||||
SWITCH_RTP_FLAG_DATAWAIT = (1 << 12),
|
||||
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13),
|
||||
SWITCH_RTP_FLAG_BYTESWAP = (1 << 13),
|
||||
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14),
|
||||
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15),
|
||||
SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16),
|
||||
@@ -559,8 +562,7 @@ typedef enum {
|
||||
SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27),
|
||||
SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28),
|
||||
SWITCH_RTP_FLAG_VIDEO = (1 << 29),
|
||||
SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30),
|
||||
SWITCH_RTP_FLAG_RTCP_PASSTHRU = (1 << 31)
|
||||
SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30)
|
||||
/* don't add any more 31 is the limit! gotta chnge to an array to add more */
|
||||
} switch_rtp_flag_enum_t;
|
||||
typedef uint32_t switch_rtp_flag_t;
|
||||
@@ -828,7 +830,9 @@ SWITCH_STACK_TOP - Stack on the top
|
||||
typedef enum {
|
||||
SWITCH_STACK_BOTTOM = (1 << 0),
|
||||
SWITCH_STACK_TOP = (1 << 1),
|
||||
SWITCH_STACK_NODUP = (1 << 2)
|
||||
SWITCH_STACK_NODUP = (1 << 2),
|
||||
SWITCH_STACK_UNSHIFT = (1 << 3),
|
||||
SWITCH_STACK_PUSH = (1 << 4),
|
||||
} switch_stack_t;
|
||||
|
||||
/*!
|
||||
@@ -1107,6 +1111,8 @@ typedef enum {
|
||||
CF_DIALPLAN,
|
||||
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
|
||||
CF_CNG_PLC,
|
||||
CF_ATTENDED_TRANSFER,
|
||||
CF_LAZY_ATTENDED_TRANSFER,
|
||||
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
|
||||
CF_FLAG_MAX
|
||||
} switch_channel_flag_t;
|
||||
@@ -1684,6 +1690,7 @@ struct switch_console_callback_match {
|
||||
};
|
||||
typedef struct switch_console_callback_match switch_console_callback_match_t;
|
||||
|
||||
typedef void (*switch_cap_callback_t) (const char *var, const char *val, void *user_data);
|
||||
typedef switch_status_t (*switch_console_complete_callback_t) (const char *, const char *, switch_console_callback_match_t **matches);
|
||||
typedef switch_bool_t (*switch_media_bug_callback_t) (switch_media_bug_t *, void *, switch_abc_type_t);
|
||||
typedef switch_bool_t (*switch_tone_detect_callback_t) (switch_core_session_t *, const char *, const char *);
|
||||
@@ -1735,6 +1742,7 @@ typedef switch_status_t (*switch_stream_handle_raw_write_function_t) (switch_str
|
||||
typedef switch_status_t (*switch_api_function_t) (_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session,
|
||||
_In_ switch_stream_handle_t *stream);
|
||||
|
||||
|
||||
#define SWITCH_STANDARD_API(name) static switch_status_t name (_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream)
|
||||
|
||||
typedef switch_status_t (*switch_input_callback_function_t) (switch_core_session_t *session, void *input,
|
||||
@@ -1772,17 +1780,32 @@ typedef struct {
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
} switch_input_args_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
switch_say_type_t type;
|
||||
switch_say_method_t method;
|
||||
switch_say_gender_t gender;
|
||||
const char *ext;
|
||||
} switch_say_args_t;
|
||||
|
||||
|
||||
typedef switch_status_t (*switch_say_callback_t) (switch_core_session_t *session,
|
||||
char *tosay,
|
||||
switch_say_args_t *say_args,
|
||||
switch_input_args_t *args);
|
||||
|
||||
typedef switch_status_t (*switch_say_string_callback_t) (switch_core_session_t *session,
|
||||
char *tosay,
|
||||
switch_say_args_t *say_args, char **rstr);
|
||||
|
||||
struct switch_say_file_handle;
|
||||
typedef struct switch_say_file_handle switch_say_file_handle_t;
|
||||
|
||||
typedef switch_status_t (*switch_new_say_callback_t) (switch_say_file_handle_t *sh,
|
||||
char *tosay,
|
||||
switch_say_args_t *say_args);
|
||||
|
||||
|
||||
typedef struct switch_xml *switch_xml_t;
|
||||
typedef struct switch_core_time_duration switch_core_time_duration_t;
|
||||
typedef switch_xml_t(*switch_xml_search_function_t) (const char *section,
|
||||
|
||||
+47
-21
@@ -151,7 +151,11 @@ static inline char *switch_strchr_strict(const char *in, char find, const char *
|
||||
#endif
|
||||
static inline int switch_string_has_escaped_data(const char *in)
|
||||
{
|
||||
const char *i = strchr(in, '\\');
|
||||
const char *i;
|
||||
|
||||
switch_assert(in);
|
||||
|
||||
i = strchr(in, '\\');
|
||||
|
||||
while (i && *i == '\\') {
|
||||
i++;
|
||||
@@ -235,20 +239,23 @@ SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size
|
||||
SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switch_size_t size);
|
||||
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);
|
||||
|
||||
/*!
|
||||
\brief Evaluate the truthfullness of a string expression
|
||||
\param expr a string expression
|
||||
\return true or false
|
||||
*/
|
||||
#define switch_true(expr)\
|
||||
((expr && ( !strcasecmp(expr, "yes") ||\
|
||||
!strcasecmp(expr, "on") ||\
|
||||
!strcasecmp(expr, "true") ||\
|
||||
!strcasecmp(expr, "enabled") ||\
|
||||
!strcasecmp(expr, "active") ||\
|
||||
!strcasecmp(expr, "allow") ||\
|
||||
(switch_is_number(expr) && atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE)
|
||||
static inline int switch_true(const char *expr)
|
||||
{
|
||||
return ((expr && ( !strcasecmp(expr, "yes") ||
|
||||
!strcasecmp(expr, "on") ||
|
||||
!strcasecmp(expr, "true") ||
|
||||
!strcasecmp(expr, "enabled") ||
|
||||
!strcasecmp(expr, "active") ||
|
||||
!strcasecmp(expr, "allow") ||
|
||||
(switch_is_number(expr) && atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE);
|
||||
}
|
||||
|
||||
#define switch_true_buf(expr)\
|
||||
((( !strcasecmp(expr, "yes") ||\
|
||||
@@ -264,14 +271,16 @@ SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame);
|
||||
\param expr a string expression
|
||||
\return true or false
|
||||
*/
|
||||
#define switch_false(expr)\
|
||||
((expr && ( !strcasecmp(expr, "no") ||\
|
||||
!strcasecmp(expr, "off") ||\
|
||||
!strcasecmp(expr, "false") ||\
|
||||
!strcasecmp(expr, "disabled") ||\
|
||||
!strcasecmp(expr, "inactive") ||\
|
||||
!strcasecmp(expr, "disallow") ||\
|
||||
(switch_is_number(expr) && !atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE)
|
||||
static inline int switch_false(const char *expr)
|
||||
{
|
||||
return ((expr && ( !strcasecmp(expr, "no") ||
|
||||
!strcasecmp(expr, "off") ||
|
||||
!strcasecmp(expr, "false") ||
|
||||
!strcasecmp(expr, "disabled") ||
|
||||
!strcasecmp(expr, "inactive") ||
|
||||
!strcasecmp(expr, "disallow") ||
|
||||
(switch_is_number(expr) && !atoi(expr)))) ? SWITCH_TRUE : SWITCH_FALSE);
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_resolve_host(const char *host, char *buf, size_t buflen);
|
||||
@@ -496,6 +505,23 @@ static inline char *switch_clean_string(char *s)
|
||||
}
|
||||
|
||||
|
||||
static inline char *switch_clean_name_string(char *s)
|
||||
{
|
||||
char *p;
|
||||
for (p = s; p && *p; p++) {
|
||||
uint8_t x = (uint8_t) * p;
|
||||
if ((x < 32) || x == '\'' || x == '"' || x == '<' || x == '>' || x == '\\' || x == ':' || x == '@' || x == '/') {
|
||||
*p = ' ';
|
||||
}
|
||||
if ( (p == s) && (*p == ' ') ) {
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief Free a pointer and set it to NULL unless it already is NULL
|
||||
@@ -631,7 +657,7 @@ SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in);
|
||||
#define switch_time_from_sec(sec) ((switch_time_t)(sec) * 1000000)
|
||||
|
||||
/*!
|
||||
\brief Declares a function designed to set a dymaic global string
|
||||
\brief Declares a function designed to set a dynamic global string
|
||||
\param fname the function name to declare
|
||||
\param vname the name of the global pointer to modify with the new function
|
||||
*/
|
||||
@@ -639,9 +665,9 @@ SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in);
|
||||
if (vname) {free(vname); vname = NULL;}vname = strdup(string);} static void fname(const char *string)
|
||||
|
||||
/*!
|
||||
\brief Separate a string into an array based on a character delimeter
|
||||
\brief Separate a string into an array based on a character delimiter
|
||||
\param buf the string to parse
|
||||
\param delim the character delimeter
|
||||
\param delim the character delimiter
|
||||
\param array the array to split the values into
|
||||
\param arraylen the max number of elements in the array
|
||||
\return the number of elements added to the array
|
||||
@@ -649,7 +675,7 @@ SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in);
|
||||
SWITCH_DECLARE(unsigned int) switch_separate_string(_In_ char *buf, char delim, _Post_count_(return) char **array, unsigned int arraylen);
|
||||
SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf, char *delim, _Post_count_(return) char **array, unsigned int arraylen);
|
||||
|
||||
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
|
||||
|
||||
SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup);
|
||||
SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str);
|
||||
SWITCH_DECLARE(char *) switch_strip_commas(char *in, char *out, switch_size_t len);
|
||||
|
||||
@@ -98,6 +98,7 @@ struct switch_xml {
|
||||
uint32_t flags;
|
||||
/*! is_switch_xml_root bool */
|
||||
switch_bool_t is_switch_xml_root_t;
|
||||
uint32_t refs;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -377,7 +378,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_locate_user_in_domain(_In_z_ const ch
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_xml_locate_user_merged(const char *key, const char *user_name, const char *domain_name,
|
||||
const char *ip, switch_xml_t *user, switch_event_t *params);
|
||||
|
||||
SWITCH_DECLARE(uint32_t) switch_xml_clear_user_cache(const char *key, const char *user_name, const char *domain_name);
|
||||
SWITCH_DECLARE(void) switch_xml_merge_user(switch_xml_t user, switch_xml_t domain, switch_xml_t group);
|
||||
|
||||
SWITCH_DECLARE(switch_xml_t) switch_xml_dup(switch_xml_t xml);
|
||||
@@ -416,6 +417,8 @@ SWITCH_DECLARE(switch_xml_section_t) switch_xml_parse_section_string(_In_opt_z_
|
||||
|
||||
SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond);
|
||||
|
||||
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);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
///\}
|
||||
#endif // _SWITCH_XML_H
|
||||
|
||||
+1
-2
@@ -9,8 +9,6 @@
|
||||
/applications/mod_conference/Makefile
|
||||
/applications/mod_db/Makefile
|
||||
/applications/mod_dptools/Makefile
|
||||
/applications/mod_enum/Makefile
|
||||
/applications/mod_enum/Makefile.in
|
||||
/applications/mod_enum/mod_enum.log
|
||||
/applications/mod_expr/Makefile
|
||||
/applications/mod_expr/Makefile.in
|
||||
@@ -31,6 +29,7 @@
|
||||
/endpoints/mod_portaudio/Makefile.in
|
||||
/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_sofia/Makefile
|
||||
|
||||
@@ -479,7 +479,7 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame)
|
||||
double success = 0.0;
|
||||
double amp = 0.0;
|
||||
double s_rate;
|
||||
double e_rate;
|
||||
// double e_rate;
|
||||
double avg_a;
|
||||
double sine_len;
|
||||
uint32_t sine_len_i;
|
||||
@@ -523,7 +523,7 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame)
|
||||
/*! Every once in a while we evaluate the desa2 and amplitude results */
|
||||
if(((pos + 1) % sine_len_i) == 0){
|
||||
s_rate = success / (error + success);
|
||||
e_rate = error / (error + success);
|
||||
// e_rate = error / (error + success);
|
||||
avg_a = amp / sine_len;
|
||||
|
||||
/*! Results out of these ranges are considered invalid */
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mod_callcenter"
|
||||
ProjectGUID="{47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}"
|
||||
RootNamespace="mod_callcenter"
|
||||
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_callcenter.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
+5
-5
@@ -19,9 +19,9 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_file_string</ProjectName>
|
||||
<ProjectGuid>{70564D74-199A-4452-9C60-19ED5F242F0D}</ProjectGuid>
|
||||
<RootNamespace>mod_file_string</RootNamespace>
|
||||
<ProjectName>mod_callcenter</ProjectName>
|
||||
<ProjectGuid>{47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}</ProjectGuid>
|
||||
<RootNamespace>mod_callcenter</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
@@ -117,7 +117,7 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_file_string.c" />
|
||||
<ClCompile Include="mod_callcenter.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
@@ -128,4 +128,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -366,7 +366,6 @@ static long do_lookup_url(switch_memory_pool_t *pool, switch_event_t *event, cha
|
||||
switch_time_t time_diff = 0;
|
||||
CURL *curl_handle = NULL;
|
||||
long httpRes = 0;
|
||||
char hostname[256] = "";
|
||||
|
||||
struct http_data http_data;
|
||||
|
||||
@@ -375,8 +374,6 @@ static long do_lookup_url(switch_memory_pool_t *pool, switch_event_t *event, cha
|
||||
http_data.max_bytes = 10240;
|
||||
SWITCH_STANDARD_STREAM(http_data.stream);
|
||||
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "url: %s\n", query);
|
||||
curl_handle = curl_easy_init();
|
||||
|
||||
@@ -729,6 +726,9 @@ SWITCH_STANDARD_APP(cidlookup_app_function)
|
||||
if (!session && pool) {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
/* This is so compile doesn't failed because status is never used */
|
||||
if (status) {
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(cidlookup_function)
|
||||
|
||||
@@ -217,7 +217,7 @@ int go(int i)
|
||||
int vgo(int i, switch_core_session_t *session)
|
||||
{
|
||||
int x;
|
||||
int sleep_len = 40000;
|
||||
//int sleep_len = 40000;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_frame_t *read_frame;
|
||||
switch_status_t status;
|
||||
@@ -233,9 +233,9 @@ int vgo(int i, switch_core_session_t *session)
|
||||
|
||||
printf("%s", SWITCH_SEQ_CLEARSCR);
|
||||
|
||||
if (i > 0) {
|
||||
sleep_len = i;
|
||||
}
|
||||
//if (i > 0) {
|
||||
//sleep_len = i;
|
||||
//}
|
||||
|
||||
initscr();
|
||||
signal(SIGINT, SIG_IGN);
|
||||
|
||||
@@ -116,6 +116,59 @@ static switch_status_t select_url(const char *user,
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#define SAY_STRING_SYNTAX "<module_name>[.<ext>] <lang>[.<ext>] <say_type> <say_method> [<say_gender>] <text>"
|
||||
SWITCH_STANDARD_API(say_string_function)
|
||||
{
|
||||
char *argv[6] = { 0 };
|
||||
int argc;
|
||||
char *lbuf = NULL, *string = NULL;
|
||||
int err = 1, par = 0;
|
||||
char *p, *ext = "wav";
|
||||
|
||||
if (cmd) {
|
||||
lbuf = strdup(cmd);
|
||||
}
|
||||
|
||||
if (lbuf && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) && (argc == 5 || argc == 6)) {
|
||||
|
||||
if ((p = strchr(argv[0], '.'))) {
|
||||
*p++ = '\0';
|
||||
ext = p;
|
||||
par++;
|
||||
}
|
||||
|
||||
if (!par && (p = strchr(argv[1], '.'))) {
|
||||
*p++ = '\0';
|
||||
ext = p;
|
||||
}
|
||||
switch_ivr_say_string(session,
|
||||
argv[1],
|
||||
ext,
|
||||
(argc == 5) ? argv[4] : argv[5],
|
||||
argv[0],
|
||||
argv[2],
|
||||
argv[3],
|
||||
(argc == 6) ? argv[4] : NULL ,
|
||||
&string);
|
||||
if (string) {
|
||||
stream->write_function(stream, "%s", string);
|
||||
free(string);
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
stream->write_function(stream, "-ERR Usage: %s\n", SAY_STRING_SYNTAX);
|
||||
}
|
||||
|
||||
free(lbuf);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_API(reg_url_function)
|
||||
{
|
||||
char *data;
|
||||
@@ -196,9 +249,13 @@ SWITCH_STANDARD_API(banner_function)
|
||||
|
||||
SWITCH_STANDARD_API(hostname_api_function)
|
||||
{
|
||||
char hostname[256] = "";
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
stream->write_function(stream, "%s", hostname);
|
||||
stream->write_function(stream, "%s", switch_core_get_hostname());
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(switchname_api_function)
|
||||
{
|
||||
stream->write_function(stream, "%s", switch_core_get_switchname());
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -276,6 +333,7 @@ SWITCH_STANDARD_API(nat_map_function)
|
||||
switch_port_t external_port = 0;
|
||||
char *tmp = NULL;
|
||||
switch_bool_t sticky = SWITCH_FALSE;
|
||||
switch_bool_t mapping = SWITCH_TRUE;
|
||||
|
||||
if (!cmd) {
|
||||
goto usage;
|
||||
@@ -310,6 +368,24 @@ SWITCH_STANDARD_API(nat_map_function)
|
||||
goto ok;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (argv[0] && switch_stristr("mapping", argv[0])) {
|
||||
if (argv[1] && switch_stristr("enable", argv[1])) {
|
||||
mapping = SWITCH_TRUE;
|
||||
} else if (argv[1] && switch_stristr("disable", argv[1])) {
|
||||
mapping = SWITCH_FALSE;
|
||||
}
|
||||
|
||||
switch_nat_set_mapping(mapping);
|
||||
tmp = switch_nat_status();
|
||||
stream->write_function(stream, tmp);
|
||||
switch_safe_free(tmp);
|
||||
goto ok;
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
goto error;
|
||||
}
|
||||
@@ -342,7 +418,7 @@ SWITCH_STANDARD_API(nat_map_function)
|
||||
goto ok;
|
||||
|
||||
usage:
|
||||
stream->write_function(stream, "USAGE: nat_map [status|reinit|republish] | [add|del] <port> [tcp|udp] [sticky]");
|
||||
stream->write_function(stream, "USAGE: nat_map [status|reinit|republish] | [add|del] <port> [tcp|udp] [sticky] | [mapping] <enable|disable>");
|
||||
|
||||
ok:
|
||||
|
||||
@@ -448,7 +524,7 @@ SWITCH_STANDARD_API(timer_test_function)
|
||||
timer_name = argv[2];
|
||||
}
|
||||
|
||||
if (mss != 10 && mss != 20 && mss != 30 && mss != 40 && mss != 60 && mss != 120) {
|
||||
if (mss != 10 && mss != 20 && mss != 30 && mss != 32 && mss != 40 && mss != 60 && mss != 120) {
|
||||
stream->write_function(stream, "parameter missing: %s\n", TIMER_TEST_SYNTAX);
|
||||
goto end;
|
||||
}
|
||||
@@ -2557,7 +2633,6 @@ SWITCH_STANDARD_API(uuid_broadcast_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[4] = { 0 };
|
||||
int argc = 0;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
@@ -2591,7 +2666,7 @@ SWITCH_STANDARD_API(uuid_broadcast_function)
|
||||
flags = SMF_ECHO_ALEG | SMF_HOLD_BLEG;
|
||||
}
|
||||
|
||||
status = switch_ivr_broadcast(argv[0], argv[1], flags);
|
||||
switch_ivr_broadcast(argv[0], argv[1], flags);
|
||||
stream->write_function(stream, "+OK Message Sent\n");
|
||||
}
|
||||
|
||||
@@ -2604,7 +2679,6 @@ SWITCH_STANDARD_API(sched_broadcast_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[4] = { 0 };
|
||||
int argc = 0;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
@@ -2634,7 +2708,7 @@ SWITCH_STANDARD_API(sched_broadcast_function)
|
||||
flags |= SMF_ECHO_ALEG;
|
||||
}
|
||||
|
||||
status = switch_ivr_schedule_broadcast(when, argv[1], argv[2], flags);
|
||||
switch_ivr_schedule_broadcast(when, argv[1], argv[2], flags);
|
||||
stream->write_function(stream, "+OK Message Scheduled\n");
|
||||
}
|
||||
|
||||
@@ -2719,8 +2793,6 @@ SWITCH_STANDARD_API(uuid_buglist_function)
|
||||
char *mydata = NULL, *argv[2] = { 0 };
|
||||
int argc = 0;
|
||||
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
goto error;
|
||||
}
|
||||
@@ -2737,7 +2809,7 @@ SWITCH_STANDARD_API(uuid_buglist_function)
|
||||
switch_core_session_t *lsession = NULL;
|
||||
|
||||
if ((lsession = switch_core_session_locate(argv[0]))) {
|
||||
status = switch_core_media_bug_enumerate(lsession, stream);
|
||||
switch_core_media_bug_enumerate(lsession, stream);
|
||||
switch_core_session_rwunlock(lsession);
|
||||
}
|
||||
goto ok;
|
||||
@@ -3819,13 +3891,10 @@ SWITCH_STANDARD_API(show_function)
|
||||
struct holder holder = { 0 };
|
||||
int help = 0;
|
||||
char *mydata = NULL, *argv[6] = { 0 };
|
||||
int argc;
|
||||
char *command = NULL, *as = NULL;
|
||||
switch_core_flag_t cflags = switch_core_flags();
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
char hostname[256] = "";
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
|
||||
const char *hostname = switch_core_get_switchname();
|
||||
|
||||
if (!(cflags & SCF_USE_SQL)) {
|
||||
stream->write_function(stream, "-ERR SQL DISABLED NO DATA AVAILABLE!\n");
|
||||
@@ -3840,7 +3909,7 @@ SWITCH_STANDARD_API(show_function)
|
||||
holder.justcount = 0;
|
||||
|
||||
if (cmd && (mydata = strdup(cmd))) {
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
command = argv[0];
|
||||
if (argv[2] && !strcasecmp(argv[1], "as")) {
|
||||
as = argv[2];
|
||||
@@ -4334,10 +4403,10 @@ SWITCH_STANDARD_API(uuid_fileman_function)
|
||||
char *cmd = argv[1];
|
||||
|
||||
if ((psession = switch_core_session_locate(uuid))) {
|
||||
switch_channel_t *channel;
|
||||
//switch_channel_t *channel;
|
||||
switch_file_handle_t *fh = NULL;
|
||||
|
||||
channel = switch_core_session_get_channel(psession);
|
||||
//channel = switch_core_session_get_channel(psession);
|
||||
|
||||
if (switch_ivr_get_file_handle(psession, &fh) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_ivr_process_fh(psession, cmd, fh);
|
||||
@@ -4645,13 +4714,12 @@ SWITCH_STANDARD_API(strftime_tz_api_function)
|
||||
SWITCH_STANDARD_API(hupall_api_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[3] = { 0 };
|
||||
int argc = 0;
|
||||
char *var = NULL;
|
||||
char *val = NULL;
|
||||
switch_call_cause_t cause = SWITCH_CAUSE_MANAGER_REQUEST;
|
||||
|
||||
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_assert(argv[0]);
|
||||
if ((cause = switch_channel_str2cause(argv[0])) == SWITCH_CAUSE_NONE) {
|
||||
cause = SWITCH_CAUSE_MANAGER_REQUEST;
|
||||
@@ -4680,6 +4748,30 @@ SWITCH_STANDARD_API(hupall_api_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_API(xml_flush_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[3] = { 0 };
|
||||
int argc = 0;
|
||||
int r = 0;
|
||||
|
||||
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
|
||||
argc = switch_split(mycmd, ' ', argv);
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
r = switch_xml_clear_user_cache(argv[0], argv[1], argv[2]);
|
||||
} else {
|
||||
r = switch_xml_clear_user_cache(NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
stream->write_function(stream, "+OK cleared %u entr%s\n", r, r == 1 ? "y" : "ies");
|
||||
|
||||
switch_safe_free(mycmd);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(escape_function)
|
||||
{
|
||||
int len;
|
||||
@@ -4871,6 +4963,87 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define LIMIT_SYNTAX "<uuid> <backend> <realm> <resource> [<max>[/interval]] [number [dialplan [context]]]"
|
||||
SWITCH_STANDARD_API(uuid_limit_function)
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[8] = { 0 };
|
||||
char *mydata = NULL;
|
||||
char *realm = NULL;
|
||||
char *resource = NULL;
|
||||
char *xfer_exten = NULL;
|
||||
int max = -1;
|
||||
int interval = 0;
|
||||
switch_core_session_t *sess = NULL;
|
||||
switch_status_t res = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mydata = strdup(cmd);
|
||||
switch_assert(mydata);
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argc < 4) {
|
||||
stream->write_function(stream, "USAGE: uuid_limit %s\n", LIMIT_SYNTAX);
|
||||
goto end;
|
||||
}
|
||||
|
||||
realm = argv[2];
|
||||
resource = argv[3];
|
||||
|
||||
/* If max is omitted or negative, only act as a counter and skip maximum checks */
|
||||
if (argc > 4) {
|
||||
if (argv[4][0] == '-') {
|
||||
max = -1;
|
||||
} else {
|
||||
char *szinterval = NULL;
|
||||
if ((szinterval = strchr(argv[4], '/'))) {
|
||||
*szinterval++ = '\0';
|
||||
interval = atoi(szinterval);
|
||||
}
|
||||
|
||||
max = atoi(argv[4]);
|
||||
|
||||
if (max < 0) {
|
||||
max = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 5) {
|
||||
xfer_exten = argv[5];
|
||||
} else {
|
||||
xfer_exten = LIMIT_DEF_XFER_EXTEN;
|
||||
}
|
||||
|
||||
sess = switch_core_session_locate(argv[0]);
|
||||
if (!sess) {
|
||||
stream->write_function(stream, "-ERR did not find a session with uuid %s\n", argv[0]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = switch_limit_incr(argv[1], sess, realm, resource, max, interval);
|
||||
|
||||
if (res != SWITCH_STATUS_SUCCESS) {
|
||||
/* Limit exceeded */
|
||||
if (*xfer_exten == '!') {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(sess);
|
||||
switch_channel_hangup(channel, switch_channel_str2cause(xfer_exten + 1));
|
||||
} else {
|
||||
switch_ivr_session_transfer(sess, xfer_exten, argv[6], argv[7]);
|
||||
}
|
||||
}
|
||||
|
||||
switch_core_session_rwunlock(sess);
|
||||
|
||||
stream->write_function(stream, "+OK");
|
||||
|
||||
end:
|
||||
switch_safe_free(mydata);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define LIMIT_RELEASE_SYNTAX "<uuid> <backend> [realm] [resource]"
|
||||
SWITCH_STANDARD_API(uuid_limit_release_function)
|
||||
{
|
||||
@@ -5031,6 +5204,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "help", "Show help for all the api commands", help_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "host_lookup", "host_lookup", host_lookup_function, "<hostname>");
|
||||
SWITCH_ADD_API(commands_api_interface, "hostname", "Returns the system hostname", hostname_api_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "switchname", "Returns the switch name", switchname_api_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "hupall", "hupall", hupall_api_function, "<cause> [<var> <value>]");
|
||||
SWITCH_ADD_API(commands_api_interface, "in_group", "determine if a user is in a group", in_group_function, "<user>[@<domain>] <group_name>");
|
||||
SWITCH_ADD_API(commands_api_interface, "is_lan_addr", "see if an ip is a lan addr", lan_addr_function, "<ip>");
|
||||
@@ -5052,6 +5226,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, UNLOAD_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "replace", "replace a string", replace_function, "<data>|<string1>|<string2>");
|
||||
SWITCH_ADD_API(commands_api_interface, "say_string", "", say_string_function, SAY_STRING_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "sched_api", "Schedule an api command", sched_api_function, SCHED_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "sched_broadcast", "Schedule a broadcast event to a running call", sched_broadcast_function,
|
||||
SCHED_BROADCAST_SYNTAX);
|
||||
@@ -5092,6 +5267,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
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_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);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_loglevel", "set loglevel on session", uuid_loglevel, UUID_LOGLEVEL_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_media", "media", uuid_media_function, MEDIA_SYNTAX);
|
||||
@@ -5110,8 +5286,11 @@ 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, "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>");
|
||||
|
||||
|
||||
switch_console_set_complete("add alias add");
|
||||
switch_console_set_complete("add alias del");
|
||||
switch_console_set_complete("add complete add");
|
||||
@@ -5211,6 +5390,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
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");
|
||||
switch_console_set_complete("add uuid_limit ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_limit_release ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_loglevel ::console::list_uuid console");
|
||||
switch_console_set_complete("add uuid_loglevel ::console::list_uuid alert");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -104,7 +104,6 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c
|
||||
|
||||
CURL *curl_handle = NULL;
|
||||
long httpRes = 0;
|
||||
char hostname[256] = "";
|
||||
|
||||
http_data_t *http_data = NULL;
|
||||
|
||||
@@ -115,8 +114,6 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c
|
||||
http_data->max_bytes = 64000;
|
||||
SWITCH_STANDARD_STREAM(http_data->stream);
|
||||
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
|
||||
if (!method) {
|
||||
method = "get";
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_db_load)
|
||||
switch_limit_interface_t *limit_interface;
|
||||
|
||||
memset(&globals, 0, sizeof(&globals));
|
||||
gethostname(globals.hostname, sizeof(globals.hostname));
|
||||
strncpy(globals.hostname, switch_core_get_switchname(), sizeof(globals.hostname));
|
||||
globals.pool = pool;
|
||||
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ static switch_xml_config_int_options_t config_int_ht_0 = { SWITCH_TRUE, 0 };
|
||||
|
||||
static struct {
|
||||
switch_hash_t *profile_hash;
|
||||
char hostname[256];
|
||||
const char *hostname;
|
||||
int integer;
|
||||
int debug;
|
||||
char *dbname;
|
||||
@@ -949,7 +949,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_directory_load)
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
gethostname(globals.hostname, sizeof(globals.hostname));
|
||||
globals.hostname = switch_core_get_switchname();
|
||||
|
||||
globals.dbname = switch_core_sprintf(pool, "directory");
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
* Neal Horman <neal at wanlink dot com>
|
||||
* Bret McDanel <trixter AT 0xdecafbad dot com>
|
||||
* Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
|
||||
* Cesar Cepeda <cesar@auronix.com>
|
||||
*
|
||||
* mod_dptools.c -- Raw Audio File Streaming Application Module
|
||||
*
|
||||
@@ -1032,7 +1033,7 @@ SWITCH_STANDARD_APP(sched_cancel_function)
|
||||
switch_scheduler_del_task_group(group);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(set_function)
|
||||
static void base_set (switch_core_session_t *session, const char *data, switch_stack_t stack)
|
||||
{
|
||||
char *var, *val = NULL;
|
||||
|
||||
@@ -1043,7 +1044,10 @@ SWITCH_STANDARD_APP(set_function)
|
||||
char *expanded = NULL;
|
||||
|
||||
var = switch_core_session_strdup(session, data);
|
||||
val = strchr(var, '=');
|
||||
|
||||
if (!(val = strchr(var, '='))) {
|
||||
val = strchr(var, ',');
|
||||
}
|
||||
|
||||
if (val) {
|
||||
*val++ = '\0';
|
||||
@@ -1058,7 +1062,7 @@ SWITCH_STANDARD_APP(set_function)
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SET [%s]=[%s]\n", switch_channel_get_name(channel), var,
|
||||
expanded ? expanded : "UNDEF");
|
||||
switch_channel_set_variable_var_check(channel, var, expanded, SWITCH_FALSE);
|
||||
switch_channel_add_variable_var_check(channel, var, expanded, SWITCH_FALSE, stack);
|
||||
|
||||
if (expanded && expanded != val) {
|
||||
switch_safe_free(expanded);
|
||||
@@ -1066,6 +1070,21 @@ SWITCH_STANDARD_APP(set_function)
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(set_function)
|
||||
{
|
||||
base_set(session, data, SWITCH_STACK_BOTTOM);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(push_function)
|
||||
{
|
||||
base_set(session, data, SWITCH_STACK_PUSH);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(unshift_function)
|
||||
{
|
||||
base_set(session, data, SWITCH_STACK_UNSHIFT);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(set_global_function)
|
||||
{
|
||||
char *var, *val = NULL;
|
||||
@@ -1551,7 +1570,8 @@ SWITCH_STANDARD_APP(tone_detect_session_function)
|
||||
int argc;
|
||||
char *mydata = NULL;
|
||||
time_t to = 0;
|
||||
int hits = 1;
|
||||
int hits = 0;
|
||||
const char *hp = NULL;
|
||||
|
||||
if (zstr(data) || !(mydata = switch_core_session_strdup(session, data))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "INVALID ARGS!\n");
|
||||
@@ -1581,10 +1601,16 @@ SWITCH_STANDARD_APP(tone_detect_session_function)
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[6]) {
|
||||
hits = atoi(argv[6]);
|
||||
if (argv[4] && argv[5]) {
|
||||
hp = argv[6];
|
||||
} else if (argv[4] && !argv[6]) {
|
||||
hp = argv[4];
|
||||
}
|
||||
|
||||
if (hp) {
|
||||
hits = atoi(hp);
|
||||
if (hits < 0) {
|
||||
hits = 1;
|
||||
hits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2077,7 +2103,7 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
|
||||
prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer), digits_regex, digit_timeout);
|
||||
}
|
||||
|
||||
#define SAY_SYNTAX "<module_name> <say_type> <say_method> [<say_gender>] <text>"
|
||||
#define SAY_SYNTAX "<module_name>[:<lang>] <say_type> <say_method> [<say_gender>] <text>"
|
||||
SWITCH_STANDARD_APP(say_function)
|
||||
{
|
||||
char *argv[5] = { 0 };
|
||||
@@ -2093,6 +2119,11 @@ SWITCH_STANDARD_APP(say_function)
|
||||
|
||||
switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, "");
|
||||
|
||||
/* Set default langauge according to the <module_name> */
|
||||
if (!strchr(argv[0], ':')) {
|
||||
argv[0] = switch_core_session_sprintf(session, "%s:%s", argv[0], argv[0]);
|
||||
}
|
||||
|
||||
switch_ivr_say(session, (argc == 4) ? argv[3] : argv[4], argv[0], argv[1], argv[2], (argc == 5) ? argv[3] : NULL ,&args);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Usage: %s\n", SAY_SYNTAX);
|
||||
@@ -2277,6 +2308,26 @@ SWITCH_STANDARD_APP(stop_displace_session_function)
|
||||
switch_ivr_stop_displace_session(session, data);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(capture_function)
|
||||
{
|
||||
char *argv[3] = { 0 };
|
||||
int argc;
|
||||
switch_regex_t *re = NULL;
|
||||
int ovector[30] = {0};
|
||||
char *lbuf;
|
||||
int proceed;
|
||||
|
||||
if (!zstr(data) && (lbuf = switch_core_session_strdup(session, data))
|
||||
&& (argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])))) == 3) {
|
||||
if ((proceed = switch_regex_perform(argv[1], argv[2], &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
switch_capture_regex(re, proceed, argv[1], ovector, argv[0], (switch_cap_callback_t)switch_regex_set_var_callback, session);
|
||||
}
|
||||
switch_regex_safe_free(re);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No data specified.\n");
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(record_function)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
@@ -2285,14 +2336,14 @@ SWITCH_STANDARD_APP(record_function)
|
||||
char *path;
|
||||
switch_input_args_t args = { 0 };
|
||||
switch_file_handle_t fh = { 0 };
|
||||
int argc;
|
||||
//int argc;
|
||||
char *mydata, *argv[4] = { 0 };
|
||||
char *l = NULL;
|
||||
const char *tmp;
|
||||
int rate;
|
||||
|
||||
if (!zstr(data) && (mydata = switch_core_session_strdup(session, data))) {
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No file specified.\n");
|
||||
return;
|
||||
@@ -2473,6 +2524,11 @@ SWITCH_STANDARD_APP(audio_bridge_function)
|
||||
{
|
||||
switch_channel_t *caller_channel = switch_core_session_get_channel(session);
|
||||
switch_core_session_t *peer_session = NULL;
|
||||
|
||||
const char *transfer_on_fail = NULL;
|
||||
char *tof_data = NULL;
|
||||
char *tof_array[4] = { 0 };
|
||||
//int tof_arrayc = 0;
|
||||
const char *continue_on_fail = NULL, *failure_causes = NULL,
|
||||
*v_campon = NULL, *v_campon_retries, *v_campon_sleep, *v_campon_timeout, *v_campon_fallback_exten = NULL;
|
||||
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
||||
@@ -2489,8 +2545,14 @@ SWITCH_STANDARD_APP(audio_bridge_function)
|
||||
}
|
||||
|
||||
continue_on_fail = switch_channel_get_variable(caller_channel, "continue_on_fail");
|
||||
failure_causes = switch_channel_get_variable(caller_channel, "failure_causes");
|
||||
|
||||
transfer_on_fail = switch_channel_get_variable(caller_channel, "transfer_on_fail");
|
||||
tof_data = switch_core_session_strdup(session, transfer_on_fail);
|
||||
switch_split(tof_data, ' ', tof_array);
|
||||
transfer_on_fail = tof_array[0];
|
||||
|
||||
failure_causes = switch_channel_get_variable(caller_channel, "failure_causes");
|
||||
|
||||
if ((v_campon = switch_channel_get_variable(caller_channel, "campon")) && switch_true(v_campon)) {
|
||||
const char *cid_name = NULL;
|
||||
const char *cid_number = NULL;
|
||||
@@ -2681,6 +2743,57 @@ SWITCH_STANDARD_APP(audio_bridge_function)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (transfer_on_fail || failure_causes) {
|
||||
const char *cause_str;
|
||||
char cause_num[35] = "";
|
||||
|
||||
cause_str = switch_channel_cause2str(cause);
|
||||
switch_snprintf(cause_num, sizeof(cause_num), "%u", cause);
|
||||
|
||||
if ((tof_array[1] == NULL ) || (!strcasecmp(tof_array[1], "auto_cause"))){
|
||||
tof_array[1] = (char *) cause_str;
|
||||
}
|
||||
|
||||
if (failure_causes) {
|
||||
char *lbuf = switch_core_session_strdup(session, failure_causes);
|
||||
char *argv[256] = { 0 };
|
||||
int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
int i, x = 0;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
|
||||
x++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!x) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
|
||||
"Failure causes [%s]: Cause: %s\n", failure_causes, cause_str);
|
||||
|
||||
switch_ivr_session_transfer(session, tof_array[1], tof_array[2], tof_array[3]);
|
||||
}
|
||||
}
|
||||
|
||||
if (transfer_on_fail) {
|
||||
if (switch_true(transfer_on_fail)) {
|
||||
return;
|
||||
} else {
|
||||
char *lbuf = switch_core_session_strdup(session, transfer_on_fail);
|
||||
char *argv[256] = { 0 };
|
||||
int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
|
||||
"Transfer on fail [%s]: Cause: %s\n", transfer_on_fail, cause_str);
|
||||
switch_ivr_session_transfer(session, tof_array[1], tof_array[2], tof_array[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!switch_channel_test_flag(caller_channel, CF_TRANSFER) && switch_channel_get_state(caller_channel) != CS_ROUTING) {
|
||||
switch_channel_hangup(caller_channel, cause);
|
||||
@@ -2789,7 +2902,7 @@ static switch_call_cause_t group_outgoing_channel(switch_core_session_t *session
|
||||
if ((domain = strchr(group, '@'))) {
|
||||
*domain++ = '\0';
|
||||
} else {
|
||||
domain = switch_core_get_variable_pdup("domain", switch_core_session_get_pool(session));
|
||||
domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = domain;
|
||||
}
|
||||
|
||||
@@ -2890,7 +3003,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 x_domain = NULL, xml = NULL, x_user = NULL, x_group = NULL, x_param, x_params;
|
||||
switch_xml_t xml = NULL, 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;
|
||||
@@ -2937,48 +3050,12 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
var_event = NULL;
|
||||
}
|
||||
|
||||
if (switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, &x_group, params) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_xml_locate_user_merged("id", user, domain, NULL, &x_user, params) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Can't find user [%s@%s]\n", user, domain);
|
||||
cause = SWITCH_CAUSE_SUBSCRIBER_ABSENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((x_params = switch_xml_child(x_domain, "params"))) {
|
||||
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
|
||||
const char *pvar = switch_xml_attr(x_param, "name");
|
||||
const char *val = switch_xml_attr(x_param, "value");
|
||||
|
||||
if (!strcasecmp(pvar, "dial-string")) {
|
||||
dest = val;
|
||||
} else if (!strncasecmp(pvar, "dial-var-", 9)) {
|
||||
if (!var_event) {
|
||||
switch_event_create(&var_event, SWITCH_EVENT_GENERAL);
|
||||
} else {
|
||||
switch_event_del_header(var_event, pvar + 9);
|
||||
}
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, pvar + 9, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((x_params = switch_xml_child(x_group, "params"))) {
|
||||
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
|
||||
const char *pvar = switch_xml_attr(x_param, "name");
|
||||
const char *val = switch_xml_attr(x_param, "value");
|
||||
|
||||
if (!strcasecmp(pvar, "dial-string")) {
|
||||
dest = val;
|
||||
} else if (!strncasecmp(pvar, "dial-var-", 9)) {
|
||||
if (!var_event) {
|
||||
switch_event_create(&var_event, SWITCH_EVENT_GENERAL);
|
||||
} else {
|
||||
switch_event_del_header(var_event, pvar + 9);
|
||||
}
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, pvar + 9, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((x_params = switch_xml_child(x_user, "params"))) {
|
||||
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
|
||||
const char *pvar = switch_xml_attr(x_param, "name");
|
||||
@@ -2996,8 +3073,9 @@ 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);
|
||||
|
||||
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");
|
||||
@@ -3090,14 +3168,6 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
}
|
||||
|
||||
if (new_channel && xml) {
|
||||
if ((x_params = switch_xml_child(x_domain, "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");
|
||||
const char *val = switch_xml_attr(x_param, "value");
|
||||
switch_channel_set_variable(new_channel, pvar, val);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -3463,6 +3533,173 @@ SWITCH_STANDARD_APP(limit_hash_execute_function)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* FILE STRING INTERFACE */
|
||||
|
||||
/* for apr_pstrcat */
|
||||
#define DEFAULT_PREBUFFER_SIZE 1024 * 64
|
||||
|
||||
struct file_string_source;
|
||||
|
||||
struct file_string_context {
|
||||
char *argv[128];
|
||||
int argc;
|
||||
int index;
|
||||
int samples;
|
||||
switch_file_handle_t fh;
|
||||
};
|
||||
|
||||
typedef struct file_string_context file_string_context_t;
|
||||
|
||||
|
||||
static int next_file(switch_file_handle_t *handle)
|
||||
{
|
||||
file_string_context_t *context = handle->private_info;
|
||||
char *file;
|
||||
const char *prefix = handle->prefix;
|
||||
|
||||
top:
|
||||
|
||||
context->index++;
|
||||
|
||||
if (switch_test_flag((&context->fh), SWITCH_FILE_OPEN)) {
|
||||
switch_core_file_close(&context->fh);
|
||||
}
|
||||
|
||||
if (context->index >= context->argc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (!prefix) {
|
||||
if (!(prefix = switch_core_get_variable_pdup("sound_prefix", handle->memory_pool))) {
|
||||
prefix = SWITCH_GLOBAL_dirs.sounds_dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prefix || switch_is_file_path(context->argv[context->index])) {
|
||||
file = context->argv[context->index];
|
||||
} else {
|
||||
file = switch_core_sprintf(handle->memory_pool, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, context->argv[context->index]);
|
||||
}
|
||||
|
||||
if (switch_core_file_open(&context->fh,
|
||||
file, handle->channels, handle->samplerate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
goto top;
|
||||
}
|
||||
|
||||
handle->samples = context->fh.samples;
|
||||
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;
|
||||
handle->speed = context->fh.speed;
|
||||
handle->interval = context->fh.interval;
|
||||
|
||||
if (switch_test_flag((&context->fh), SWITCH_FILE_NATIVE)) {
|
||||
switch_set_flag(handle, SWITCH_FILE_NATIVE);
|
||||
} else {
|
||||
switch_clear_flag(handle, SWITCH_FILE_NATIVE);
|
||||
}
|
||||
|
||||
|
||||
if (!switch_test_flag(handle, SWITCH_FILE_NATIVE)) {
|
||||
if (context->index == 0) {
|
||||
context->samples = (handle->samplerate / 1000) * 250;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t file_string_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
|
||||
{
|
||||
file_string_context_t *context = handle->private_info;
|
||||
|
||||
if (samples == 0 && whence == SEEK_SET) {
|
||||
context->index = -1;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!handle->seekable) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File is not seekable\n");
|
||||
return SWITCH_STATUS_NOTIMPL;
|
||||
}
|
||||
|
||||
return switch_core_file_seek(&context->fh, cur_sample, samples, whence);
|
||||
}
|
||||
|
||||
static switch_status_t file_string_file_open(switch_file_handle_t *handle, const char *path)
|
||||
{
|
||||
file_string_context_t *context;
|
||||
char *file_dup;
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
context = switch_core_alloc(handle->memory_pool, sizeof(*context));
|
||||
|
||||
file_dup = switch_core_strdup(handle->memory_pool, path);
|
||||
context->argc = switch_separate_string(file_dup, '!', context->argv, (sizeof(context->argv) / sizeof(context->argv[0])));
|
||||
context->index = -1;
|
||||
|
||||
handle->private_info = context;
|
||||
|
||||
return next_file(handle) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t file_string_file_read(switch_file_handle_t *handle, void *data, size_t *len)
|
||||
{
|
||||
file_string_context_t *context = handle->private_info;
|
||||
switch_status_t status;
|
||||
size_t llen = *len;
|
||||
|
||||
if (context->samples > 0) {
|
||||
if (*len > (size_t) context->samples) {
|
||||
*len = context->samples;
|
||||
}
|
||||
|
||||
context->samples -= *len;
|
||||
memset(data, 255, *len *2);
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = switch_core_file_read(&context->fh, data, len);
|
||||
}
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
if (!next_file(handle)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
*len = llen;
|
||||
status = switch_core_file_read(&context->fh, data, len);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Registration */
|
||||
|
||||
static char *file_string_supported_formats[SWITCH_MAX_CODECS] = { 0 };
|
||||
|
||||
|
||||
/* /FILE STRING INTERFACE */
|
||||
|
||||
|
||||
|
||||
#define SPEAK_DESC "Speak text to a channel via the tts interface"
|
||||
#define DISPLACE_DESC "Displace audio from a file to the channels input"
|
||||
#define SESS_REC_DESC "Starts a background recording of the entire session"
|
||||
@@ -3484,10 +3721,22 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_dialplan_interface_t *dp_interface;
|
||||
switch_chat_interface_t *chat_interface;
|
||||
switch_file_interface_t *file_interface;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
file_string_supported_formats[0] = "file_string";
|
||||
|
||||
file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
|
||||
file_interface->interface_name = modname;
|
||||
file_interface->extens = file_string_supported_formats;
|
||||
file_interface->file_open = file_string_file_open;
|
||||
file_interface->file_close = file_string_file_close;
|
||||
file_interface->file_read = file_string_file_read;
|
||||
file_interface->file_seek = file_string_file_seek;
|
||||
|
||||
|
||||
error_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
|
||||
error_endpoint_interface->interface_name = "error";
|
||||
error_endpoint_interface->io_routines = &error_io_routines;
|
||||
@@ -3511,6 +3760,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "bind_digit_action", "bind a key sequence or regex to an action",
|
||||
"bind a key sequence or regex to an action", bind_digit_action_function, BIND_DIGIT_ACTION_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "capture", "capture data into a var", "capture data into a var",
|
||||
capture_function, "<varname>|<data>|<regex>", SAF_SUPPORT_NOMEDIA);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "clear_digit_action", "clear all digit bindings", "",
|
||||
clear_digit_action_function, CLEAR_DIGIT_ACTION_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
|
||||
@@ -3558,6 +3810,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "set", "Set a channel variable", SET_LONG_DESC, set_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "push", "Set a channel variable", SET_LONG_DESC, push_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "unshift", "Set a channel variable", SET_LONG_DESC, unshift_function, "<varname>=<value>",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_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);
|
||||
SWITCH_ADD_APP(app_interface, "set_profile_var", "Set a caller profile variable", SET_PROFILE_VAR_LONG_DESC, set_profile_var_function,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
BASE=../../../..
|
||||
|
||||
LDNS=ldns
|
||||
|
||||
LDNS_DIR=$(switch_srcdir)/libs/$(LDNS)
|
||||
LDNS_BUILDDIR=$(switch_builddir)/libs/$(LDNS)
|
||||
LOCAL_CFLAGS=-I$(LDNS_DIR) -I$(LDNS_DIR)/include
|
||||
LDNS_LA=$(LDNS_BUILDDIR)/libldns.la
|
||||
LOCAL_LIBADD=$(LDNS_LA)
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
$(LDNS_BUILDDIR)/Makefile: $(LDNS_DIR)/Makefile.in
|
||||
mkdir -p $(LDNS_BUILDDIR)
|
||||
cd $(LDNS_BUILDDIR) && $(DEFAULT_VARS) $(LDNS_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(LDNS_DIR) --disable-gost --without-ssl --disable-sha2
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(LDNS_LA): $(LDNS_BUILDDIR)/Makefile
|
||||
cd $(LDNS_BUILDDIR) && $(MAKE)
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(MODNAME).lo: $(LDNS_LA)
|
||||
@@ -1,13 +0,0 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_enum
|
||||
|
||||
UDNS_DIR=$(switch_srcdir)/libs/udns
|
||||
mod_enum_la_CFLAGS = -I$(UDNS_DIR) -DHAVE_POLL $(AM_CFLAGS)
|
||||
|
||||
mod_LTLIBRARIES = mod_enum.la
|
||||
mod_enum_la_SOURCES = mod_enum.c
|
||||
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_dn.c $(UDNS_DIR)/udns_dntosp.c $(UDNS_DIR)/udns_parse.c $(UDNS_DIR)/udns_misc.c
|
||||
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_a.c $(UDNS_DIR)/udns_rr_ptr.c $(UDNS_DIR)/udns_rr_mx.c $(UDNS_DIR)/udns_rr_txt.c $(UDNS_DIR)/udns_bl.c
|
||||
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_srv.c $(UDNS_DIR)/udns_rr_naptr.c $(UDNS_DIR)/udns_codes.c $(UDNS_DIR)/udns_resolver.c
|
||||
mod_enum_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_enum_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
||||
@@ -0,0 +1,323 @@
|
||||
diff -ru b/ldns/ldns.h a/ldns/ldns.h
|
||||
--- b/ldns/ldns.h 2011-03-24 20:32:30.000000000 -0500
|
||||
+++ a/ldns/ldns.h 2011-03-24 20:29:03.000000000 -0500
|
||||
@@ -148,6 +148,16 @@
|
||||
/** EDNS flags */
|
||||
extern ldns_lookup_table ldns_edns_flags[];
|
||||
|
||||
+
|
||||
+#ifdef USE_WINSOCK
|
||||
+#define SOCK_INVALID INVALID_SOCKET
|
||||
+#define close_socket(_s) if (_s > SOCK_INVALID) {closesocket(_s); _s = SOCK_INVALID;}
|
||||
+#else
|
||||
+#define SOCK_INVALID -1
|
||||
+#define close_socket(_s) if (_s > SOCK_INVALID) {close(_s); _s = SOCK_INVALID;}
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff -ru b/net.c a/net.c
|
||||
--- b/net.c 2011-02-11 10:50:46.000000000 -0600
|
||||
+++ a/net.c 2011-03-24 20:28:15.000000000 -0500
|
||||
@@ -261,12 +261,18 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
+#ifndef WIN32
|
||||
+#include <poll.h>
|
||||
+#endif
|
||||
+
|
||||
/** wait for a socket to become ready */
|
||||
static int
|
||||
ldns_sock_wait(int sockfd, struct timeval timeout, int write)
|
||||
{
|
||||
- fd_set fds;
|
||||
int ret;
|
||||
+
|
||||
+#ifdef WIN32
|
||||
+ fd_set fds;
|
||||
#ifndef S_SPLINT_S
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(FD_SET_T sockfd, &fds);
|
||||
@@ -275,6 +281,26 @@
|
||||
ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
|
||||
else
|
||||
ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
|
||||
+#else
|
||||
+
|
||||
+ struct pollfd pfds[2];
|
||||
+ int x = 0;
|
||||
+
|
||||
+ memset(&pfds[0], 0, sizeof(pfds[0]) * 2);
|
||||
+
|
||||
+ pfds[0].fd = sockfd;
|
||||
+ pfds[0].events = POLLIN|POLLERR;
|
||||
+
|
||||
+ if (write) {
|
||||
+ pfds[0].events |= POLLOUT;
|
||||
+ }
|
||||
+
|
||||
+ ret = poll(pfds, 1, timeout.tv_sec * 1000 + timeout.tv_usec / 1000);
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+
|
||||
if(ret == 0)
|
||||
/* timeout expired */
|
||||
return 0;
|
||||
@@ -299,11 +325,7 @@
|
||||
|
||||
/* wait for an response*/
|
||||
if(!ldns_sock_wait(sockfd, timeout, 0)) {
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(sockfd);
|
||||
-#else
|
||||
- closesocket(sockfd);
|
||||
-#endif
|
||||
+ close_socket(sockfd);
|
||||
return LDNS_STATUS_NETWORK_ERR;
|
||||
}
|
||||
|
||||
@@ -313,11 +335,7 @@
|
||||
ldns_sock_nonblock(sockfd);
|
||||
|
||||
answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(sockfd);
|
||||
-#else
|
||||
- closesocket(sockfd);
|
||||
-#endif
|
||||
+ close_socket(sockfd);
|
||||
|
||||
if (*answer_size == 0) {
|
||||
/* oops */
|
||||
@@ -353,9 +371,10 @@
|
||||
|
||||
if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
|
||||
IPPROTO_UDP))
|
||||
- == -1) {
|
||||
+ == SOCK_INVALID) {
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
@@ -366,20 +385,20 @@
|
||||
int sockfd;
|
||||
|
||||
if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
|
||||
- IPPROTO_TCP)) == -1) {
|
||||
+ IPPROTO_TCP)) == SOCK_INVALID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* perform nonblocking connect, to be able to wait with select() */
|
||||
ldns_sock_nonblock(sockfd);
|
||||
- if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
|
||||
+ if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) {
|
||||
#ifndef USE_WINSOCK
|
||||
#ifdef EINPROGRESS
|
||||
if(errno != EINPROGRESS) {
|
||||
#else
|
||||
if(1) {
|
||||
#endif
|
||||
- close(sockfd);
|
||||
+ close_socket(sockfd);
|
||||
return 0;
|
||||
}
|
||||
#else /* USE_WINSOCK */
|
||||
@@ -398,11 +417,7 @@
|
||||
socklen_t len = (socklen_t)sizeof(error);
|
||||
|
||||
if(!ldns_sock_wait(sockfd, timeout, 1)) {
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(sockfd);
|
||||
-#else
|
||||
- closesocket(sockfd);
|
||||
-#endif
|
||||
+ close_socket(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -421,7 +436,7 @@
|
||||
continue; /* try again */
|
||||
#endif
|
||||
else if(error != 0) {
|
||||
- close(sockfd);
|
||||
+ close_socket(sockfd);
|
||||
/* error in errno for our user */
|
||||
errno = error;
|
||||
return 0;
|
||||
@@ -645,11 +660,7 @@
|
||||
}
|
||||
|
||||
answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(sockfd);
|
||||
-#else
|
||||
- closesocket(sockfd);
|
||||
-#endif
|
||||
+ close_socket(sockfd);
|
||||
|
||||
if (*answer_size == 0) {
|
||||
/* oops */
|
||||
@@ -782,7 +793,7 @@
|
||||
* @hostname is used */
|
||||
for (ns_i = 0;
|
||||
ns_i < ldns_resolver_nameserver_count(resolver) &&
|
||||
- resolver->_socket == 0;
|
||||
+ resolver->_socket == SOCK_INVALID;
|
||||
ns_i++) {
|
||||
ns = ldns_rdf2native_sockaddr_storage(
|
||||
resolver->_nameservers[ns_i],
|
||||
@@ -792,7 +803,7 @@
|
||||
ldns_resolver_timeout(resolver));
|
||||
}
|
||||
|
||||
- if (resolver->_socket == 0) {
|
||||
+ if (resolver->_socket == SOCK_INVALID) {
|
||||
ldns_pkt_free(query);
|
||||
LDNS_FREE(ns);
|
||||
return LDNS_STATUS_NETWORK_ERR;
|
||||
@@ -807,13 +818,7 @@
|
||||
if (status != LDNS_STATUS_OK) {
|
||||
/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
|
||||
we have to close the socket here! */
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
-
|
||||
+ close_socket(resolver->_socket);
|
||||
return LDNS_STATUS_CRYPTO_TSIG_ERR;
|
||||
}
|
||||
}
|
||||
@@ -826,12 +831,8 @@
|
||||
if(!query_wire) {
|
||||
ldns_pkt_free(query);
|
||||
LDNS_FREE(ns);
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
+
|
||||
+ close_socket(resolver->_socket);
|
||||
|
||||
return LDNS_STATUS_MEM_ERR;
|
||||
}
|
||||
@@ -843,12 +844,8 @@
|
||||
|
||||
/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
|
||||
we have to close the socket here! */
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
+
|
||||
+ close_socket(resolver->_socket);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -862,12 +859,8 @@
|
||||
/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
|
||||
we have to close the socket here! */
|
||||
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
+
|
||||
+ close_socket(resolver->_socket);
|
||||
|
||||
return LDNS_STATUS_NETWORK_ERR;
|
||||
}
|
||||
diff -ru b/resolver.c a/resolver.c
|
||||
--- b/resolver.c 2010-12-14 08:41:38.000000000 -0600
|
||||
+++ a/resolver.c 2011-03-24 20:07:17.000000000 -0500
|
||||
@@ -627,9 +627,7 @@
|
||||
r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC;
|
||||
r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC;
|
||||
|
||||
- /* TODO: fd=0 is actually a valid socket (stdin),
|
||||
- replace with -1 */
|
||||
- r->_socket = 0;
|
||||
+ r->_socket = -1;
|
||||
r->_axfr_soa_count = 0;
|
||||
r->_axfr_i = 0;
|
||||
r->_cur_axfr_pkt = NULL;
|
||||
@@ -903,6 +901,8 @@
|
||||
size_t i;
|
||||
|
||||
if (res) {
|
||||
+ close_socket(res->_socket);
|
||||
+
|
||||
if (res->_searchlist) {
|
||||
for (i = 0; i < ldns_resolver_searchlist_count(res); i++) {
|
||||
ldns_rdf_deep_free(res->_searchlist[i]);
|
||||
@@ -1198,7 +1198,7 @@
|
||||
ldns_status status;
|
||||
|
||||
/* check if start() has been called */
|
||||
- if (!resolver || resolver->_socket == 0) {
|
||||
+ if (!resolver || resolver->_socket == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1215,12 +1215,9 @@
|
||||
if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) {
|
||||
resolver->_axfr_soa_count++;
|
||||
if (resolver->_axfr_soa_count >= 2) {
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
+
|
||||
+ close_socket(resolver->_socket);
|
||||
+
|
||||
ldns_pkt_free(resolver->_cur_axfr_pkt);
|
||||
resolver->_cur_axfr_pkt = NULL;
|
||||
}
|
||||
@@ -1243,12 +1240,8 @@
|
||||
/* RoRi: we must now also close the socket, otherwise subsequent uses of the
|
||||
same resolver structure will fail because the link is still open or
|
||||
in an undefined state */
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
+
|
||||
+ close_socket(resolver->_socket);
|
||||
|
||||
return NULL;
|
||||
} else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) {
|
||||
@@ -1258,12 +1251,8 @@
|
||||
/* RoRi: we must now also close the socket, otherwise subsequent uses of the
|
||||
same resolver structure will fail because the link is still open or
|
||||
in an undefined state */
|
||||
-#ifndef USE_WINSOCK
|
||||
- close(resolver->_socket);
|
||||
-#else
|
||||
- closesocket(resolver->_socket);
|
||||
-#endif
|
||||
- resolver->_socket = 0;
|
||||
+
|
||||
+ close_socket(resolver->_socket);
|
||||
|
||||
return NULL;
|
||||
} else {
|
||||
@@ -42,7 +42,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\udns""
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\ldns""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
@@ -106,7 +106,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\udns""
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\ldns""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
@@ -171,7 +171,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\udns""
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\ldns""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
@@ -235,7 +235,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\udns""
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\ldns""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\udns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\ldns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -82,7 +82,7 @@
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\udns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\ldns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -96,7 +96,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\udns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\ldns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -112,7 +112,7 @@
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\udns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\ldns;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -128,9 +128,8 @@
|
||||
<ClCompile Include="mod_enum.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\libs\win32\udns\libudns.2010.vcxproj">
|
||||
<Project>{4043fc6a-9a30-4577-8ad5-9b233c9575d8}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<ProjectReference Include="..\..\..\..\libs\win32\ldns\ldns-lib\ldns-lib.2010.vcxproj">
|
||||
<Project>{23b4d303-79fc-49e0-89e2-2280e7e28940}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
|
||||
@@ -30,11 +30,10 @@
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <udns.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#define closesocket close
|
||||
#ifdef _MSC_VER
|
||||
#define ssize_t int
|
||||
#endif
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_enum_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_enum_shutdown);
|
||||
@@ -49,19 +48,10 @@ struct enum_record {
|
||||
char *route;
|
||||
int supported;
|
||||
struct enum_record *next;
|
||||
struct enum_record *tail;
|
||||
};
|
||||
typedef struct enum_record enum_record_t;
|
||||
|
||||
struct query {
|
||||
const char *name; /* original query string */
|
||||
char *number;
|
||||
unsigned char dn[DNS_MAXDN];
|
||||
enum dns_type qtyp; /* type of the query */
|
||||
enum_record_t *results;
|
||||
int errs;
|
||||
};
|
||||
typedef struct query enum_query_t;
|
||||
|
||||
struct route {
|
||||
char *service;
|
||||
char *regex;
|
||||
@@ -70,20 +60,22 @@ struct route {
|
||||
};
|
||||
typedef struct route enum_route_t;
|
||||
|
||||
static enum dns_class qcls = DNS_C_IN;
|
||||
|
||||
static switch_event_node_t *NODE = NULL;
|
||||
|
||||
static struct {
|
||||
char *root;
|
||||
char *server;
|
||||
char *isn_root;
|
||||
enum_route_t *route_order;
|
||||
switch_memory_pool_t *pool;
|
||||
int auto_reload;
|
||||
int timeout;
|
||||
int retries;
|
||||
int random;
|
||||
} globals;
|
||||
|
||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_root, globals.root);
|
||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_server, globals.server);
|
||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_isn_root, globals.isn_root);
|
||||
|
||||
static void add_route(char *service, char *regex, char *replace)
|
||||
@@ -119,16 +111,28 @@ static switch_status_t load_config(void)
|
||||
goto done;
|
||||
}
|
||||
|
||||
globals.timeout = 5000;
|
||||
globals.retries = 3;
|
||||
globals.random = 0;
|
||||
|
||||
if ((settings = switch_xml_child(cfg, "settings"))) {
|
||||
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||
const char *var = switch_xml_attr_soft(param, "name");
|
||||
const char *val = switch_xml_attr_soft(param, "value");
|
||||
if (!strcasecmp(var, "default-root")) {
|
||||
set_global_root(val);
|
||||
} else if (!strcasecmp(var, "use-server")) {
|
||||
set_global_server(val);
|
||||
} else if (!strcasecmp(var, "auto-reload")) {
|
||||
globals.auto_reload = switch_true(val);
|
||||
} else if (!strcasecmp(var, "query-timeout")) {
|
||||
globals.timeout = atoi(val) * 1000;
|
||||
} else if (!strcasecmp(var, "query-timeout-ms")) {
|
||||
globals.timeout = atoi(val);
|
||||
} else if (!strcasecmp(var, "query-timeout-retry")) {
|
||||
globals.retries = atoi(val);
|
||||
} else if (!strcasecmp(var, "random-nameserver")) {
|
||||
globals.random = switch_true(val);
|
||||
} else if (!strcasecmp(var, "default-isn-root")) {
|
||||
set_global_isn_root(val);
|
||||
} else if (!strcasecmp(var, "log-level-trace")) {
|
||||
@@ -152,6 +156,33 @@ static switch_status_t load_config(void)
|
||||
}
|
||||
|
||||
done:
|
||||
#ifdef _MSC_VER
|
||||
if (!globals.server) {
|
||||
HKEY hKey;
|
||||
DWORD data_sz;
|
||||
char* buf;
|
||||
RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
|
||||
0, KEY_QUERY_VALUE, &hKey);
|
||||
|
||||
if (hKey) {
|
||||
RegQueryValueEx(hKey, "DhcpNameServer", NULL, NULL, NULL, &data_sz);
|
||||
if (data_sz) {
|
||||
buf = (char*)malloc(data_sz + 1);
|
||||
|
||||
RegQueryValueEx(hKey, "DhcpNameServer", NULL, NULL, (LPBYTE)buf, &data_sz);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if(buf[data_sz - 1] != 0) {
|
||||
buf[data_sz] = 0;
|
||||
}
|
||||
switch_replace_char(buf, ' ', 0, SWITCH_FALSE); /* only use the first entry ex "192.168.1.1 192.168.1.2" */
|
||||
globals.server = buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (xml) {
|
||||
switch_xml_free(xml);
|
||||
@@ -168,11 +199,12 @@ static switch_status_t load_config(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
static char *reverse_number(char *in, char *root)
|
||||
static char *reverse_number(const char *in, const char *root)
|
||||
{
|
||||
switch_size_t len;
|
||||
char *out = NULL;
|
||||
char *y, *z;
|
||||
const char *y;
|
||||
char *z;
|
||||
|
||||
if (!(in && root)) {
|
||||
return NULL;
|
||||
@@ -198,59 +230,33 @@ static char *reverse_number(char *in, char *root)
|
||||
return out;
|
||||
}
|
||||
|
||||
static void dnserror(enum_query_t *q, int errnum)
|
||||
{
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unable to lookup %s record for %s: %s\n",
|
||||
dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
|
||||
q->errs++;
|
||||
}
|
||||
|
||||
static void add_result(enum_query_t *q, int order, int preference, char *service, char *route, int supported)
|
||||
static void add_result(enum_record_t **results, int order, int preference, char *service, char *route, int supported)
|
||||
{
|
||||
enum_record_t *new_result, *rp, *prev = NULL;
|
||||
enum_record_t *new_result;
|
||||
|
||||
new_result = malloc(sizeof(*new_result));
|
||||
switch_assert(new_result);
|
||||
memset(new_result, 0, sizeof(*new_result));
|
||||
|
||||
memset(new_result, 0, sizeof(*new_result));
|
||||
new_result->order = order;
|
||||
new_result->preference = preference;
|
||||
new_result->service = strdup(service);
|
||||
new_result->route = strdup(route);
|
||||
new_result->supported = supported;
|
||||
|
||||
|
||||
if (!q->results) {
|
||||
q->results = new_result;
|
||||
return;
|
||||
}
|
||||
|
||||
rp = q->results;
|
||||
|
||||
while (rp && strcasecmp(rp->service, new_result->service)) {
|
||||
prev = rp;
|
||||
rp = rp->next;
|
||||
}
|
||||
|
||||
while (rp && !strcasecmp(rp->service, new_result->service) && new_result->order > rp->order) {
|
||||
prev = rp;
|
||||
rp = rp->next;
|
||||
}
|
||||
|
||||
while (rp && !strcasecmp(rp->service, new_result->service) && new_result->preference > rp->preference) {
|
||||
prev = rp;
|
||||
rp = rp->next;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
new_result->next = rp;
|
||||
prev->next = new_result;
|
||||
if (!*results) {
|
||||
*results = new_result;
|
||||
(*results)->tail = new_result;
|
||||
} else {
|
||||
new_result->next = rp;
|
||||
q->results = new_result;
|
||||
(*results)->tail->next = new_result;
|
||||
(*results)->tail = new_result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void free_results(enum_record_t ** results)
|
||||
{
|
||||
enum_record_t *fp, *rp;
|
||||
@@ -265,201 +271,234 @@ static void free_results(enum_record_t ** results)
|
||||
*results = NULL;
|
||||
}
|
||||
|
||||
static void parse_rr(const struct dns_parse *p, enum_query_t *q, struct dns_rr *rr)
|
||||
|
||||
static ldns_rdf *ldns_rdf_new_addr_frm_str(const char *str)
|
||||
{
|
||||
const unsigned char *pkt = p->dnsp_pkt;
|
||||
const unsigned char *end = p->dnsp_end;
|
||||
const unsigned char *dptr = rr->dnsrr_dptr;
|
||||
const unsigned char *dend = rr->dnsrr_dend;
|
||||
unsigned char *dn = rr->dnsrr_dn;
|
||||
const unsigned char *c;
|
||||
char flags;
|
||||
int order;
|
||||
int preference;
|
||||
ldns_rdf *a;
|
||||
|
||||
ldns_str2rdf_a(&a, str);
|
||||
|
||||
if (!a) {
|
||||
/* maybe ip6 */
|
||||
ldns_str2rdf_aaaa(&a, str);
|
||||
if (!a) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
#define strip_quotes(_s) if (*_s == '"') _s++; if (end_of(_s) == '"') end_of(_s) = '\0'
|
||||
|
||||
static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t **results)
|
||||
{
|
||||
char *str = ldns_rr2str(naptr);
|
||||
char *argv[11] = { 0 };
|
||||
int i, argc;
|
||||
char *pack[4] = { 0 };
|
||||
int packc;
|
||||
|
||||
char *p;
|
||||
int order = 10;
|
||||
int preference = 100;
|
||||
char *service = NULL;
|
||||
char *regex = NULL;
|
||||
char *replace = NULL;
|
||||
char *ptr;
|
||||
int argc = 0;
|
||||
char *argv[4] = { 0 };
|
||||
int n;
|
||||
char string_arg[3][256] = { {0} };
|
||||
char *packstr;
|
||||
|
||||
switch (rr->dnsrr_typ) {
|
||||
case DNS_T_NAPTR: /* prio weight port targetDN */
|
||||
c = dptr;
|
||||
c += 4; /* order, pref */
|
||||
|
||||
for (n = 0; n < 3; ++n) {
|
||||
if (c >= dend) {
|
||||
goto xperr;
|
||||
} else {
|
||||
c += *c + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) {
|
||||
goto xperr;
|
||||
}
|
||||
|
||||
c = dptr;
|
||||
order = dns_get16(c + 0);
|
||||
preference = dns_get16(c + 2);
|
||||
flags = (char) dns_get16(c + 4);
|
||||
c += 4;
|
||||
|
||||
for (n = 0; n < 3; n++) {
|
||||
uint32_t len = *c++, cpylen = len;
|
||||
switch_assert(string_arg[n]);
|
||||
if (len > sizeof(string_arg[n]) - 1) {
|
||||
cpylen = sizeof(string_arg[n]) - 1;
|
||||
}
|
||||
strncpy(string_arg[n], (char *) c, cpylen);
|
||||
*(string_arg[n] + len) = '\0';
|
||||
c += len;
|
||||
}
|
||||
|
||||
service = string_arg[1];
|
||||
|
||||
if ((argc = switch_separate_string(string_arg[2], '!', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
regex = argv[1];
|
||||
replace = argv[2];
|
||||
} else {
|
||||
goto xperr;
|
||||
}
|
||||
|
||||
for (ptr = replace; ptr && *ptr; ptr++) {
|
||||
if (*ptr == '\\') {
|
||||
*ptr = '$';
|
||||
}
|
||||
}
|
||||
|
||||
if (flags && service && regex && replace) {
|
||||
switch_regex_t *re = NULL;
|
||||
int proceed = 0, ovector[30];
|
||||
char substituted[1024] = "";
|
||||
char rbuf[1024] = "";
|
||||
char *uri;
|
||||
enum_route_t *route;
|
||||
int supported = 0;
|
||||
switch_regex_safe_free(re);
|
||||
|
||||
if ((proceed = switch_regex_perform(q->number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
if (strchr(regex, '(')) {
|
||||
switch_perform_substitution(re, proceed, replace, q->number, substituted, sizeof(substituted), ovector);
|
||||
uri = substituted;
|
||||
} else {
|
||||
uri = replace;
|
||||
}
|
||||
|
||||
switch_mutex_lock(MUTEX);
|
||||
for (route = globals.route_order; route; route = route->next) {
|
||||
if (strcasecmp(service, route->service)) {
|
||||
continue;
|
||||
}
|
||||
switch_regex_safe_free(re);
|
||||
if ((proceed = switch_regex_perform(uri, route->regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
if (strchr(route->regex, '(')) {
|
||||
switch_perform_substitution(re, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
|
||||
uri = rbuf;
|
||||
} else {
|
||||
uri = route->replace;
|
||||
}
|
||||
supported++;
|
||||
add_result(q, order, preference, service, uri, supported);
|
||||
}
|
||||
}
|
||||
|
||||
if (!supported) {
|
||||
add_result(q, order, preference, service, uri, 0);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(MUTEX);
|
||||
|
||||
|
||||
switch_regex_safe_free(re);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
char *regex, *replace;
|
||||
|
||||
if (zstr(str)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
for (p = str; p && *p; p++) {
|
||||
if (*p == '\t') *p = ' ';
|
||||
if (*p == ' ' && *(p+1) == '.') *p = '\0';
|
||||
}
|
||||
|
||||
xperr:
|
||||
|
||||
argc = switch_split(str, ' ', argv);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (i > 0) {
|
||||
strip_quotes(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
service = argv[7];
|
||||
packstr = argv[8];
|
||||
|
||||
if (zstr(service) || zstr(packstr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!zstr(argv[4])) {
|
||||
order = atoi(argv[4]);
|
||||
}
|
||||
|
||||
if (!zstr(argv[5])) {
|
||||
preference = atoi(argv[5]);
|
||||
}
|
||||
|
||||
|
||||
if ((packc = switch_split(packstr, '!', pack))) {
|
||||
regex = pack[1];
|
||||
replace = pack[2];
|
||||
} else {
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (p = replace; p && *p; p++) {
|
||||
if (*p == '\\') {
|
||||
*p = '$';
|
||||
}
|
||||
}
|
||||
|
||||
if (service && regex && replace) {
|
||||
switch_regex_t *re = NULL, *re2 = NULL;
|
||||
int proceed = 0, ovector[30];
|
||||
char substituted[1024] = "";
|
||||
char rbuf[1024] = "";
|
||||
char *uri;
|
||||
enum_route_t *route;
|
||||
int supported = 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);
|
||||
uri = substituted;
|
||||
} else {
|
||||
uri = replace;
|
||||
}
|
||||
|
||||
switch_mutex_lock(MUTEX);
|
||||
for (route = globals.route_order; route; route = route->next) {
|
||||
if (strcasecmp(service, route->service)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((proceed = switch_regex_perform(uri, route->regex, &re2, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
if (strchr(route->regex, '(')) {
|
||||
switch_perform_substitution(re2, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
|
||||
uri = rbuf;
|
||||
} else {
|
||||
uri = route->replace;
|
||||
}
|
||||
supported++;
|
||||
add_result(results, order, preference, service, uri, supported);
|
||||
}
|
||||
switch_regex_safe_free(re2);
|
||||
}
|
||||
switch_mutex_unlock(MUTEX);
|
||||
|
||||
if (!supported) {
|
||||
add_result(results, order, preference, service, uri, 0);
|
||||
}
|
||||
|
||||
switch_regex_safe_free(re);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
switch_safe_free(str);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void dnscb(struct dns_ctx *ctx, void *result, void *data)
|
||||
|
||||
switch_status_t ldns_lookup(const char *number, const char *root, const char *server_name, enum_record_t **results)
|
||||
{
|
||||
int r = dns_status(ctx);
|
||||
enum_query_t *q = data;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
unsigned nrr;
|
||||
unsigned char dn[DNS_MAXDN];
|
||||
const unsigned char *pkt, *cur, *end, *qdn;
|
||||
if (!result) {
|
||||
dnserror(q, r);
|
||||
return;
|
||||
ldns_resolver *res = NULL;
|
||||
ldns_rdf *domain = NULL;
|
||||
ldns_pkt *p = NULL;
|
||||
ldns_rr_list *naptr = NULL;
|
||||
ldns_status s = LDNS_STATUS_ERR;
|
||||
ldns_rdf *serv_rdf;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
char *name = NULL;
|
||||
struct timeval to = { 0, 0};
|
||||
|
||||
if (!(name = reverse_number(number, root))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
|
||||
goto end;
|
||||
}
|
||||
pkt = result;
|
||||
end = pkt + r;
|
||||
cur = dns_payload(pkt);
|
||||
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
|
||||
dns_initparse(&p, NULL, pkt, cur, end);
|
||||
p.dnsp_qcls = 0;
|
||||
p.dnsp_qtyp = 0;
|
||||
qdn = dn;
|
||||
nrr = 0;
|
||||
while ((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
if (!dns_dnequal(qdn, rr.dnsrr_dn))
|
||||
continue;
|
||||
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
|
||||
++nrr;
|
||||
else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
|
||||
if (dns_getdn(pkt, &rr.dnsrr_dptr, end, p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || rr.dnsrr_dptr != rr.dnsrr_dend) {
|
||||
r = DNS_E_PROTOCOL;
|
||||
break;
|
||||
} else {
|
||||
qdn = p.dnsp_dnbuf;
|
||||
|
||||
if (!(domain = ldns_dname_new_frm_str(name))) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!zstr(server_name)) {
|
||||
res = ldns_resolver_new();
|
||||
switch_assert(res);
|
||||
|
||||
if ((serv_rdf = ldns_rdf_new_addr_frm_str(server_name))) {
|
||||
s = ldns_resolver_push_nameserver(res, serv_rdf);
|
||||
ldns_rdf_deep_free(serv_rdf);
|
||||
}
|
||||
} else {
|
||||
/* create a new resolver from /etc/resolv.conf */
|
||||
s = ldns_resolver_new_frm_file(&res, NULL);
|
||||
}
|
||||
|
||||
if (s != LDNS_STATUS_OK) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
to.tv_sec = globals.timeout / 1000;
|
||||
to.tv_usec = (globals.timeout % 1000) * 1000;
|
||||
|
||||
ldns_resolver_set_timeout(res, to);
|
||||
ldns_resolver_set_retry(res, (uint8_t)globals.retries);
|
||||
ldns_resolver_set_random(res, globals.random);
|
||||
|
||||
if ((p = ldns_resolver_query(res,
|
||||
domain,
|
||||
LDNS_RR_TYPE_NAPTR,
|
||||
LDNS_RR_CLASS_IN,
|
||||
LDNS_RD))) {
|
||||
/* retrieve the NAPTR records from the answer section of that
|
||||
* packet
|
||||
*/
|
||||
|
||||
if ((naptr = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NAPTR, LDNS_SECTION_ANSWER))) {
|
||||
size_t i;
|
||||
|
||||
ldns_rr_list_sort(naptr);
|
||||
|
||||
for (i = 0; i < ldns_rr_list_rr_count(naptr); i++) {
|
||||
parse_naptr(ldns_rr_list_rr(naptr, i), number, results);
|
||||
}
|
||||
|
||||
//ldns_rr_list_print(stdout, naptr);
|
||||
ldns_rr_list_deep_free(naptr);
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (!r && !nrr)
|
||||
r = DNS_E_NODATA;
|
||||
if (r < 0) {
|
||||
dnserror(q, r);
|
||||
free(result);
|
||||
return;
|
||||
|
||||
end:
|
||||
|
||||
switch_safe_free(name);
|
||||
|
||||
if (domain) {
|
||||
ldns_rdf_deep_free(domain);
|
||||
}
|
||||
|
||||
dns_rewind(&p, NULL);
|
||||
p.dnsp_qtyp = q->qtyp;
|
||||
p.dnsp_qcls = qcls;
|
||||
while (dns_nextrr(&p, &rr)) {
|
||||
parse_rr(&p, q, &rr);
|
||||
if (p) {
|
||||
ldns_pkt_free(p);
|
||||
}
|
||||
|
||||
free(result);
|
||||
if (res) {
|
||||
ldns_resolver_deep_free(res);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static switch_status_t enum_lookup(char *root, char *in, enum_record_t ** results)
|
||||
static switch_status_t enum_lookup(char *root, char *in, enum_record_t **results)
|
||||
{
|
||||
switch_status_t sstatus = SWITCH_STATUS_SUCCESS;
|
||||
char *name = NULL;
|
||||
enum_query_t query = { 0 };
|
||||
enum dns_type l_qtyp = DNS_T_NAPTR;
|
||||
int i = 0, abs = 0, j = 0;
|
||||
dns_socket fd = (dns_socket) - 1;
|
||||
fd_set fds;
|
||||
struct timeval tv = { 0 };
|
||||
time_t now = 0;
|
||||
struct dns_ctx *nctx = NULL;
|
||||
char *num, *mnum = NULL, *mroot = NULL, *p;
|
||||
char *mnum = NULL, *mroot = NULL, *p;
|
||||
char *server = NULL;
|
||||
|
||||
*results = NULL;
|
||||
|
||||
@@ -475,87 +514,13 @@ static switch_status_t enum_lookup(char *root, char *in, enum_record_t ** result
|
||||
root = globals.root;
|
||||
}
|
||||
|
||||
num = mnum;
|
||||
if (!(name = reverse_number(num, root))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
|
||||
sstatus = SWITCH_STATUS_FALSE;
|
||||
goto done;
|
||||
|
||||
if (!(server = switch_core_get_variable("enum-server"))) {
|
||||
server = globals.server;
|
||||
}
|
||||
|
||||
if (!(nctx = dns_new(NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Memory Error!\n");
|
||||
sstatus = SWITCH_STATUS_MEMERR;
|
||||
goto done;
|
||||
}
|
||||
ldns_lookup(mnum, root, server, results);
|
||||
|
||||
fd = dns_open(nctx);
|
||||
|
||||
if (fd < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FD Error!\n");
|
||||
sstatus = SWITCH_STATUS_FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
dns_ptodn(name, (unsigned int) strlen(name), query.dn, sizeof(query.dn), &abs);
|
||||
query.name = name;
|
||||
query.number = num;
|
||||
query.qtyp = l_qtyp;
|
||||
|
||||
if (abs) {
|
||||
abs = DNS_NOSRCH;
|
||||
}
|
||||
|
||||
if (!dns_submit_dn(nctx, query.dn, qcls, l_qtyp, abs, 0, dnscb, &query)) {
|
||||
dnserror(&query, dns_status(nctx));
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
now = 0;
|
||||
|
||||
while ((i = dns_timeouts(nctx, 1, now)) > 0) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4389 4127)
|
||||
#endif
|
||||
FD_SET(fd, &fds);
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
j += i;
|
||||
|
||||
if (j > globals.timeout || query.results || query.errs) {
|
||||
break;
|
||||
}
|
||||
|
||||
tv.tv_sec = i;
|
||||
tv.tv_usec = 0;
|
||||
i = select((int) (fd + 1), &fds, 0, 0, &tv);
|
||||
now = switch_epoch_time_now(NULL);
|
||||
if (i > 0) {
|
||||
dns_ioevent(nctx, now);
|
||||
}
|
||||
}
|
||||
|
||||
if (!query.results) {
|
||||
sstatus = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
*results = query.results;
|
||||
query.results = NULL;
|
||||
|
||||
done:
|
||||
|
||||
if (fd > -1) {
|
||||
closesocket(fd);
|
||||
fd = (dns_socket) - 1;
|
||||
}
|
||||
|
||||
if (nctx) {
|
||||
dns_free(nctx);
|
||||
}
|
||||
|
||||
switch_safe_free(name);
|
||||
switch_safe_free(mnum);
|
||||
switch_safe_free(mroot);
|
||||
|
||||
@@ -623,15 +588,17 @@ SWITCH_STANDARD_APP(enum_app_function)
|
||||
dest = argv[0];
|
||||
root = argv[1];
|
||||
if (enum_lookup(root, dest, &results) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_header_t *hi;
|
||||
if ((hi = switch_channel_variable_first(channel))) {
|
||||
for (; hi; hi = hi->next) {
|
||||
switch_event_t *vars;
|
||||
|
||||
if (switch_channel_get_variables(channel, &vars) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_header_t *hi;
|
||||
for (hi = vars->headers; hi; hi = hi->next) {
|
||||
char *vvar = hi->name;
|
||||
if (vvar && !strncmp(vvar, "enum_", 5)) {
|
||||
switch_channel_set_variable(channel, (char *) vvar, NULL);
|
||||
}
|
||||
}
|
||||
switch_channel_variable_last(channel);
|
||||
switch_event_destroy(&vars);
|
||||
}
|
||||
|
||||
for (rp = results; rp; rp = rp->next) {
|
||||
@@ -823,9 +790,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_enum_load)
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
if (dns_init(0) < 0) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
do_load();
|
||||
@@ -852,8 +816,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_enum_shutdown)
|
||||
}
|
||||
|
||||
switch_safe_free(globals.root);
|
||||
switch_safe_free(globals.server);
|
||||
switch_safe_free(globals.isn_root);
|
||||
|
||||
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ SWITCH_STANDARD_APP(bcast_function)
|
||||
switch_port_t rtp_port;
|
||||
char guess_ip[25];
|
||||
ls_how_t ready = SEND_TYPE_UNKNOWN;
|
||||
int argc;
|
||||
//int argc;
|
||||
char *mydata, *argv[5];
|
||||
char *mcast_ip = "224.168.168.168";
|
||||
switch_port_t mcast_port = 34567;
|
||||
@@ -87,7 +87,7 @@ SWITCH_STANDARD_APP(bcast_function)
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
assert(mydata != NULL);
|
||||
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "esf_multicast_ip"))) {
|
||||
mcast_ip = switch_core_session_strdup(session, var);
|
||||
|
||||
@@ -1167,7 +1167,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
switch_call_cause_t cancel_cause = 0;
|
||||
char *uuid_list = NULL;
|
||||
int connected = 0, total = 0;
|
||||
int total = 0;
|
||||
const char *codec;
|
||||
struct call_helper *rows[MAX_ROWS] = { 0 };
|
||||
int rowcount = 0;
|
||||
@@ -1238,7 +1238,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
struct call_helper *h = cbh->rows[i];
|
||||
char *parsed = NULL;
|
||||
|
||||
switch_event_create_brackets(h->originate_string, '{', '}', ',', &ovars, &parsed);
|
||||
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;
|
||||
@@ -1417,8 +1417,6 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
goto end;
|
||||
}
|
||||
|
||||
connected = 1;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
@@ -1513,7 +1511,6 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_event_t *event = NULL;
|
||||
char *sql = NULL;
|
||||
int connected = 0;
|
||||
|
||||
if (!globals.running) return NULL;
|
||||
|
||||
@@ -1592,8 +1589,6 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
goto end;
|
||||
}
|
||||
|
||||
connected = 1;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
@@ -3870,7 +3865,7 @@ static void extract_fifo_outbound_uuid(char *string, char *uuid, switch_size_t l
|
||||
|
||||
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
|
||||
switch_event_create_brackets(string, '{', '}', ',', &ovars, &parsed);
|
||||
switch_event_create_brackets(string, '{', '}', ',', &ovars, &parsed, SWITCH_TRUE);
|
||||
|
||||
if ((fifo_outbound_uuid = switch_event_get_header(ovars, "fifo_outbound_uuid"))) {
|
||||
switch_snprintf(uuid, len, "%s", fifo_outbound_uuid);
|
||||
@@ -3890,7 +3885,7 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
fifo_node_t *node;
|
||||
|
||||
gethostname(globals.hostname, sizeof(globals.hostname));
|
||||
strncpy(globals.hostname, switch_core_get_switchname(), sizeof(globals.hostname));
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
|
||||
|
||||
@@ -531,16 +531,33 @@ SWITCH_STANDARD_API(hash_api_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define HASH_DUMP_SYNTAX "all|limit|db"
|
||||
#define HASH_DUMP_SYNTAX "all|limit|db [<realm>]"
|
||||
SWITCH_STANDARD_API(hash_dump_function)
|
||||
{
|
||||
int mode;
|
||||
switch_hash_index_t *hi;
|
||||
int argc = 0;
|
||||
char *argv[4] = { 0 };
|
||||
char *mydata = NULL;
|
||||
int realm = 0;
|
||||
char *realmvalue = NULL;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
if (!zstr(cmd)) {
|
||||
mydata = strdup(cmd);
|
||||
switch_assert(mydata);
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
} else {
|
||||
realmvalue = "test";
|
||||
realm = 0;
|
||||
stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"\n");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = strdup(argv[0]);
|
||||
if (argc == 2) {
|
||||
realm = 1;
|
||||
realmvalue = switch_mprintf("%s_", argv[1]);
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "all")) {
|
||||
mode = 3;
|
||||
@@ -553,7 +570,6 @@ SWITCH_STANDARD_API(hash_dump_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
if (mode & 1) {
|
||||
switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
|
||||
for (hi = switch_hash_first(NULL, globals.limit_hash); hi; hi = switch_hash_next(hi)) {
|
||||
@@ -577,8 +593,13 @@ SWITCH_STANDARD_API(hash_dump_function)
|
||||
const void *key;
|
||||
switch_ssize_t keylen;
|
||||
switch_hash_this(hi, &key, &keylen, &val);
|
||||
|
||||
stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
|
||||
if (realm) {
|
||||
if (strstr(key, realmvalue)) {
|
||||
stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
|
||||
}
|
||||
}
|
||||
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
|
||||
}
|
||||
@@ -590,7 +611,7 @@ SWITCH_STANDARD_API(hash_dump_function)
|
||||
#define HASH_REMOTE_SYNTAX "list|kill [name]|rescan"
|
||||
SWITCH_STANDARD_API(hash_remote_function)
|
||||
{
|
||||
int argc;
|
||||
//int argc;
|
||||
char *argv[10];
|
||||
char *dup = NULL;
|
||||
|
||||
@@ -601,7 +622,7 @@ SWITCH_STANDARD_API(hash_remote_function)
|
||||
|
||||
dup = strdup(cmd);
|
||||
|
||||
argc = switch_split(dup, ' ', argv);
|
||||
switch_split(dup, ' ', argv);
|
||||
if (argv[0] && !strcmp(argv[0], "list")) {
|
||||
switch_hash_index_t *hi;
|
||||
stream->write_function(stream, "Remote connections:\nName\t\t\tState\n");
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
BASE=../../../..
|
||||
|
||||
LOCAL_OBJS += load.o
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* load.c
|
||||
|
||||
Free software by Richard W.E. Furse. Do with as you will. No
|
||||
warranty. */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "ladspa.h"
|
||||
#include "utils.h"
|
||||
#include "inttypes.h"
|
||||
#include "switch.h"
|
||||
/*****************************************************************************/
|
||||
|
||||
/* This function provides a wrapping of dlopen(). When the filename is
|
||||
not an absolute path (i.e. does not begin with / character), this
|
||||
routine will search the LADSPA_PATH for the file. */
|
||||
static void *dlopenLADSPA(const char *pcFilename, int iFlag)
|
||||
{
|
||||
|
||||
char *pcBuffer;
|
||||
const char *pcEnd;
|
||||
const char *pcLADSPAPath;
|
||||
const char *pcStart;
|
||||
int iEndsInSO;
|
||||
int iNeedSlash;
|
||||
size_t iFilenameLength;
|
||||
void *pvResult;
|
||||
|
||||
iFilenameLength = strlen(pcFilename);
|
||||
pvResult = NULL;
|
||||
|
||||
if (pcFilename[0] == '/') {
|
||||
|
||||
/* The filename is absolute. Assume the user knows what he/she is
|
||||
doing and simply dlopen() it. */
|
||||
|
||||
pvResult = dlopen(pcFilename, iFlag);
|
||||
if (pvResult != NULL)
|
||||
return pvResult;
|
||||
|
||||
} else {
|
||||
|
||||
/* If the filename is not absolute then we wish to check along the
|
||||
LADSPA_PATH path to see if we can find the file there. We do
|
||||
NOT call dlopen() directly as this would find plugins on the
|
||||
LD_LIBRARY_PATH, whereas the LADSPA_PATH is the correct place
|
||||
to search. */
|
||||
|
||||
pcLADSPAPath = getenv("LADSPA_PATH");
|
||||
|
||||
if (pcLADSPAPath) {
|
||||
|
||||
pcStart = pcLADSPAPath;
|
||||
while (*pcStart != '\0') {
|
||||
pcEnd = pcStart;
|
||||
while (*pcEnd != ':' && *pcEnd != '\0')
|
||||
pcEnd++;
|
||||
|
||||
pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart));
|
||||
if (pcEnd > pcStart)
|
||||
strncpy(pcBuffer, pcStart, pcEnd - pcStart);
|
||||
iNeedSlash = 0;
|
||||
if (pcEnd > pcStart)
|
||||
if (*(pcEnd - 1) != '/') {
|
||||
iNeedSlash = 1;
|
||||
pcBuffer[pcEnd - pcStart] = '/';
|
||||
}
|
||||
strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename);
|
||||
|
||||
pvResult = dlopen(pcBuffer, iFlag);
|
||||
|
||||
free(pcBuffer);
|
||||
if (pvResult != NULL)
|
||||
return pvResult;
|
||||
|
||||
pcStart = pcEnd;
|
||||
if (*pcStart == ':')
|
||||
pcStart++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* As a last ditch effort, check if filename does not end with
|
||||
".so". In this case, add this suffix and recurse. */
|
||||
iEndsInSO = 0;
|
||||
if (iFilenameLength > 3)
|
||||
iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0);
|
||||
if (!iEndsInSO) {
|
||||
pcBuffer = malloc(iFilenameLength + 4);
|
||||
strcpy(pcBuffer, pcFilename);
|
||||
strcat(pcBuffer, ".so");
|
||||
pvResult = dlopenLADSPA(pcBuffer, iFlag);
|
||||
free(pcBuffer);
|
||||
}
|
||||
|
||||
if (pvResult != NULL)
|
||||
return pvResult;
|
||||
|
||||
/* If nothing has worked, then at least we can make sure we set the
|
||||
correct error message - and this should correspond to a call to
|
||||
dlopen() with the actual filename requested. The dlopen() manual
|
||||
page does not specify whether the first or last error message
|
||||
will be kept when multiple calls are made to dlopen(). We've
|
||||
covered the former case - now we can handle the latter by calling
|
||||
dlopen() again here. */
|
||||
return dlopen(pcFilename, iFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void *loadLADSPAPluginLibrary(const char *pcPluginFilename)
|
||||
{
|
||||
|
||||
void *pvPluginHandle;
|
||||
|
||||
pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW);
|
||||
if (!pvPluginHandle) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load plugin \"%s\": %s\n", pcPluginFilename, dlerror());
|
||||
}
|
||||
|
||||
return pvPluginHandle;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void unloadLADSPAPluginLibrary(void *pvLADSPAPluginLibrary)
|
||||
{
|
||||
dlclose(pvLADSPAPluginLibrary);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const LADSPA_Descriptor *findLADSPAPluginDescriptor(void *pvLADSPAPluginLibrary, const char *pcPluginLibraryFilename, const char *pcPluginLabel)
|
||||
{
|
||||
|
||||
const LADSPA_Descriptor *psDescriptor;
|
||||
LADSPA_Descriptor_Function pfDescriptorFunction;
|
||||
unsigned long lPluginIndex;
|
||||
|
||||
dlerror();
|
||||
pfDescriptorFunction = (LADSPA_Descriptor_Function) (intptr_t)dlsym(pvLADSPAPluginLibrary, "ladspa_descriptor");
|
||||
if (!pfDescriptorFunction) {
|
||||
const char *pcError = dlerror();
|
||||
if (pcError) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Unable to find ladspa_descriptor() function in plugin "
|
||||
"library file \"%s\": %s.\n" "Are you sure this is a LADSPA plugin file?\n", pcPluginLibraryFilename, pcError);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (lPluginIndex = 0;; lPluginIndex++) {
|
||||
psDescriptor = pfDescriptorFunction(lPluginIndex);
|
||||
if (psDescriptor == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Unable to find label \"%s\" in plugin library file \"%s\".\n", pcPluginLabel, pcPluginLibraryFilename);
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(psDescriptor->Label, pcPluginLabel) == 0)
|
||||
return psDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* 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_ladspa.c -- LADSPA
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include "ladspa.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_ladspa_runtime);
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_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_ladspa, mod_ladspa_load, mod_ladspa_shutdown, NULL);
|
||||
|
||||
#define MAX_INDEX 256
|
||||
|
||||
typedef struct {
|
||||
switch_core_session_t *session;
|
||||
char *plugin_name;
|
||||
char *label_name;
|
||||
void *library_handle;
|
||||
const LADSPA_Descriptor *ldesc;
|
||||
LADSPA_Handle handle;
|
||||
LADSPA_Data config[MAX_INDEX];
|
||||
int num_idx;
|
||||
char *str_config[MAX_INDEX];
|
||||
int str_idx;
|
||||
uint8_t has_config[MAX_INDEX];
|
||||
int skip;
|
||||
LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
LADSPA_Data file_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
LADSPA_Data out_ports[MAX_INDEX];
|
||||
switch_file_handle_t fh;
|
||||
} switch_ladspa_t;
|
||||
|
||||
|
||||
|
||||
int check_range(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data val)
|
||||
{
|
||||
if (ldesc->PortRangeHints[i].LowerBound && ldesc->PortRangeHints[i].UpperBound &&
|
||||
(val < ldesc->PortRangeHints[i].LowerBound || val > ldesc->PortRangeHints[i].UpperBound)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Param %f out of bounds %f-%f\n",
|
||||
val, ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int find_default(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data *ptr)
|
||||
|
||||
{
|
||||
LADSPA_Data dftval = 0;
|
||||
int fail = 0;
|
||||
|
||||
LADSPA_PortRangeHintDescriptor port_hint = ldesc->PortRangeHints[i].HintDescriptor;
|
||||
|
||||
switch (port_hint & LADSPA_HINT_DEFAULT_MASK) {
|
||||
case LADSPA_HINT_DEFAULT_NONE:
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_MINIMUM:
|
||||
dftval = ldesc->PortRangeHints[i].LowerBound;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_LOW:
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
|
||||
dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
|
||||
* 0.75 + log(ldesc->PortRangeHints[i].UpperBound)
|
||||
* 0.25);
|
||||
} else {
|
||||
dftval = (ldesc->PortRangeHints[i].LowerBound * 0.75 + ldesc->PortRangeHints[i].UpperBound * 0.25);
|
||||
}
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_MIDDLE:
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
|
||||
dftval = sqrt(ldesc->PortRangeHints[i].LowerBound * ldesc->PortRangeHints[i].UpperBound);
|
||||
} else {
|
||||
dftval = 0.5 * (ldesc->PortRangeHints[i].LowerBound + ldesc->PortRangeHints[i].UpperBound);
|
||||
}
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_HIGH:
|
||||
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
|
||||
dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
|
||||
* 0.25 + log(ldesc->PortRangeHints[i].UpperBound)
|
||||
* 0.75);
|
||||
} else {
|
||||
dftval = (ldesc->PortRangeHints[i].LowerBound * 0.25 + ldesc->PortRangeHints[i].UpperBound * 0.75);
|
||||
}
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_MAXIMUM:
|
||||
dftval = ldesc->PortRangeHints[i].UpperBound;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_0:
|
||||
dftval = 0;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_1:
|
||||
dftval = 1;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_100:
|
||||
dftval = 100;
|
||||
break;
|
||||
case LADSPA_HINT_DEFAULT_440:
|
||||
dftval = 440;
|
||||
break;
|
||||
default:
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fail) {
|
||||
*ptr = dftval;
|
||||
}
|
||||
|
||||
return !fail;
|
||||
}
|
||||
|
||||
static void dump_info(const LADSPA_Descriptor *ldesc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Name: \"%s\"\n", ldesc->Name);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Label: \"%s\"\n", ldesc->Label);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Unique ID: %lu\n", ldesc->UniqueID);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Maker: \"%s\"\n", ldesc->Maker);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Copyright: \"%s\"\n", ldesc->Copyright);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Must Run Real-Time: ");
|
||||
if (LADSPA_IS_REALTIME(ldesc->Properties))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has activate() Function: ");
|
||||
if (ldesc->activate != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has deactivate() Function: ");
|
||||
if (ldesc->deactivate != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has run_adding() Function: ");
|
||||
if (ldesc->run_adding != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
|
||||
|
||||
if (ldesc->instantiate == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO INSTANTIATE FUNCTION.\n");
|
||||
if (ldesc->connect_port == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CONNECT_PORT FUNCTION.\n");
|
||||
if (ldesc->run == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO RUN FUNCTION.\n");
|
||||
if (ldesc->run_adding != NULL && ldesc->set_run_adding_gain == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS RUN_ADDING FUNCTION BUT " "NOT SET_RUN_ADDING_GAIN.\n");
|
||||
if (ldesc->run_adding == NULL && ldesc->set_run_adding_gain != NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS SET_RUN_ADDING_GAIN FUNCTION BUT " "NOT RUN_ADDING.\n");
|
||||
if (ldesc->cleanup == NULL)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CLEANUP FUNCTION.\n");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Environment: ");
|
||||
if (LADSPA_IS_HARD_RT_CAPABLE(ldesc->Properties))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal or Hard Real-Time\n");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal\n");
|
||||
|
||||
if (LADSPA_IS_INPLACE_BROKEN(ldesc->Properties))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "This plugin cannot use in-place processing. " "It will not work with all hosts.\n");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Ports:");
|
||||
|
||||
if (ldesc->PortCount == 0)
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\tERROR: PLUGIN HAS NO PORTS.\n");
|
||||
|
||||
for (i = 0; i < ldesc->PortCount; i++) {
|
||||
LADSPA_Data dft = 0.0f;
|
||||
int found = 0;
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
|
||||
found = find_default(ldesc, i, &dft);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n \"%s\" ", ldesc->PortNames[i]);
|
||||
|
||||
if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i])
|
||||
&& LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: INPUT AND OUTPUT");
|
||||
else if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "input");
|
||||
else if (LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "output");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: NEITHER INPUT NOR OUTPUT");
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])
|
||||
&& LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: CONTROL AND AUDIO");
|
||||
else if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", control");
|
||||
else if (LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", audio");
|
||||
else
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: NEITHER CONTROL NOR AUDIO");
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
|
||||
if (found) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: %f\n",
|
||||
ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound, dft);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: none.\n",
|
||||
ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static switch_bool_t ladspa_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
switch_ladspa_t *pvt = (switch_ladspa_t *) user_data;
|
||||
//switch_frame_t *frame = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
|
||||
|
||||
switch (type) {
|
||||
case SWITCH_ABC_TYPE_INIT:
|
||||
{
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
LADSPA_PortDescriptor port_desc;
|
||||
int i = 0, j = 0, k = 0, str_idx = 0;
|
||||
|
||||
switch_core_session_get_read_impl(pvt->session, &read_impl);
|
||||
|
||||
if (!(pvt->library_handle = loadLADSPAPluginLibrary(pvt->plugin_name))) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
if (!(pvt->ldesc = findLADSPAPluginDescriptor(pvt->library_handle, pvt->plugin_name, pvt->label_name))) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
|
||||
pvt->handle = pvt->ldesc->instantiate(pvt->ldesc, read_impl.actual_samples_per_second);
|
||||
|
||||
dump_info(pvt->ldesc);
|
||||
|
||||
|
||||
for (i = 0; i < pvt->ldesc->PortCount; i++) {
|
||||
port_desc = pvt->ldesc->PortDescriptors[i];
|
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(port_desc) && LADSPA_IS_PORT_INPUT(port_desc)) {
|
||||
LADSPA_Data dft = 0.0f;
|
||||
int found = find_default(pvt->ldesc, i, &dft);
|
||||
|
||||
if (found && !pvt->has_config[j]) {
|
||||
pvt->config[j] = dft;
|
||||
pvt->has_config[j] = 1;
|
||||
}
|
||||
|
||||
if (pvt->has_config[j]) {
|
||||
if (!check_range(pvt->ldesc, i, pvt->config[j])) {
|
||||
pvt->config[j] = dft;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_WARNING, "FALLING TO DEFAULT PARAM %d [%s] (%f)\n",
|
||||
j+1,
|
||||
pvt->ldesc->PortNames[i],
|
||||
pvt->config[j]);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "ADDING PARAM %d [%s] (%f)\n",
|
||||
j+1,
|
||||
pvt->ldesc->PortNames[i],
|
||||
pvt->config[j]);
|
||||
pvt->ldesc->connect_port(pvt->handle, i, &pvt->config[j++]);
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
if (LADSPA_IS_PORT_INPUT(port_desc) && LADSPA_IS_PORT_AUDIO(port_desc)) {
|
||||
int mapped = 0;
|
||||
|
||||
if (pvt->str_idx && !zstr(pvt->str_config[str_idx])) {
|
||||
|
||||
if (!strcasecmp(pvt->str_config[str_idx], "none")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT NOTHING to port: %s\n",
|
||||
pvt->ldesc->PortNames[i]
|
||||
);
|
||||
mapped = 1;
|
||||
} else if (!strncasecmp(pvt->str_config[str_idx], "file:", 5)) {
|
||||
char *file = pvt->str_config[str_idx] + 5;
|
||||
|
||||
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session),
|
||||
SWITCH_LOG_ERROR, "CAN'T CONNECT FILE [%s] File already mapped\n", file);
|
||||
} else {
|
||||
if (switch_core_file_open(&pvt->fh,
|
||||
file,
|
||||
read_impl.number_of_channels,
|
||||
read_impl.actual_samples_per_second,
|
||||
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT FILE [%s] to port: %s\n",
|
||||
file,
|
||||
pvt->ldesc->PortNames[i]
|
||||
);
|
||||
|
||||
pvt->ldesc->connect_port(pvt->handle, i, pvt->file_buf);
|
||||
mapped = 1;
|
||||
}
|
||||
}
|
||||
|
||||
str_idx++;
|
||||
}
|
||||
|
||||
if (!mapped) {
|
||||
pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT CHANNEL AUDIO to port: %s\n",
|
||||
pvt->ldesc->PortNames[i]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (LADSPA_IS_PORT_OUTPUT(port_desc)) {
|
||||
if (LADSPA_IS_PORT_AUDIO(port_desc)) {
|
||||
pvt->ldesc->connect_port(pvt->handle, i, pvt->out_buf);
|
||||
} else if (k < MAX_INDEX) {
|
||||
pvt->ldesc->connect_port(pvt->handle, i, &pvt->out_ports[k++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
{
|
||||
|
||||
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
|
||||
switch_core_file_close(&pvt->fh);
|
||||
}
|
||||
|
||||
if (pvt->handle && pvt->ldesc) {
|
||||
pvt->ldesc->cleanup(pvt->handle);
|
||||
}
|
||||
|
||||
if (pvt->library_handle) {
|
||||
unloadLADSPAPluginLibrary(pvt->library_handle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SWITCH_ABC_TYPE_WRITE_REPLACE:
|
||||
case SWITCH_ABC_TYPE_READ_REPLACE:
|
||||
{
|
||||
switch_frame_t *rframe;
|
||||
int16_t *slin, abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
|
||||
switch_size_t olen = 0;
|
||||
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
|
||||
rframe = switch_core_media_bug_get_read_replace_frame(bug);
|
||||
} else {
|
||||
rframe = switch_core_media_bug_get_write_replace_frame(bug);
|
||||
}
|
||||
|
||||
slin = rframe->data;
|
||||
|
||||
if (switch_channel_media_ready(channel)) {
|
||||
switch_short_to_float(slin, pvt->in_buf, rframe->samples);
|
||||
|
||||
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
|
||||
olen = rframe->samples;
|
||||
if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
char *file = switch_core_session_strdup(pvt->session, pvt->fh.file_path);
|
||||
switch_core_session_get_read_impl(pvt->session, &read_impl);
|
||||
|
||||
switch_core_file_close(&pvt->fh);
|
||||
|
||||
if (switch_core_file_open(&pvt->fh,
|
||||
file,
|
||||
read_impl.number_of_channels,
|
||||
read_impl.actual_samples_per_second,
|
||||
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
olen = rframe->samples;
|
||||
if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot READ file: %s\n", file);
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch_short_to_float(abuf, pvt->file_buf, olen);
|
||||
}
|
||||
|
||||
pvt->ldesc->run(pvt->handle, rframe->samples);
|
||||
|
||||
switch_float_to_short(pvt->out_buf, slin, rframe->samples);
|
||||
}
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
|
||||
switch_core_media_bug_set_read_replace_frame(bug, rframe);
|
||||
} else {
|
||||
switch_core_media_bug_set_write_replace_frame(bug, rframe);
|
||||
}
|
||||
|
||||
if (pvt->skip && !--pvt->skip) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_WRITE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
switch_status_t stop_ladspa_session(switch_core_session_t *session)
|
||||
{
|
||||
switch_media_bug_t *bug;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if ((bug = switch_channel_get_private(channel, "ladspa"))) {
|
||||
switch_channel_set_private(channel, "ladspa", NULL);
|
||||
switch_core_media_bug_remove(session, &bug);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_status_t ladspa_session(switch_core_session_t *session, const char *flags, const char *plugin_name, const char *label, const char *params)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_media_bug_t *bug;
|
||||
switch_status_t status;
|
||||
switch_ladspa_t *pvt = { 0 };
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
int i, bflags = SMBF_READ_REPLACE | SMBF_ANSWER_REQ;
|
||||
char *pstr;
|
||||
int argc;
|
||||
char *argv[50];
|
||||
char *dparams = NULL;
|
||||
|
||||
if (zstr(plugin_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s INVALID PLUGIN\n", switch_channel_get_name(channel));
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (zstr(flags)) {
|
||||
flags = "r";
|
||||
}
|
||||
|
||||
if (strchr(flags, 'w')) {
|
||||
bflags = SMBF_WRITE_REPLACE;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "FLAGS: %s PLUGIN: %s LABEL: %s PARAMS: %s\n",
|
||||
flags, plugin_name, label, params);
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
pvt = switch_core_session_alloc(session, sizeof(*pvt));
|
||||
|
||||
pvt->session = session;
|
||||
if (!zstr(label)) {
|
||||
pvt->label_name = switch_core_session_strdup(session, label);
|
||||
} else {
|
||||
char *p;
|
||||
pvt->label_name = switch_core_session_strdup(session, plugin_name);
|
||||
if ((p = strrchr(pvt->label_name, '.'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(plugin_name, ".so")) {
|
||||
pvt->plugin_name = switch_core_session_strdup(session, plugin_name);
|
||||
} else {
|
||||
pvt->plugin_name = switch_core_session_sprintf(session, "%s.so", plugin_name);
|
||||
}
|
||||
|
||||
dparams = switch_core_session_strdup(session, params);
|
||||
|
||||
argc = switch_split(dparams, ' ', argv);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (switch_is_number(argv[i])) {
|
||||
if (pvt->num_idx < MAX_INDEX) {
|
||||
pvt->config[pvt->num_idx] = atof(argv[i]);
|
||||
pvt->has_config[pvt->num_idx] = 1;
|
||||
pvt->num_idx++;
|
||||
}
|
||||
} else {
|
||||
if (pvt->str_idx < MAX_INDEX) {
|
||||
pvt->str_config[pvt->str_idx++] = switch_core_session_strdup(session, argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
pstr = switch_core_session_sprintf(session, "%s|%s|%s|%s", flags, plugin_name, label, params);
|
||||
|
||||
if ((status = switch_core_media_bug_add(session, "ladspa", pstr,
|
||||
ladspa_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_channel_set_private(channel, "ladspa", bug);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void ladspa_parse(switch_core_session_t *session, const char *data)
|
||||
{
|
||||
char *argv[5] = { 0 };
|
||||
char *lbuf;
|
||||
|
||||
if (data) {
|
||||
lbuf = strdup(data);
|
||||
switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
ladspa_session(session, argv[0], argv[1], argv[2], argv[3]);
|
||||
free(lbuf);
|
||||
}
|
||||
}
|
||||
|
||||
#define APP_SYNTAX "<flags>|<plugin>|<label>|<params>"
|
||||
SWITCH_STANDARD_APP(ladspa_run_function)
|
||||
{
|
||||
ladspa_parse(session, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define API_SYNTAX "<uuid>|<flags>|<plugin>|<label>|<params>"
|
||||
SWITCH_STANDARD_API(ladspa_api)
|
||||
{
|
||||
char *uuid = NULL;
|
||||
char *data;
|
||||
char *p;
|
||||
switch_core_session_t *ksession = NULL;
|
||||
|
||||
if (!cmd) goto err;
|
||||
|
||||
data = strdup(cmd);
|
||||
|
||||
if ((p = strchr(data, ' '))) {
|
||||
uuid = data;
|
||||
*p++ = '\0';
|
||||
|
||||
if ((ksession = switch_core_session_locate(uuid))) {
|
||||
ladspa_parse(ksession, p);
|
||||
switch_core_session_rwunlock(ksession);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR non-existant UUID\n");
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Usage %s\n", API_SYNTAX);
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
err:
|
||||
|
||||
stream->write_function(stream, "-ERR Operation Failed\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Macro expands to: switch_status_t mod_ladspa_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
|
||||
char *path = getenv("LADSPA_PATH");
|
||||
|
||||
if (zstr(path)) {
|
||||
if (switch_directory_exists("/usr/lib64/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
|
||||
putenv("LADSPA_PATH=/usr/lib64/ladspa/:/usr/local/lib/ladspa");
|
||||
} else if (switch_directory_exists("/usr/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
|
||||
putenv("LADSPA_PATH=/usr/lib/ladspa/:/usr/local/lib/ladspa");
|
||||
}
|
||||
}
|
||||
|
||||
/* 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, "ladspa_run", "ladspa_run", NULL, ladspa_run_function, APP_SYNTAX, SAF_NONE);
|
||||
SWITCH_ADD_API(api_interface, "uuid_ladspa", "ladspa", ladspa_api, API_SYNTAX);
|
||||
|
||||
switch_console_set_complete("add uuid_ladspa ::console::list_uuid");
|
||||
|
||||
|
||||
/* 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_ladspa_shutdown() */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown)
|
||||
{
|
||||
/* Cleanup dynamically allocated config settings */
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -0,0 +1,72 @@
|
||||
/* utils.h
|
||||
|
||||
Free software by Richard W.E. Furse. Do with as you will. No
|
||||
warranty. */
|
||||
|
||||
#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB
|
||||
#define LADSPA_SDK_LOAD_PLUGIN_LIB
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "ladspa.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Functions in load.c: */
|
||||
|
||||
/* This function call takes a plugin library filename, searches for
|
||||
the library along the LADSPA_PATH, loads it with dlopen() and
|
||||
returns a plugin handle for use with findPluginDescriptor() or
|
||||
unloadLADSPAPluginLibrary(). Errors are handled by writing a
|
||||
message to stderr and calling exit(1). It is alright (although
|
||||
inefficient) to call this more than once for the same file. */
|
||||
void * loadLADSPAPluginLibrary(const char * pcPluginFilename);
|
||||
|
||||
/* This function unloads a LADSPA plugin library. */
|
||||
void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary);
|
||||
|
||||
/* This function locates a LADSPA plugin within a plugin library
|
||||
loaded with loadLADSPAPluginLibrary(). Errors are handled by
|
||||
writing a message to stderr and calling exit(1). Note that the
|
||||
plugin library filename is only included to help provide
|
||||
informative error messages. */
|
||||
const LADSPA_Descriptor *
|
||||
findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary,
|
||||
const char * pcPluginLibraryFilename,
|
||||
const char * pcPluginLabel);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Functions in search.c: */
|
||||
|
||||
/* Callback function for use with LADSPAPluginSearch(). The callback
|
||||
function passes the filename (full path), a plugin handle (dlopen()
|
||||
style) and a LADSPA_DescriptorFunction (from which
|
||||
LADSPA_Descriptors can be acquired). */
|
||||
typedef void LADSPAPluginSearchCallbackFunction
|
||||
(const char * pcFullFilename,
|
||||
void * pvPluginHandle,
|
||||
LADSPA_Descriptor_Function fDescriptorFunction);
|
||||
|
||||
/* Search through the $(LADSPA_PATH) (or a default path) for any
|
||||
LADSPA plugin libraries. Each plugin library is tested using
|
||||
dlopen() and dlsym(,"ladspa_descriptor"). After loading each
|
||||
library, the callback function is called to process it. This
|
||||
function leaves items passed to the callback function open. */
|
||||
void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Function in default.c: */
|
||||
|
||||
/* Find the default value for a port. Return 0 if a default is found
|
||||
and -1 if not. */
|
||||
int getLADSPADefault(const LADSPA_PortRangeHint * psPortRangeHint,
|
||||
const unsigned long lSampleRate,
|
||||
LADSPA_Data * pfResult);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -133,6 +133,7 @@ struct callback_obj {
|
||||
profile_t *profile;
|
||||
switch_core_session_t *session;
|
||||
switch_event_t *event;
|
||||
float max_rate;
|
||||
};
|
||||
typedef struct callback_obj callback_t;
|
||||
|
||||
@@ -153,6 +154,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_lcr_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_lcr_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_lcr, mod_lcr_load, mod_lcr_shutdown, NULL);
|
||||
|
||||
static void lcr_destroy(lcr_route route)
|
||||
{
|
||||
while(route) {
|
||||
switch_event_destroy(&route->fields);
|
||||
route=route->next;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *do_cid(switch_memory_pool_t *pool, const char *cid, const char *number, switch_core_session_t *session)
|
||||
{
|
||||
switch_regex_t *re = NULL;
|
||||
@@ -239,14 +248,13 @@ static char *get_bridge_data(switch_memory_pool_t *pool, char *dialed_number, ch
|
||||
size_t tstrip;
|
||||
char *data = NULL;
|
||||
char *destination_number = NULL;
|
||||
char *orig_destination_number = NULL;
|
||||
char *codec = NULL;
|
||||
char *cid = NULL;
|
||||
char *header = NULL;
|
||||
char *user_rate = NULL;
|
||||
char *export_fields = NULL;
|
||||
|
||||
orig_destination_number = destination_number = switch_core_strdup(pool, dialed_number);
|
||||
destination_number = switch_core_strdup(pool, dialed_number);
|
||||
|
||||
tstrip = ((cur_route->digit_len - cur_route->tstrip) + 1);
|
||||
lstrip = cur_route->lstrip;
|
||||
@@ -613,6 +621,9 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
} else if (CF("lcr_carrier_name")) {
|
||||
additional->carrier_name = switch_core_strdup(pool, switch_str_nil(argv[i]));
|
||||
} else if (CF("lcr_rate_field")) {
|
||||
if (!argv[i] || zstr(argv[i])) {
|
||||
goto end;
|
||||
}
|
||||
additional->rate = (float)atof(switch_str_nil(argv[i]));
|
||||
additional->rate_str = switch_core_sprintf(pool, "%0.5f", additional->rate);
|
||||
} else if (CF("lcr_gw_prefix")) {
|
||||
@@ -658,9 +669,14 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
r = 0; goto end;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (current = cbt->head; current; current = current->next) {
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
key = switch_core_sprintf(pool, "%s:%s", additional->gw_prefix, additional->gw_suffix);
|
||||
if (switch_core_hash_find(cbt->dedup_hash, key)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
@@ -717,7 +733,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
|
||||
|
||||
end:
|
||||
|
||||
switch_event_destroy(&additional->fields);
|
||||
/* event is freed in lcr_destroy() switch_event_destroy(&additional->fields); */
|
||||
|
||||
return r;
|
||||
|
||||
@@ -752,10 +768,14 @@ static switch_status_t is_intrastatelata(callback_t *cb_struct)
|
||||
*/
|
||||
if (!cb_struct->lookup_number || strlen(cb_struct->lookup_number) != 11 || *cb_struct->lookup_number != '1' ||
|
||||
!switch_is_number(cb_struct->lookup_number)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG,
|
||||
"%s doesn't appear to be a NANP number\n", cb_struct->lookup_number);
|
||||
/* dest doesn't appear to be NANP number */
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
if (!cb_struct->cid || strlen(cb_struct->cid) != 11 || *cb_struct->cid != '1' || !switch_is_number(cb_struct->cid)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG,
|
||||
"%s doesn't appear to be a NANP number\n", cb_struct->cid);
|
||||
/* cid not NANP */
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
@@ -813,6 +833,7 @@ 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);
|
||||
|
||||
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) {
|
||||
is_intrastatelata(cb_struct);
|
||||
}
|
||||
@@ -835,6 +856,10 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
|
||||
if (cb_struct->session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "we have a session\n");
|
||||
if ((channel = switch_core_session_get_channel(cb_struct->session))) {
|
||||
const char *max_rate = switch_channel_get_variable(channel, "max_rate");
|
||||
if (!zstr(max_rate)) {
|
||||
cb_struct->max_rate = atof(max_rate);
|
||||
}
|
||||
switch_channel_set_variable_var_check(channel, "lcr_rate_field", rate_field, SWITCH_FALSE);
|
||||
switch_channel_set_variable_var_check(channel, "lcr_user_rate_field", user_rate_field, SWITCH_FALSE);
|
||||
switch_channel_set_variable_var_check(channel, "lcr_query_digits", digits_copy, SWITCH_FALSE);
|
||||
@@ -900,6 +925,7 @@ static switch_bool_t test_profile(char *lcr_profile)
|
||||
|
||||
routes.lookup_number = "15555551212";
|
||||
routes.cid = "18005551212";
|
||||
lcr_destroy(routes.head);
|
||||
return (lcr_do_lookup(&routes) == SWITCH_STATUS_SUCCESS) ?
|
||||
SWITCH_TRUE : SWITCH_FALSE;
|
||||
}
|
||||
@@ -1053,13 +1079,17 @@ static switch_status_t lcr_load_config()
|
||||
if (zstr(custom_sql)) {
|
||||
/* use default sql */
|
||||
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 "
|
||||
"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");
|
||||
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 ");
|
||||
@@ -1067,12 +1097,15 @@ static switch_status_t lcr_load_config()
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cid field not defined, please update your lcr database schema.\n");
|
||||
}
|
||||
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, "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}");
|
||||
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);
|
||||
}
|
||||
|
||||
sql_stream.write_function(&sql_stream, "ORDER BY digits DESC%s",
|
||||
profile->order_by);
|
||||
if (db_random) {
|
||||
@@ -1229,7 +1262,6 @@ static switch_call_cause_t lcr_outgoing_channel(switch_core_session_t *session,
|
||||
const char *intralata = NULL;
|
||||
switch_core_session_t *mysession = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
switch_caller_profile_t *caller_profile = NULL;
|
||||
|
||||
dest = strdup(outbound_profile->destination_number);
|
||||
|
||||
@@ -1256,7 +1288,6 @@ static switch_call_cause_t lcr_outgoing_channel(switch_core_session_t *session,
|
||||
timelimit = atoi(var);
|
||||
}
|
||||
routes.session = session;
|
||||
caller_profile = switch_channel_get_caller_profile(channel);
|
||||
intrastate = switch_channel_get_variable(channel, "intrastate");
|
||||
intralata = switch_channel_get_variable(channel, "intralata");
|
||||
cid_name_override = switch_channel_get_variable(channel, "origination_caller_id_name");
|
||||
@@ -1378,6 +1409,7 @@ static switch_call_cause_t lcr_outgoing_channel(switch_core_session_t *session,
|
||||
if (mysession) {
|
||||
switch_core_session_rwunlock(mysession);
|
||||
}
|
||||
lcr_destroy(routes.head);
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
switch_safe_free(dest);
|
||||
|
||||
@@ -1475,6 +1507,7 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
|
||||
}
|
||||
|
||||
end:
|
||||
lcr_destroy(routes.head);
|
||||
if (event) {
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
@@ -1607,6 +1640,7 @@ SWITCH_STANDARD_APP(lcr_app_function)
|
||||
}
|
||||
|
||||
end:
|
||||
lcr_destroy(routes.head);
|
||||
if (routes.event) {
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
@@ -1630,10 +1664,10 @@ static void write_data(switch_stream_handle_t *stream, switch_bool_t as_xml, con
|
||||
|
||||
SWITCH_STANDARD_API(dialplan_lcr_function)
|
||||
{
|
||||
char *argv[4] = { 0 };
|
||||
char *argv[9] = { 0 };
|
||||
int argc;
|
||||
char *mydata = NULL;
|
||||
char *dialstring = NULL;
|
||||
//char *dialstring = NULL;
|
||||
char *lcr_profile = NULL;
|
||||
lcr_route current = NULL;
|
||||
max_obj_t maximum_lengths = { 0 };
|
||||
@@ -1755,7 +1789,8 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
|
||||
current = cb_struct.head;
|
||||
while (current) {
|
||||
|
||||
dialstring = get_bridge_data(pool, cb_struct.lookup_number, cb_struct.cid, current, cb_struct.profile, cb_struct.session);
|
||||
//dialstring =
|
||||
get_bridge_data(pool, cb_struct.lookup_number, cb_struct.cid, current, cb_struct.profile, cb_struct.session);
|
||||
rowcount++;
|
||||
|
||||
if (as_xml) {
|
||||
@@ -1790,7 +1825,7 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
|
||||
if (as_xml) {
|
||||
event_xml = switch_event_xmlize(current->fields, SWITCH_VA_NONE);
|
||||
event_str = switch_xml_toxml(event_xml, SWITCH_FALSE);
|
||||
stream->write_function(stream, event_str);
|
||||
stream->write_function(stream, "%s", event_str);
|
||||
switch_xml_free(event_xml);
|
||||
switch_safe_free(event_str);
|
||||
}
|
||||
@@ -1819,6 +1854,7 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
|
||||
}
|
||||
|
||||
end:
|
||||
lcr_destroy(cb_struct.head);
|
||||
if (!session) {
|
||||
if (pool) {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
@@ -1867,16 +1903,11 @@ SWITCH_STANDARD_API(dialplan_lcr_admin_function)
|
||||
stream->write_function(stream, " has intrastate:\t%s\n", profile->profile_has_intrastate ? "true" : "false");
|
||||
stream->write_function(stream, " has intralata:\t%s\n", profile->profile_has_intralata ? "true" : "false");
|
||||
stream->write_function(stream, " has npanxx:\t%s\n", profile->profile_has_npanxx ? "true" : "false");
|
||||
stream->write_function(stream, " Reorder rate:\t%s\n",
|
||||
profile->reorder_by_rate ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Info in headers:\t%s\n",
|
||||
profile->info_in_headers ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Quote IN() List:\t%s\n",
|
||||
profile->quote_in_list ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Sip Redirection Mode:\t%s\n",
|
||||
profile->enable_sip_redir ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Import fields:\t%s\n",
|
||||
profile->export_fields_str ? profile->export_fields_str : "(null)");
|
||||
stream->write_function(stream, " Reorder rate:\t%s\n", profile->reorder_by_rate ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Info in headers:\t%s\n", profile->info_in_headers ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Quote IN() List:\t%s\n", profile->quote_in_list ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Sip Redirection Mode:\t%s\n", profile->enable_sip_redir ? "enabled" : "disabled");
|
||||
stream->write_function(stream, " Import fields:\t%s\n", profile->export_fields_str ? profile->export_fields_str : "(null)");
|
||||
stream->write_function(stream, " Limit type:\t%s\n", profile->limit_type);
|
||||
stream->write_function(stream, "\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
BASE=../../../..
|
||||
|
||||
MONGO_CXX_DRIVER_VERSION=v1.8
|
||||
MONGO_CXX_DRIVER_URL=http://downloads.mongodb.org/cxx-driver
|
||||
MONGO_CXX_DRIVER_TARBALL=mongodb-linux-x86_64-$(MONGO_CXX_DRIVER_VERSION)-latest.tgz
|
||||
MONGO_CXX_DRIVER_SRC=$(BASE)/libs/mongo-cxx-driver-$(MONGO_CXX_DRIVER_VERSION)
|
||||
LIBMONGOCLIENT_A =$(MONGO_CXX_DRIVER_SRC)/libmongoclient.a
|
||||
|
||||
LOCAL_SOURCES=mongo_conn.cpp
|
||||
LOCAL_OBJS=mongo_conn.o
|
||||
|
||||
LOCAL_CFLAGS=-I$(MONGO_CXX_DRIVER_SRC)/mongo
|
||||
LOCAL_LIBADD=$(LIBMONGOCLIENT_A)
|
||||
LOCAL_LDFLAGS=-lboost_thread -lboost_filesystem-mt -lboost_system-mt
|
||||
MODDIR=$(shell pwd)
|
||||
|
||||
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
$(MONGO_CXX_DRIVER_SRC):
|
||||
$(GETLIB) $(MONGO_CXX_DRIVER_URL) $(MONGO_CXX_DRIVER_TARBALL)
|
||||
cd $(MONGO_CXX_DRIVER_SRC) && patch -p0 -i $(MODDIR)/fpic_hack.diff
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
|
||||
$(LIBMONGOCLIENT_A): $(MONGO_CXX_DRIVER_SRC)
|
||||
cd $(MONGO_CXX_DRIVER_SRC) && scons
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- SConstruct.orig 2011-04-28 19:00:36.000000000 +0200
|
||||
+++ SConstruct 2011-04-28 19:01:19.000000000 +0200
|
||||
@@ -45,7 +45,7 @@
|
||||
linux = True
|
||||
|
||||
if nix:
|
||||
- env.Append( CPPFLAGS=" -O3" )
|
||||
+ env.Append( CPPFLAGS=" -I../pcre -fPIC -O3" )
|
||||
env.Append( LIBS=["pthread"] )
|
||||
if linux:
|
||||
env.Append( LINKFLAGS=" -Wl,--as-needed -Wl,-zdefs " )
|
||||
@@ -0,0 +1,151 @@
|
||||
#include <switch.h>
|
||||
#include "mod_mongo.h"
|
||||
|
||||
|
||||
static struct {
|
||||
mongo_connection_pool_t *conn_pool;
|
||||
} globals;
|
||||
|
||||
|
||||
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))) {
|
||||
*json_query++ = '\0';
|
||||
if ((json_fields = strchr(json_query, delim))) {
|
||||
*json_fields++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(ns) && !zstr(json_query) && !zstr(json_fields)) {
|
||||
|
||||
DBClientConnection *conn = NULL;
|
||||
|
||||
try {
|
||||
BSONObj query = fromjson(json_query);
|
||||
BSONObj fields = fromjson(json_fields);
|
||||
|
||||
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);
|
||||
|
||||
stream->write_function(stream, "-OK\n%s\n", res.toString().c_str());
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\nNo connection\n");
|
||||
}
|
||||
} catch (DBException &e) {
|
||||
if (conn) {
|
||||
mongo_connection_destroy(&conn);
|
||||
}
|
||||
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\n%s\n", SYNTAX);
|
||||
}
|
||||
|
||||
switch_safe_free(ns);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
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";
|
||||
switch_size_t min_connections = 1, max_connections = 1;
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if ((settings = switch_xml_child(cfg, "settings"))) {
|
||||
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
int tmp;
|
||||
|
||||
if (!strcmp(var, "host")) {
|
||||
host = val;
|
||||
} else if (!strcmp(var, "min-connections")) {
|
||||
if ((tmp = atoi(val)) > 0) {
|
||||
min_connections = tmp;
|
||||
}
|
||||
} else if (!strcmp(var, "max-connections")) {
|
||||
if ((tmp = atoi(val)) > 0) {
|
||||
max_connections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mongo_connection_pool_create(&globals.conn_pool, min_connections, max_connections, host) != 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_xml_free(xml);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mongo_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_mongo, mod_mongo_load, mod_mongo_shutdown, NULL);
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
switch_application_interface_t *app_interface;
|
||||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
|
||||
if (config() != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
SWITCH_ADD_API(api_interface, "mongo_find_one", "mongo", mongo_find_one_function, SYNTAX);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mongo_shutdown)
|
||||
{
|
||||
mongo_connection_pool_destroy(&globals.conn_pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef MOD_MONGO_H
|
||||
#define MOD_MONGO_H
|
||||
|
||||
|
||||
#include <client/dbclient.h>
|
||||
#include <client/connpool.h>
|
||||
#include <db/json.h>
|
||||
#include <bson/bson.h>
|
||||
|
||||
using namespace mongo;
|
||||
|
||||
typedef struct {
|
||||
char *host;
|
||||
|
||||
switch_size_t min_connections;
|
||||
switch_size_t max_connections;
|
||||
switch_size_t size;
|
||||
switch_queue_t *connections;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
} 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_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
|
||||
const char *host);
|
||||
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);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
#include <switch.h>
|
||||
#include "mod_mongo.h"
|
||||
|
||||
/*
|
||||
we could use the driver's connection pool,
|
||||
if we could set the max connections (PoolForHost::setMaxPerHost)
|
||||
|
||||
ScopedDbConnection scoped_conn("host");
|
||||
DBClientConnection *conn = dynamic_cast< DBClientConnection* >(&scoped_conn.conn());
|
||||
scoped_conn.done();
|
||||
*/
|
||||
|
||||
switch_status_t mongo_connection_create(DBClientConnection **connection, const char *host)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
*connection = conn;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", host);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void mongo_connection_destroy(DBClientConnection **conn)
|
||||
{
|
||||
switch_assert(*conn != NULL);
|
||||
delete *conn;
|
||||
|
||||
*conn = NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
mongo_connection_pool_t *cpool = NULL;
|
||||
DBClientConnection *conn = NULL;
|
||||
|
||||
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!(cpool = (mongo_connection_pool_t *)switch_core_alloc(pool, sizeof(mongo_connection_pool_t)))) {
|
||||
switch_goto_status(SWITCH_STATUS_MEMERR, done);
|
||||
}
|
||||
|
||||
if ((status = switch_mutex_init(&cpool->mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((status = switch_queue_create(&cpool->connections, max_connections, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
cpool->min_connections = min_connections;
|
||||
cpool->max_connections = max_connections;
|
||||
cpool->host = switch_core_strdup(pool, host);
|
||||
|
||||
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);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
*conn_pool = cpool;
|
||||
} else {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool)
|
||||
{
|
||||
mongo_connection_pool_t *cpool = *conn_pool;
|
||||
void *data = NULL;
|
||||
|
||||
switch_assert(cpool != NULL);
|
||||
|
||||
while (switch_queue_trypop(cpool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_destroy((DBClientConnection **)&data);
|
||||
}
|
||||
|
||||
switch_mutex_destroy(cpool->mutex);
|
||||
switch_core_destroy_memory_pool(&cpool->pool);
|
||||
|
||||
*conn_pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
DBClientConnection *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool)
|
||||
{
|
||||
DBClientConnection *conn = NULL;
|
||||
void *data = NULL;
|
||||
|
||||
switch_assert(conn_pool != NULL);
|
||||
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conn_pool->mutex);
|
||||
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL get: size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
|
||||
#endif
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientConnection *conn)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
switch_assert(conn_pool != NULL);
|
||||
switch_assert(conn != NULL);
|
||||
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
if (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
|
||||
mongo_connection_destroy(&conn);
|
||||
conn_pool->size--;
|
||||
} else {
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: push connection %p\n", conn);
|
||||
#endif
|
||||
status = switch_queue_push(conn_pool->connections, conn);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conn_pool->mutex);
|
||||
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: put size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -399,7 +399,7 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
||||
const char *billrate;
|
||||
const char *billaccount;
|
||||
float nobal_amt = globals.nobal_amt;
|
||||
float lowbal_amt = globals.lowbal_amt;
|
||||
//float lowbal_amt = globals.lowbal_amt;
|
||||
float balance;
|
||||
|
||||
if (!session) {
|
||||
@@ -421,10 +421,11 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
||||
if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) {
|
||||
nobal_amt = (float)atof(switch_channel_get_variable(channel, "nobal_amt"));
|
||||
}
|
||||
/*
|
||||
if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) {
|
||||
lowbal_amt = (float)atof(switch_channel_get_variable(channel, "lowbal_amt"));
|
||||
}
|
||||
|
||||
*/
|
||||
/* Return if there's no billing information on this session */
|
||||
if (!billrate || !billaccount) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -802,9 +803,6 @@ SWITCH_STANDARD_API(nibblebill_api_function)
|
||||
if ((argc == 2 || argc == 3) && !zstr(argv[0])) {
|
||||
char *uuid = argv[0];
|
||||
if ((psession = switch_core_session_locate(uuid))) {
|
||||
switch_channel_t *channel;
|
||||
channel = switch_core_session_get_channel(psession);
|
||||
|
||||
if (!strcasecmp(argv[1], "adjust") && argc == 3) {
|
||||
nibblebill_adjust(psession, (float) atof(argv[2]));
|
||||
} else if (!strcasecmp(argv[1], "flush")) {
|
||||
@@ -904,7 +902,7 @@ switch_state_handler_table_t nibble_state_handler = {
|
||||
/* on_hibernate */ NULL,
|
||||
/* on_reset */ NULL,
|
||||
/* on_park */ NULL,
|
||||
/* on_reporting */ process_hangup, /* force billing event on b-leg if we can */
|
||||
/* on_reporting */ NULL,
|
||||
/* on_destroy */ NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
BASE=../../../..
|
||||
LOCAL_OBJS=ivr.o util.o config.o menu.o
|
||||
include $(BASE)/build/modmake.rules
|
||||
@@ -0,0 +1,130 @@
|
||||
/* 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;
|
||||
|
||||
/* 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, "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 != 11) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
extern const char *global_cf;
|
||||
|
||||
struct vmivr_profile {
|
||||
const char *name;
|
||||
|
||||
const char *domain;
|
||||
const char *id;
|
||||
|
||||
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_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_ */
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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;
|
||||
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
|
||||
*/
|
||||
@@ -0,0 +1,30 @@
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* 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},
|
||||
{ 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 and 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--) {
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
if (strncasecmp(switch_event_get_header(phrase_params, "VM-Message-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 (!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_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" };
|
||||
|
||||
password = mtvm_menu_get_input_set(session, profile, menu, "XXX." /* TODO Conf Min 3 Digit */, "#" /* TODO Conf terminate input key */);
|
||||
|
||||
/* 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 */, "#" /* TODO Conf terminate input key */);
|
||||
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 */, "#" /* TODO Conf terminate input key */);
|
||||
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", NULL);
|
||||
|
||||
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", NULL);
|
||||
|
||||
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, const char *terminate_key) {
|
||||
char *result = NULL;
|
||||
int retry;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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]; /* TODO Make this load from the configuration */
|
||||
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
|
||||
*/
|
||||
@@ -0,0 +1,31 @@
|
||||
#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);
|
||||
|
||||
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, const char *terminate_key);
|
||||
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@@ -0,0 +1,137 @@
|
||||
<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="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" /> <!-- TODO Make the ivrengine: parsed and the key configurable -->
|
||||
</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" /> <!-- TODO Make the ivrengine: parsed and the key configurable -->
|
||||
</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="3" action="save_msg" variable="VM-Key-Main-Save-File" />
|
||||
<key dtmf="5" action="menu:std_preference" />
|
||||
</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="0" 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_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>
|
||||
</keys>
|
||||
</menu>
|
||||
</menus>
|
||||
</profile>
|
||||
</profiles>
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
<include><!--This line will be ignored it's here to validate the xml and is optional -->
|
||||
<macros name="protovm" sound-prefix="$${sounds_dir}/fr/ca/june">
|
||||
<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="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"/>
|
||||
<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"/>
|
||||
</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 -->
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#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_ */
|
||||
|
||||
@@ -89,7 +89,7 @@ SWITCH_LIMIT_INCR(limit_incr_redis)
|
||||
}
|
||||
|
||||
/* Get the keys for redis server */
|
||||
uuid_rediskey = switch_core_session_sprintf(session,"%s_%s_%s", switch_core_get_hostname(), realm, resource);
|
||||
uuid_rediskey = switch_core_session_sprintf(session,"%s_%s_%s", switch_core_get_switchname(), realm, resource);
|
||||
rediskey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
|
||||
|
||||
if ((pvt = switch_channel_get_private(channel, "limit_redis"))) {
|
||||
@@ -179,7 +179,7 @@ SWITCH_LIMIT_RELEASE(limit_release_redis)
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Couldn't decrement value corresponding to %s\n", (char *)p_key);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, end);
|
||||
}
|
||||
p_uuid_key = switch_core_session_sprintf(session, "%s_%s", switch_core_get_hostname(), (char *)p_key);
|
||||
p_uuid_key = switch_core_session_sprintf(session, "%s_%s", switch_core_get_switchname(), (char *)p_key);
|
||||
if (credis_decr(redis,p_uuid_key,&uuid_val) != 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Couldn't decrement value corresponding to %s\n", p_uuid_key);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, end);
|
||||
@@ -193,7 +193,7 @@ SWITCH_LIMIT_RELEASE(limit_release_redis)
|
||||
|
||||
} else {
|
||||
rediskey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
|
||||
uuid_rediskey = switch_core_session_sprintf(session, "%s_%s_%s", switch_core_get_hostname(), realm, resource);
|
||||
uuid_rediskey = switch_core_session_sprintf(session, "%s_%s_%s", switch_core_get_switchname(), realm, resource);
|
||||
switch_core_hash_delete(pvt->hash, (const char *) rediskey);
|
||||
|
||||
if (credis_decr(redis, rediskey, &val) != 0) {
|
||||
@@ -249,13 +249,13 @@ SWITCH_LIMIT_RESET(limit_reset_redis)
|
||||
{
|
||||
REDIS redis;
|
||||
if (redis_factory(&redis) == SWITCH_STATUS_SUCCESS) {
|
||||
char *rediskey = switch_mprintf("%s_*", switch_core_get_hostname());
|
||||
char *rediskey = switch_mprintf("%s_*", switch_core_get_switchname());
|
||||
int dec = 0, val = 0, keyc;
|
||||
char *uuids[2000];
|
||||
|
||||
if ((keyc = credis_keys(redis, rediskey, uuids, switch_arraylen(uuids))) > 0) {
|
||||
int i = 0;
|
||||
int hostnamelen = strlen(switch_core_get_hostname())+1;
|
||||
int hostnamelen = strlen(switch_core_get_switchname())+1;
|
||||
|
||||
for (i = 0; i < keyc && uuids[i]; i++){
|
||||
const char *key = uuids[i] + hostnamelen;
|
||||
|
||||
@@ -175,7 +175,7 @@ SWITCH_STANDARD_APP(rss_function)
|
||||
char *filename = NULL;
|
||||
char *argv[3], *feed_list[TTS_MAX_ENTRIES] = { 0 }, *feed_names[TTS_MAX_ENTRIES] = {
|
||||
0};
|
||||
int argc, feed_index = 0;
|
||||
int feed_index = 0;
|
||||
const char *cf = "rss.conf";
|
||||
switch_xml_t cfg, cxml, feeds, feed;
|
||||
char buf[1024] = "";
|
||||
@@ -236,7 +236,7 @@ SWITCH_STANDARD_APP(rss_function)
|
||||
|
||||
if (!zstr(data)) {
|
||||
if ((mydata = switch_core_session_strdup(session, data))) {
|
||||
argc = switch_separate_string(mydata, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
switch_separate_string(mydata, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
if (argv[0]) {
|
||||
engine = argv[0];
|
||||
|
||||
@@ -70,33 +70,89 @@ SWITCH_STANDARD_APP(stop_dtmf_session_function)
|
||||
spandsp_stop_inband_dtmf_session(session);
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(spandsp_fax_detect_session_function)
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[3] = { 0 };
|
||||
char *dupdata;
|
||||
const char *app = NULL, *arg = NULL;
|
||||
int timeout = 0;
|
||||
|
||||
if (!zstr(data) && (dupdata = switch_core_session_strdup(session, data))) {
|
||||
if ((argc = switch_split(dupdata, ' ', argv)) == 3) {
|
||||
app = argv[0];
|
||||
arg = argv[1];
|
||||
timeout = atoi(argv[2]);
|
||||
if (timeout < 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot Enable fax detection '%s' '%s'\n", argv[0], argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(spandsp_stop_fax_detect_session_function)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Disabling fax detection\n");
|
||||
spandsp_fax_stop_detect_session(session);
|
||||
}
|
||||
|
||||
static void event_handler(switch_event_t *event)
|
||||
{
|
||||
mod_spandsp_fax_event_handler(event);
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(t38_gateway_function)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
time_t timeout = switch_epoch_time_now(NULL) + 20;
|
||||
const char *var;
|
||||
|
||||
if (zstr(data) || strcasecmp(data, "self")) {
|
||||
data = "peer";
|
||||
}
|
||||
|
||||
switch_channel_set_variable(channel, "t38_leg", data);
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "t38_gateway_detect_timeout"))) {
|
||||
long to = atol(var);
|
||||
if (to > -1) {
|
||||
timeout = (time_t) (switch_epoch_time_now(NULL) + to);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s invalid timeout value.\n", switch_channel_get_name(channel));
|
||||
int argc = 0;
|
||||
char *argv[2] = { 0 };
|
||||
char *dupdata;
|
||||
const char *direction = NULL, *flags = NULL;
|
||||
|
||||
if (!zstr(data) && (dupdata = switch_core_session_strdup(session, data))) {
|
||||
if ((argc = switch_split(dupdata, ' ', argv))) {
|
||||
if (argc > 0) {
|
||||
direction = argv[0];
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
flags = argv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zstr(direction) || strcasecmp(direction, "self")) {
|
||||
direction = "peer";
|
||||
}
|
||||
|
||||
switch_ivr_tone_detect_session(session, "t38", "1100.0", "rw", timeout, 1, data, NULL, t38_gateway_start);
|
||||
switch_channel_set_variable(channel, "t38_leg", direction);
|
||||
|
||||
if (!zstr(flags) && !strcasecmp(flags, "nocng")) {
|
||||
t38_gateway_start(session, direction, NULL);
|
||||
} else {
|
||||
if ((var = switch_channel_get_variable(channel, "t38_gateway_detect_timeout"))) {
|
||||
long to = atol(var);
|
||||
if (to > -1) {
|
||||
timeout = (time_t) (switch_epoch_time_now(NULL) + to);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s invalid timeout value.\n", switch_channel_get_name(channel));
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,6 +254,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
|
||||
SWITCH_ADD_APP(app_interface, "spandsp_stop_dtmf", "stop inband dtmf", "Stop detecting inband dtmf.", stop_dtmf_session_function, "", SAF_NONE);
|
||||
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);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "spandsp_stop_fax_detect", "stop fax detect", "stop fax detect", spandsp_stop_fax_detect_session_function, "", SAF_NONE);
|
||||
|
||||
|
||||
mod_spandsp_fax_load(pool);
|
||||
mod_spandsp_codecs_load(module_interface, pool);
|
||||
|
||||
|
||||
@@ -68,3 +68,9 @@ switch_status_t spandsp_inband_dtmf_session(switch_core_session_t *session);
|
||||
|
||||
switch_status_t callprogress_detector_start(switch_core_session_t *session, const char *name);
|
||||
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,
|
||||
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);
|
||||
|
||||
@@ -220,7 +220,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
|
||||
}
|
||||
|
||||
for (pvt = t38_state_list.head; pvt; pvt = pvt->next) {
|
||||
if (pvt->udptl_state) {
|
||||
if (pvt->udptl_state && pvt->session && switch_channel_ready(switch_core_session_get_channel(pvt->session))) {
|
||||
t38_terminal_send_timeout(pvt->t38_state, samples);
|
||||
}
|
||||
}
|
||||
@@ -414,18 +414,19 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
|
||||
/* Fire event */
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, pvt->app_mode == FUNCTION_TX ? SPANDSP_EVENT_TXFAXRESULT : SPANDSP_EVENT_RXFAXRESULT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-success", (result == T30_ERR_OK) ? "1" : "0");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-result-code", fax_result_code);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-result-text", t30_completion_code_to_str(result));
|
||||
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-document-total-pages", fax_document_total_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-bad-rows", fax_bad_rows);
|
||||
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-result-code", fax_result_code);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-result-text", t30_completion_code_to_str(result));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-ecm-used", (t.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_core_session_queue_private_event(session, &event, SWITCH_FALSE);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +434,6 @@ static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uin
|
||||
{
|
||||
switch_frame_t out_frame = { 0 };
|
||||
switch_core_session_t *session;
|
||||
switch_channel_t *channel;
|
||||
pvt_t *pvt;
|
||||
uint8_t pkt[LOCAL_FAX_MAX_DATAGRAM];
|
||||
int x;
|
||||
@@ -441,23 +441,37 @@ static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uin
|
||||
|
||||
pvt = (pvt_t *) user_data;
|
||||
session = pvt->session;
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
/* we need to build a real packet here and make write_frame.packet and write_frame.packetlen point to it */
|
||||
out_frame.flags = SFF_UDPTL_PACKET | SFF_PROXY_PACKET;
|
||||
out_frame.packet = pkt;
|
||||
out_frame.packetlen = udptl_build_packet(pvt->udptl_state, pkt, buf, len);
|
||||
|
||||
//switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "WRITE %d udptl bytes\n", out_frame.packetlen);
|
||||
if ((r = udptl_build_packet(pvt->udptl_state, pkt, buf, len)) > 0) {
|
||||
out_frame.packetlen = r;
|
||||
//switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "WRITE %d udptl bytes\n", out_frame.packetlen);
|
||||
|
||||
for (x = 0; x < count; x++) {
|
||||
if (switch_core_session_write_frame(session, &out_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
r = -1;
|
||||
break;
|
||||
for (x = 0; x < count; x++) {
|
||||
if (switch_core_session_write_frame(session, &out_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "INVALID WRITE: %d:%d\n", out_frame.packetlen, count);
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "INVALID PACKETLEN: %d PASSED: %d:%d\n", r, len, count);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
t30_state_t *t30;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "TERMINATING T30 STATE\n");
|
||||
|
||||
if (pvt->t38_state && (t30 = t38_terminal_get_t30_state(pvt->t38_state))) {
|
||||
t30_terminate(t30);
|
||||
}
|
||||
switch_yield(10000);
|
||||
}
|
||||
|
||||
return r;
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
@@ -1772,8 +1786,8 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app,
|
||||
switch_channel_set_variable(channel, "t38_peer", switch_core_session_get_uuid(other_session));
|
||||
switch_channel_set_variable(other_channel, "t38_peer", switch_core_session_get_uuid(session));
|
||||
|
||||
switch_channel_set_variable(peer ? other_channel : channel, "t38_gateway_format", "audio");
|
||||
switch_channel_set_variable(peer ? channel : other_channel, "t38_gateway_format", "udptl");
|
||||
switch_channel_set_variable(peer ? other_channel : channel, "t38_gateway_format", "udptl");
|
||||
switch_channel_set_variable(peer ? channel : other_channel, "t38_gateway_format", "audio");
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s starting gateway mode to %s\n",
|
||||
@@ -1803,6 +1817,250 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app,
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *app;
|
||||
char *data;
|
||||
char *key;
|
||||
int up;
|
||||
int total_hits;
|
||||
int hits;
|
||||
int sleep;
|
||||
int expires;
|
||||
int default_sleep;
|
||||
int default_expires;
|
||||
switch_tone_detect_callback_t callback;
|
||||
modem_connect_tones_rx_state_t rx_tones;
|
||||
|
||||
switch_media_bug_t *bug;
|
||||
switch_core_session_t *session;
|
||||
int bug_running;
|
||||
|
||||
} spandsp_fax_tone_container_t;
|
||||
|
||||
static switch_status_t tone_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
spandsp_fax_tone_container_t *cont = switch_channel_get_private(channel, "_fax_tone_detect_");
|
||||
|
||||
|
||||
if (!cont || dtmf->digit != 'f') {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (cont->callback) {
|
||||
cont->callback(cont->session, cont->app, cont->data);
|
||||
} else {
|
||||
switch_channel_execute_on(switch_core_session_get_channel(cont->session), "execute_on_fax_detect");
|
||||
if (cont->app) {
|
||||
switch_core_session_execute_application_async(cont->session, cont->app, cont->data);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static switch_bool_t tone_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
spandsp_fax_tone_container_t *cont = (spandsp_fax_tone_container_t *) user_data;
|
||||
switch_frame_t *frame = NULL;
|
||||
switch_bool_t rval = SWITCH_TRUE;
|
||||
|
||||
switch (type) {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_READ_REPLACE:
|
||||
case SWITCH_ABC_TYPE_WRITE_REPLACE:
|
||||
{
|
||||
int skip = 0;
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
|
||||
frame = switch_core_media_bug_get_read_replace_frame(bug);
|
||||
} else {
|
||||
frame = switch_core_media_bug_get_write_replace_frame(bug);
|
||||
}
|
||||
|
||||
if (cont->sleep) {
|
||||
cont->sleep--;
|
||||
if (cont->sleep) {
|
||||
skip = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cont->expires) {
|
||||
cont->expires--;
|
||||
if (!cont->expires) {
|
||||
cont->hits = 0;
|
||||
cont->sleep = 0;
|
||||
cont->expires = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cont->up) {
|
||||
skip = 1;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
cont->hits = 0;
|
||||
modem_connect_tones_rx(&cont->rx_tones, frame->data, frame->samples);
|
||||
cont->hits = modem_connect_tones_rx_get(&cont->rx_tones);
|
||||
|
||||
if (cont->hits) {
|
||||
switch_event_t *event;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_DEBUG,
|
||||
"Fax Tone Detected. [%s][%s]\n", cont->app, switch_str_nil(cont->data));
|
||||
|
||||
if (cont->callback) {
|
||||
cont->callback(cont->session, cont->app, cont->data);
|
||||
} else {
|
||||
switch_channel_execute_on(switch_core_session_get_channel(cont->session), "execute_on_fax_detect");
|
||||
if (cont->app) {
|
||||
switch_core_session_execute_application_async(cont->session, cont->app, cont->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_DETECTED_TONE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_t *dup;
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detected-Fax-Tone", "true");
|
||||
|
||||
if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_fire(&dup);
|
||||
}
|
||||
|
||||
if (switch_core_session_queue_event(cont->session, &event) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR,
|
||||
"Event queue failed!\n");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
rval = SWITCH_FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_WRITE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rval == SWITCH_FALSE) {
|
||||
cont->bug_running = 0;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
switch_status_t spandsp_fax_stop_detect_session(switch_core_session_t *session)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
spandsp_fax_tone_container_t *cont = switch_channel_get_private(channel, "_fax_tone_detect_");
|
||||
|
||||
if (cont) {
|
||||
switch_channel_set_private(channel, "_fax_tone_detect_", NULL);
|
||||
cont->up = 0;
|
||||
switch_core_media_bug_remove(session, &cont->bug);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_status_t spandsp_fax_detect_session(switch_core_session_t *session,
|
||||
const char *flags, time_t timeout,
|
||||
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;
|
||||
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 (cont) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max Tones Reached!\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!cont && !(cont = switch_core_session_alloc(session, sizeof(*cont)))) {
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
if (app) {
|
||||
cont->app = switch_core_session_strdup(session, app);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
cont->data = switch_core_session_strdup(session, data);
|
||||
}
|
||||
|
||||
cont->callback = callback;
|
||||
cont->up = 1;
|
||||
cont->session = session;
|
||||
|
||||
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
cont->default_sleep = 25;
|
||||
cont->default_expires = 250;
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "fax_tone_detect_sleep"))) {
|
||||
int tmp = atoi(var);
|
||||
if (tmp > 0) {
|
||||
cont->default_sleep = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "fax_tone_detect_expires"))) {
|
||||
int tmp = atoi(var);
|
||||
if (tmp > 0) {
|
||||
cont->default_expires = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (zstr(flags)) {
|
||||
bflags = SMBF_READ_REPLACE;
|
||||
} else {
|
||||
if (strchr(flags, 'r')) {
|
||||
bflags |= SMBF_READ_REPLACE;
|
||||
} else if (strchr(flags, 'w')) {
|
||||
bflags |= SMBF_WRITE_REPLACE;
|
||||
}
|
||||
}
|
||||
|
||||
bflags |= SMBF_NO_PAUSE;
|
||||
|
||||
|
||||
switch_core_event_hook_add_send_dtmf(session, tone_on_dtmf);
|
||||
switch_core_event_hook_add_recv_dtmf(session, tone_on_dtmf);
|
||||
|
||||
|
||||
if ((status = switch_core_media_bug_add(session, "fax_tone_detect", "",
|
||||
tone_detect_callback, cont, timeout, bflags, &cont->bug)) != SWITCH_STATUS_SUCCESS) {
|
||||
cont->bug_running = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_channel_set_private(channel, "_fax_tone_detect_", cont);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
|
||||
@@ -61,7 +61,6 @@ static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8
|
||||
int octet_cnt;
|
||||
int octet_idx;
|
||||
int stat;
|
||||
int i;
|
||||
const uint8_t **pbuf;
|
||||
|
||||
for (octet_idx = 0, *p_num_octets = 0;; octet_idx += octet_cnt) {
|
||||
@@ -71,7 +70,6 @@ static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8
|
||||
*p_num_octets += octet_cnt;
|
||||
|
||||
pbuf = &p_object[octet_idx];
|
||||
i = 0;
|
||||
/* Make sure the buffer contains at least the number of bits requested */
|
||||
if ((*len + octet_cnt) > limit)
|
||||
return -1;
|
||||
|
||||
@@ -237,9 +237,8 @@ static switch_bool_t process_data(vmd_session_info_t *vmd_info, switch_frame_t *
|
||||
double pts[P];
|
||||
int16_t *data;
|
||||
int16_t max;
|
||||
switch_ssize_t len;
|
||||
|
||||
len = frame->samples * sizeof(int16_t);
|
||||
//len = frame->samples * sizeof(int16_t);
|
||||
data = (int16_t *) frame->data;
|
||||
|
||||
for (max = (int16_t) abs(data[0]), i = 1; i < frame->samples; i++) {
|
||||
|
||||
@@ -204,6 +204,36 @@ static switch_status_t vm_execute_sql(vm_profile_t *profile, char *sql, switch_m
|
||||
return status;
|
||||
}
|
||||
|
||||
char *vm_execute_sql2str(vm_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
|
||||
{
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
|
||||
char *ret = NULL;
|
||||
|
||||
if (mutex) {
|
||||
switch_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
if (!(dbh = vm_get_db_handle(profile))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = switch_cache_db_execute_sql2str(dbh, sql, resbuf, len, NULL);
|
||||
|
||||
end:
|
||||
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
|
||||
if (mutex) {
|
||||
switch_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static switch_bool_t vm_execute_sql_callback(vm_profile_t *profile, switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback,
|
||||
void *pdata)
|
||||
{
|
||||
@@ -2384,7 +2414,6 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
char *vm_email = NULL;
|
||||
char *vm_email_from = NULL;
|
||||
char *vm_notify_email = NULL;
|
||||
char *email_addr = NULL;
|
||||
char *vm_timezone = NULL;
|
||||
int send_mail = 0;
|
||||
int send_main = 0;
|
||||
@@ -2449,8 +2478,6 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
vm_notify_email = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "vm-mailfrom")) {
|
||||
vm_email_from = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "email-addr")) {
|
||||
email_addr = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "vm-email-all-messages") && (send_main = switch_true(val))) {
|
||||
send_mail++;
|
||||
} else if (!strcasecmp(var, "vm-notify-email-all-messages") && (send_notify = switch_true(val))) {
|
||||
@@ -2487,9 +2514,24 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
file_path = switch_mprintf("%s%smsg_%s_broadcast_%s", dir_path, SWITCH_PATH_SEPARATOR, use_uuid, filename);
|
||||
|
||||
if (copy) {
|
||||
file_path = switch_mprintf("%s%smsg_%s_broadcast_%s", dir_path, SWITCH_PATH_SEPARATOR, use_uuid, filename);
|
||||
|
||||
if (strlen(file_path) >= 250 /* Max size of the SQL field */) {
|
||||
char *ext;
|
||||
switch_safe_free(file_path);
|
||||
|
||||
if (!(ext = strrchr(filename, '.'))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Filename doesn't include a file format %s\n", filename);
|
||||
ret = SWITCH_STATUS_FALSE;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ext++;
|
||||
|
||||
file_path = switch_mprintf("%s%smsg_%s_broadcast_%" SWITCH_TIME_T_FMT ".%s", dir_path, SWITCH_PATH_SEPARATOR, use_uuid, switch_micro_time_now(), ext);
|
||||
}
|
||||
|
||||
switch_file_copy(path, file_path, SWITCH_FPROT_FILE_SOURCE_PERMS, pool);
|
||||
} else {
|
||||
file_path = (char *) path;
|
||||
@@ -2956,8 +2998,6 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
int send_mail = 0;
|
||||
cc_t cc = { 0 };
|
||||
char *read_flags = NORMAL_FLAG_STRING;
|
||||
int priority = 3;
|
||||
int email_attach = 1;
|
||||
char *operator_ext = NULL;
|
||||
char buf[2];
|
||||
char key_buf[80];
|
||||
@@ -2972,7 +3012,6 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
char *record_macro = VM_RECORD_MESSAGE_MACRO;
|
||||
int send_main = 0;
|
||||
int send_notify = 0;
|
||||
int insert_db = 1;
|
||||
const char *read_id = NULL;
|
||||
const char *caller_id_name = NULL;
|
||||
const char *caller_id_number = NULL;
|
||||
@@ -3029,10 +3068,6 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
vm_storage_dir = switch_core_session_strdup(session, val);
|
||||
} else if (!strcasecmp(var, "vm-notify-email-all-messages") && (send_notify = switch_true(val))) {
|
||||
send_mail++;
|
||||
} else if (!strcasecmp(var, "vm-keep-local-after-email")) {
|
||||
insert_db = switch_true(val);
|
||||
} else if (!strcasecmp(var, "vm-attach-file")) {
|
||||
email_attach = switch_true(val);
|
||||
} else if (!strcasecmp(var, "vm-disk-quota")) {
|
||||
disk_quota = atoi(val);
|
||||
} else if (!strcasecmp(var, "vm-alternate-greet-id")) {
|
||||
@@ -3072,11 +3107,6 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||
"Falling back to leaving message locally due to too many misconfiguration.\n");
|
||||
send_mail = 0;
|
||||
insert_db = 1;
|
||||
}
|
||||
|
||||
if (send_notify && !send_main) {
|
||||
insert_db = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -3258,7 +3288,6 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
(void) vm_macro_get(session, VM_RECORD_URGENT_CHECK_MACRO, key_buf, input, sizeof(input), 1, "", &term, profile->digit_timeout);
|
||||
if (*profile->urgent_key == *input) {
|
||||
read_flags = URGENT_FLAG_STRING;
|
||||
priority = 1;
|
||||
(void) switch_ivr_phrase_macro(session, VM_ACK_MACRO, "marked-urgent", NULL, NULL);
|
||||
} else {
|
||||
(void) switch_ivr_phrase_macro(session, VM_ACK_MACRO, "saved", NULL, NULL);
|
||||
@@ -3300,7 +3329,6 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
|
||||
|
||||
SWITCH_STANDARD_APP(voicemail_function)
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[6] = { 0 };
|
||||
char *mydata = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
@@ -3314,7 +3342,7 @@ SWITCH_STANDARD_APP(voicemail_function)
|
||||
|
||||
if (!zstr(data)) {
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
@@ -4328,7 +4356,6 @@ SWITCH_STANDARD_API(voicemail_list_api_function)
|
||||
#define VOICEMAIL_SYNTAX "rss [<host> <port> <uri> <user> <domain>] | [load|unload|reload] <profile> [reloadxml]"
|
||||
SWITCH_STANDARD_API(voicemail_api_function)
|
||||
{
|
||||
int argc = 0;
|
||||
char *mydata = NULL, *argv[6];
|
||||
char *host = NULL, *port = NULL, *uri = NULL;
|
||||
char *user = NULL, *domain = NULL;
|
||||
@@ -4340,7 +4367,7 @@ SWITCH_STANDARD_API(voicemail_api_function)
|
||||
void *val = NULL;
|
||||
switch_xml_t xml_root;
|
||||
const char *err;
|
||||
|
||||
int argc = 0;
|
||||
|
||||
if (session) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@@ -4479,6 +4506,795 @@ SWITCH_STANDARD_API(voicemail_api_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
struct msg_get_callback {
|
||||
switch_event_t *my_params;
|
||||
};
|
||||
typedef struct msg_get_callback msg_get_callback_t;
|
||||
|
||||
static int message_get_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
msg_get_callback_t *cbt = (msg_get_callback_t *) pArg;
|
||||
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Received-Epoch", "%s", argv[0]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Read-Epoch", "%s", argv[1]);
|
||||
/* switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, user, argv[2], 255); */
|
||||
/* switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, domain, argv[3], 255); */
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-UUID", "%s", argv[4]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Caller-Name", "%s", argv[5]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Caller-Number", "%s", argv[6]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Folder", "%s", argv[7]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-File-Path", "%s", argv[8]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Duration", "%s", argv[9]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Flags", "%s", argv[10]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Read-Flags", "%s", argv[11]);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, "VM-Message-Forwarded-By", "%s", argv[12]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msg_lst_callback {
|
||||
char *buf;
|
||||
size_t len;
|
||||
switch_event_t *my_params;
|
||||
};
|
||||
typedef struct msg_lst_callback msg_lst_callback_t;
|
||||
|
||||
static int message_list_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
msg_lst_callback_t *cbt = (msg_lst_callback_t *) pArg;
|
||||
char *varname = NULL;
|
||||
/* Message # never start with 0 */
|
||||
varname = switch_mprintf("VM-List-Message-%ld-UUID", ++cbt->len);
|
||||
switch_event_add_header(cbt->my_params, SWITCH_STACK_BOTTOM, varname, "%s", argv[0]);
|
||||
switch_safe_free(varname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int message_purge_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
const char *profile_name = argv[0];
|
||||
const char *uuid = argv[1];
|
||||
const char *id = argv[2];
|
||||
const char *domain = argv[3];
|
||||
const char *file_path = argv[4];
|
||||
char *sql;
|
||||
vm_profile_t *profile = get_profile(profile_name);
|
||||
|
||||
if (unlink(file_path) != 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", file_path);
|
||||
} else {
|
||||
sql = switch_mprintf("DELETE FROM voicemail_msgs WHERE username='%q' AND domain='%q' AND uuid = '%q'", id, domain, uuid);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
profile_rwunlock(profile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Preference API */
|
||||
#define VM_FSDB_PREF_GREETING_SET_USAGE "<profile> <domain> <user> <slot> [file-path]"
|
||||
SWITCH_STANDARD_API(vm_fsdb_pref_greeting_set_function)
|
||||
{
|
||||
int slot = -1;
|
||||
const char *file_path = NULL;
|
||||
char *sql = NULL;
|
||||
char res[254] = "";
|
||||
|
||||
char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
slot = atoi(argv[3]);
|
||||
if (argv[4])
|
||||
file_path = argv[4];
|
||||
|
||||
if (!profile_name || !domain || !id || !slot) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
} else {
|
||||
char *dir_path = switch_core_sprintf(pool, "%s%svoicemail%s%s%s%s%s%s", SWITCH_GLOBAL_dirs.storage_dir,
|
||||
SWITCH_PATH_SEPARATOR,
|
||||
SWITCH_PATH_SEPARATOR,
|
||||
profile->name, SWITCH_PATH_SEPARATOR, domain, SWITCH_PATH_SEPARATOR, id);
|
||||
char *final_file_path = switch_core_sprintf(pool, "%s%sgreeting_%d.%s", dir_path, SWITCH_PATH_SEPARATOR, slot, profile->file_ext);
|
||||
|
||||
if (file_path) {
|
||||
if (switch_file_exists(file_path, pool) != SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR Filename doesn't exist\n");
|
||||
profile_rwunlock(profile);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_file_rename(file_path, final_file_path, pool);
|
||||
}
|
||||
|
||||
if (switch_file_exists(final_file_path, pool) == SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
sql = switch_mprintf("SELECT count(*) FROM voicemail_prefs WHERE username = '%q' AND domain = '%q'", id, domain);
|
||||
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, greeting_path) VALUES('%q', '%q', '%q')", id, domain, final_file_path);
|
||||
} else {
|
||||
sql = switch_mprintf("UPDATE voicemail_prefs SET greeting_path = '%q' WHERE username = '%q' AND domain = '%q'", final_file_path, id, domain);
|
||||
}
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(sql);
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Recording doesn't exist [%s]\n", final_file_path);
|
||||
}
|
||||
profile_rwunlock(profile);
|
||||
}
|
||||
|
||||
stream->write_function(stream, "-OK\n");
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_PREF_RECNAME_SET_USAGE "<profile> <domain> <user> <file-path>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_pref_recname_set_function)
|
||||
{
|
||||
const char *file_path = NULL;
|
||||
|
||||
char *sql = NULL;
|
||||
char res[254] = "";
|
||||
|
||||
char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
file_path = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id || !file_path) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (switch_file_exists(file_path, pool) != SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR Filename doesn't exist\n");
|
||||
profile_rwunlock(profile);
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("SELECT count(*) FROM voicemail_prefs WHERE username = '%q' AND domain = '%q'", id, domain);
|
||||
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,
|
||||
SWITCH_PATH_SEPARATOR,
|
||||
profile->name, SWITCH_PATH_SEPARATOR, domain, SWITCH_PATH_SEPARATOR, id);
|
||||
char *final_file_path = switch_core_sprintf(pool, "%s%srecorded_name.%s", dir_path, SWITCH_PATH_SEPARATOR, profile->file_ext);
|
||||
|
||||
if (switch_file_exists(file_path, pool) != SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR Filename doesn't exist\n");
|
||||
profile_rwunlock(profile);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_file_rename(file_path, final_file_path, pool);
|
||||
|
||||
}
|
||||
profile_rwunlock(profile);
|
||||
stream->write_function(stream, "-OK\n");
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_PREF_PASSWORD_SET_USAGE "<profile> <domain> <user> <password>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_pref_password_set_function)
|
||||
{
|
||||
const char *password = NULL;
|
||||
|
||||
char *sql = NULL;
|
||||
char res[254] = "";
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
password = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id || !password) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("SELECT count(*) FROM voicemail_prefs WHERE username = '%q' AND domain = '%q'", id, domain);
|
||||
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, password) VALUES('%q', '%q', '%q')", id, domain, password);
|
||||
} else {
|
||||
sql = switch_mprintf("UPDATE voicemail_prefs SET password = '%q' WHERE username = '%q' AND domain = '%q'", password, id, domain);
|
||||
}
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
switch_safe_free(sql);
|
||||
profile_rwunlock(profile);
|
||||
|
||||
stream->write_function(stream, "-OK\n");
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Message API */
|
||||
|
||||
#define VM_FSDB_MSG_LIST_USAGE "<format> <profile> <domain> <user>"
|
||||
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;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[1])
|
||||
profile_name = argv[1];
|
||||
if (argv[2])
|
||||
domain = argv[2];
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
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);
|
||||
|
||||
memset(&cbt, 0, sizeof(cbt));
|
||||
|
||||
switch_event_create(&cbt.my_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, message_list_callback, &cbt);
|
||||
|
||||
profile_rwunlock(profile);
|
||||
|
||||
switch_event_add_header(cbt.my_params, SWITCH_STACK_BOTTOM, "VM-List-Count", "%"SWITCH_SIZE_T_FMT, cbt.len);
|
||||
switch_event_serialize_json(cbt.my_params, &ebuf);
|
||||
switch_event_destroy(&cbt.my_params);
|
||||
|
||||
switch_safe_free(sql);
|
||||
stream->write_function(stream, "%s", ebuf);
|
||||
switch_safe_free(ebuf);
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_PURGE_USAGE "<profile> <domain> <user>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_purge_function)
|
||||
{
|
||||
char *sql;
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
|
||||
if (!profile_name || !domain || !id) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("SELECT '%q', uuid, username, domain, file_path FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND flags = 'delete'", profile_name, id, domain);
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, message_purge_callback, NULL);
|
||||
profile_rwunlock(profile);
|
||||
|
||||
stream->write_function(stream, "-OK\n");
|
||||
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_DELETE_USAGE "<profile> <domain> <user> <uuid>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_delete_function)
|
||||
{
|
||||
char *sql;
|
||||
const char *uuid = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
uuid = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id || !uuid) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("UPDATE voicemail_msgs SET flags = 'delete' WHERE username = '%q' AND domain = '%q' AND uuid = '%q'", id, domain, uuid);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
profile_rwunlock(profile);
|
||||
|
||||
stream->write_function(stream, "-OK\n");
|
||||
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_SAVE_USAGE "<profile> <domain> <user> <uuid>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_save_function)
|
||||
{
|
||||
char *sql;
|
||||
const char *uuid = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
uuid = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id || !uuid) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("UPDATE voicemail_msgs SET flags='save' WHERE username='%q' AND domain='%q' AND uuid = '%q'", id, domain, uuid);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
profile_rwunlock(profile);
|
||||
|
||||
stream->write_function(stream, "-OK\n");
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_UNDELETE_USAGE "<profile> <domain> <user> <uuid>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_undelete_function)
|
||||
{
|
||||
char *sql;
|
||||
const char *uuid = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
uuid = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id || !uuid) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("UPDATE voicemail_msgs SET flags='' WHERE username='%q' AND domain='%q' AND uuid = '%q'", id, domain, uuid);
|
||||
vm_execute_sql(profile, sql, profile->mutex);
|
||||
profile_rwunlock(profile);
|
||||
|
||||
stream->write_function(stream, "-OK\n");
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_AUTH_LOGIN_USAGE "<profile> <domain> <user> <password>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_auth_login_function)
|
||||
{
|
||||
char *sql;
|
||||
char *password = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
char user_db_password[64] = { 0 };
|
||||
const char *user_xml_password = NULL;
|
||||
|
||||
switch_event_t *params = NULL;
|
||||
switch_xml_t x_user = NULL;
|
||||
switch_bool_t vm_enabled = SWITCH_TRUE;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[0])
|
||||
profile_name = argv[0];
|
||||
if (argv[1])
|
||||
domain = argv[1];
|
||||
if (argv[2])
|
||||
id = argv[2];
|
||||
if (argv[3])
|
||||
password = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id || !password) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_event_create(¶ms, SWITCH_EVENT_GENERAL);
|
||||
if (switch_xml_locate_user_merged("id", id, domain, NULL, &x_user, params) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Can't find user [%s@%s]\n", id, domain);
|
||||
stream->write_function(stream, "-ERR User not found\n");
|
||||
} else {
|
||||
switch_xml_t x_param, x_params;
|
||||
|
||||
x_params = switch_xml_child(x_user, "params");
|
||||
|
||||
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
|
||||
const char *var = switch_xml_attr_soft(x_param, "name");
|
||||
const char *val = switch_xml_attr_soft(x_param, "value");
|
||||
if (zstr(var) || zstr(val)) {
|
||||
continue; /* Ignore empty entires */
|
||||
}
|
||||
|
||||
if (!strcasecmp(var, "vm-enabled")) {
|
||||
vm_enabled = !switch_false(val);
|
||||
}
|
||||
if (!strcasecmp(var, "vm-password")) {
|
||||
user_xml_password = val;
|
||||
}
|
||||
}
|
||||
|
||||
sql = switch_mprintf("SELECT password FROM voicemail_prefs WHERE username = '%q' AND domain = '%q'", id, domain);
|
||||
vm_execute_sql2str(profile, profile->mutex, sql, user_db_password, sizeof(user_db_password));
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
if (vm_enabled == SWITCH_FALSE) {
|
||||
stream->write_function(stream, "%s", "-ERR Login Denied");
|
||||
} else if (!zstr(user_db_password)) {
|
||||
if (!strcasecmp(user_db_password, password)) {
|
||||
stream->write_function(stream, "%s", "-OK");
|
||||
} else {
|
||||
stream->write_function(stream, "%s", "-ERR");
|
||||
}
|
||||
} else if (!zstr(user_xml_password)) {
|
||||
if (!strcasecmp(user_xml_password, password)) {
|
||||
stream->write_function(stream, "%s", "-OK");
|
||||
} else {
|
||||
stream->write_function(stream, "%s", "-ERR");
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "%s", "-ERR");
|
||||
|
||||
}
|
||||
|
||||
switch_xml_free(x_user);
|
||||
profile_rwunlock(profile);
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_GET_USAGE "<format> <profile> <domain> <user> <uuid>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_get_function)
|
||||
{
|
||||
char *sql;
|
||||
msg_get_callback_t cbt = { 0 };
|
||||
char *ebuf = NULL;
|
||||
char *uuid = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[1])
|
||||
profile_name = argv[1];
|
||||
if (argv[2])
|
||||
domain = argv[2];
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
if (argv[4])
|
||||
uuid = argv[4];
|
||||
|
||||
if (!profile_name || !domain || !id || !uuid) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("SELECT * FROM voicemail_msgs WHERE username = '%q' AND domain = '%q' AND uuid = '%q' ORDER BY read_flags, created_epoch", id, domain, uuid);
|
||||
|
||||
memset(&cbt, 0, sizeof(cbt));
|
||||
|
||||
switch_event_create(&cbt.my_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, message_get_callback, &cbt);
|
||||
|
||||
profile_rwunlock(profile);
|
||||
|
||||
switch_event_serialize_json(cbt.my_params, &ebuf);
|
||||
switch_event_destroy(&cbt.my_params);
|
||||
|
||||
switch_safe_free(sql);
|
||||
stream->write_function(stream, "%s", ebuf);
|
||||
switch_safe_free(ebuf);
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define VM_FSDB_MSG_COUNT_USAGE "<format> <profile> <domain> <user>"
|
||||
SWITCH_STANDARD_API(vm_fsdb_msg_count_function)
|
||||
{
|
||||
char *sql;
|
||||
msg_cnt_callback_t cbt = { 0 };
|
||||
switch_event_t *my_params = NULL;
|
||||
char *ebuf = NULL;
|
||||
|
||||
const char *id = NULL, *domain = NULL, *profile_name = NULL;
|
||||
vm_profile_t *profile = NULL;
|
||||
|
||||
char *argv[6] = { 0 };
|
||||
char *mycmd = NULL;
|
||||
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = switch_core_strdup(pool, cmd);
|
||||
switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argv[1])
|
||||
profile_name = argv[1];
|
||||
if (argv[2])
|
||||
domain = argv[2];
|
||||
if (argv[3])
|
||||
id = argv[3];
|
||||
|
||||
if (!profile_name || !domain || !id) {
|
||||
stream->write_function(stream, "-ERR Missing Arguments\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(profile = get_profile(profile_name))) {
|
||||
stream->write_function(stream, "-ERR Profile not found\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
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 "
|
||||
"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");
|
||||
|
||||
|
||||
vm_execute_sql_callback(profile, profile->mutex, sql, message_count_callback, &cbt);
|
||||
|
||||
profile_rwunlock(profile);
|
||||
|
||||
switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_event_add_header(my_params, SWITCH_STACK_BOTTOM, "VM-Total-New-Messages", "%d", cbt.total_new_messages + cbt.total_new_urgent_messages);
|
||||
switch_event_add_header(my_params, SWITCH_STACK_BOTTOM, "VM-Total-New-Urgent-Messages", "%d", cbt.total_new_urgent_messages);
|
||||
switch_event_add_header(my_params, SWITCH_STACK_BOTTOM, "VM-Total-Saved-Messages", "%d", cbt.total_saved_messages + cbt.total_saved_urgent_messages);
|
||||
switch_event_add_header(my_params, SWITCH_STACK_BOTTOM, "VM-Total-Saved-Urgent-Messages", "%d", cbt.total_saved_urgent_messages);
|
||||
switch_event_serialize_json(my_params, &ebuf);
|
||||
switch_event_destroy(&my_params);
|
||||
|
||||
switch_safe_free(sql);
|
||||
stream->write_function(stream, "%s", ebuf);
|
||||
switch_safe_free(ebuf);
|
||||
done:
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
@@ -4520,6 +5336,23 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_read", "vm_read", voicemail_read_api_function, VM_READ_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_list", "vm_list", voicemail_list_api_function, VM_LIST_USAGE);
|
||||
|
||||
/* Auth API */
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_auth_login", "vm_fsdb_auth_login", vm_fsdb_auth_login_function, VM_FSDB_AUTH_LOGIN_USAGE);
|
||||
|
||||
/* Message Targeted API */
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_count", "vm_fsdb_msg_count", vm_fsdb_msg_count_function, VM_FSDB_MSG_COUNT_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_list", "vm_fsdb_msg_list", vm_fsdb_msg_list_function, VM_FSDB_MSG_LIST_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_get", "vm_fsdb_msg_get", vm_fsdb_msg_get_function, VM_FSDB_MSG_GET_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_delete", "vm_fsdb_msg_delete", vm_fsdb_msg_delete_function, VM_FSDB_MSG_DELETE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_undelete", "vm_fsdb_msg_undelete", vm_fsdb_msg_undelete_function, VM_FSDB_MSG_UNDELETE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_purge", "vm_fsdb_msg_purge", vm_fsdb_msg_purge_function, VM_FSDB_MSG_PURGE_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_msg_save", "vm_fsdb_msg_save", vm_fsdb_msg_save_function, VM_FSDB_MSG_SAVE_USAGE);
|
||||
|
||||
/* Preferences */
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_pref_greeting_set", "vm_fsdb_pref_greeting_set", vm_fsdb_pref_greeting_set_function, VM_FSDB_PREF_GREETING_SET_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_pref_recname_set", "vm_fsdb_pref_recname_set", vm_fsdb_pref_recname_set_function, VM_FSDB_PREF_RECNAME_SET_USAGE);
|
||||
SWITCH_ADD_API(commands_api_interface, "vm_fsdb_pref_password_set", "vm_fsdb_pref_password_set", vm_fsdb_pref_password_set_function, VM_FSDB_PREF_PASSWORD_SET_USAGE);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,14 @@ typedef struct {
|
||||
} cepstral_t;
|
||||
|
||||
|
||||
static struct {
|
||||
char *encoding;
|
||||
} globals;
|
||||
|
||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_encoding, globals.encoding);
|
||||
|
||||
|
||||
|
||||
/* This callback caches the audio in the buffer */
|
||||
static swift_result_t write_audio(swift_event * event, swift_event_t type, void *udata)
|
||||
{
|
||||
@@ -223,7 +231,7 @@ static switch_status_t cepstral_speech_feed_tts(switch_speech_handle_t *sh, char
|
||||
if (zstr(text)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
swift_port_speak_file(cepstral->port, text, NULL, &cepstral->tts_stream, NULL);
|
||||
swift_port_speak_file(cepstral->port, text, globals.encoding, &cepstral->tts_stream, NULL);
|
||||
} else {
|
||||
char *to_say;
|
||||
if (zstr(text)) {
|
||||
@@ -231,7 +239,7 @@ static switch_status_t cepstral_speech_feed_tts(switch_speech_handle_t *sh, char
|
||||
}
|
||||
|
||||
if ((to_say = switch_mprintf("<break time=\"1000ms\"/> %s <break time=\"1000ms\"/>", text))) {
|
||||
swift_port_speak_text(cepstral->port, to_say, 0, NULL, &cepstral->tts_stream, NULL);
|
||||
swift_port_speak_text(cepstral->port, to_say, 0, globals.encoding, &cepstral->tts_stream, NULL);
|
||||
switch_safe_free(to_say);
|
||||
}
|
||||
}
|
||||
@@ -401,10 +409,54 @@ static void cepstral_float_param_tts(switch_speech_handle_t *sh, char *param, do
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t load_config(void)
|
||||
{
|
||||
char *cf = "cepstral.conf";
|
||||
switch_xml_t cfg, xml = NULL, param, settings;
|
||||
|
||||
/* Init to SWIFT default encoding */
|
||||
set_global_encoding(SWIFT_DEFAULT_ENCODING);
|
||||
|
||||
if (xml = switch_xml_open_cfg(cf, &cfg, NULL)) {
|
||||
if ((settings = switch_xml_child(cfg, "settings"))) {
|
||||
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
if (!strcasecmp(var, "encoding")) {
|
||||
if (!strcasecmp(val, "utf-8")) {
|
||||
set_global_encoding(SWIFT_UTF8);
|
||||
} else if (!strcasecmp(val, "us-ascii")) {
|
||||
set_global_encoding(SWIFT_ASCII);
|
||||
} else if (!strcasecmp(val, "iso8859-1")) {
|
||||
set_global_encoding(SWIFT_ISO_8859_1);
|
||||
} else if (!strcasecmp(val, "iso8859-15")) {
|
||||
set_global_encoding(SWIFT_ISO_8859_15);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown value \"%s\" for param \"%s\". Setting to default.\n", val, var);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Param \"%s\" unknown\n", var);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Open of \"%s\" failed. Using default settings.\n", cf);
|
||||
}
|
||||
|
||||
if (xml) {
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_cepstral_load)
|
||||
{
|
||||
switch_speech_interface_t *speech_interface;
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
load_config();
|
||||
|
||||
/* Open the Swift TTS Engine */
|
||||
if (!(engine = swift_engine_open(NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Engine.");
|
||||
|
||||
@@ -3161,12 +3161,15 @@ static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_
|
||||
if (schannel != NULL && !switch_test_flag(ah, SWITCH_ASR_FLAG_CLOSED)) {
|
||||
r = (recognizer_data_t *) schannel->data;
|
||||
speech_channel_stop(schannel);
|
||||
speech_channel_destroy(schannel);
|
||||
switch_core_hash_destroy(&r->grammars);
|
||||
switch_core_hash_destroy(&r->enabled_grammars);
|
||||
switch_mutex_lock(schannel->mutex);
|
||||
if (r->dtmf_generator) {
|
||||
r->dtmf_generator_active = 0;
|
||||
mpf_dtmf_generator_destroy(r->dtmf_generator);
|
||||
}
|
||||
switch_mutex_unlock(schannel->mutex);
|
||||
speech_channel_destroy(schannel);
|
||||
}
|
||||
/* this lets FreeSWITCH's speech_thread know the handle is closed */
|
||||
switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED);
|
||||
@@ -3366,7 +3369,7 @@ static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp
|
||||
speech_channel_set_state(schannel, SPEECH_CHANNEL_PROCESSING);
|
||||
} else if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
|
||||
/* RECOGNIZE failed to start */
|
||||
if (recog_hdr->completion_cause == RECOGNIZER_COMPLETION_CAUSE_UNKNOWN) {
|
||||
if (!recog_hdr || recog_hdr->completion_cause == RECOGNIZER_COMPLETION_CAUSE_UNKNOWN) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) RECOGNIZE failed: status = %d\n", schannel->name,
|
||||
message->start_line.status_code);
|
||||
} else {
|
||||
@@ -3502,13 +3505,15 @@ static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *fra
|
||||
}
|
||||
frame->type |= MEDIA_FRAME_TYPE_AUDIO;
|
||||
}
|
||||
|
||||
|
||||
switch_mutex_lock(schannel->mutex);
|
||||
if (r->dtmf_generator_active) {
|
||||
if (!mpf_dtmf_generator_put_frame(r->dtmf_generator, frame)) {
|
||||
if (!mpf_dtmf_generator_sending(r->dtmf_generator))
|
||||
r->dtmf_generator_active = 0;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(schannel->mutex);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -21,3 +21,4 @@ $(CELT_LA): $(CELT_BUILDDIR)/Makefile
|
||||
cd $(CELT_BUILDDIR) && $(MAKE)
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(MODNAME).lo: $(CELT_LA)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
|
||||
MODNAME=mod_com_g729
|
||||
VERSION=193
|
||||
VERSION=194
|
||||
|
||||
if ISLINUX
|
||||
|
||||
|
||||
@@ -250,7 +250,6 @@ static switch_status_t switch_dahdi_encode(switch_codec_t *codec,
|
||||
{
|
||||
int32_t res;
|
||||
short *dbuf_linear;
|
||||
unsigned char *ebuf_g729;
|
||||
unsigned char ebuf_ulaw[decoded_data_len / 2];
|
||||
uint32_t i;
|
||||
struct dahdi_context *context = NULL;
|
||||
@@ -268,7 +267,6 @@ static switch_status_t switch_dahdi_encode(switch_codec_t *codec,
|
||||
}
|
||||
|
||||
dbuf_linear = decoded_data;
|
||||
ebuf_g729 = encoded_data;
|
||||
for (i = 0; i < decoded_data_len / sizeof(short); i++) {
|
||||
ebuf_ulaw[i] = linear_to_ulaw(dbuf_linear[i]);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ OPUS_DIR=$(switch_srcdir)/libs/$(OPUS)
|
||||
OPUS_BUILDDIR=$(switch_builddir)/libs/$(OPUS)
|
||||
LOCAL_CFLAGS=-I$(OPUS_DIR)/src -g -O2
|
||||
|
||||
IETF_LA=$(OPUS_BUILDDIR)/src/.libs/libietfcodec.a
|
||||
CELT_LA=$(OPUS_BUILDDIR)/celt/libcelt/.libs/libcelt0.a
|
||||
SILK_LA=$(OPUS_BUILDDIR)/silk/.libs/libSKP_SILK_SDK.a
|
||||
IETF_LA=$(OPUS_BUILDDIR)/src/libietfcodec.la
|
||||
CELT_LA=$(OPUS_BUILDDIR)/celt/libcelt/libcelt0.la
|
||||
SILK_LA=$(OPUS_BUILDDIR)/silk/libSKP_SILK_SDK.la
|
||||
|
||||
LOCAL_LIBADD=$(IETF_LA) $(CELT_LA) $(SILK_LA) -lm -lz
|
||||
|
||||
@@ -26,3 +26,7 @@ $(IETF_LA): $(OPUS_BUILDDIR)/Makefile
|
||||
cd $(OPUS_BUILDDIR) && $(MAKE)
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(CELT_LA): $(IETF_LA)
|
||||
$(SILK_LA): $(IETF_LA)
|
||||
|
||||
$(MODNAME).lo: $(IETF_LA) $(CELT_LA) $(SILK_LA)
|
||||
|
||||
@@ -89,14 +89,14 @@ vocallo_codec_t g_codec_map[] =
|
||||
{ SNGTC_CODEC_PCMA, IANA_PCMA_A_8000_1, "PCMA", "Sangoma PCMA", 40, 64000, 10000, 80, 160, 80, 8000, 8000, 1 },
|
||||
{ SNGTC_CODEC_L16_1, IANA_L16_A_8000_1, "L16", "Sangoma L16", 40, 120000, 10000, 80, 160, 160, 8000, 8000, 0 },
|
||||
{ SNGTC_CODEC_L16_2, IANA_L16_A_16000_1, "L16", "Sangoma L16 2", 40, 320000, 10000, 160, 320, 320, 16000, 16000, 0 },
|
||||
{ SNGTC_CODEC_G729AB, IANA_G729_AB_8000_1, "G729", "Sangoma G729", 40, 8000, 10000, 80, 160, 10, 8000, 8000, 1 },
|
||||
{ SNGTC_CODEC_G729AB, IANA_G729_AB_8000_1, "G729", "Sangoma G729", 200, 8000, 10000, 80, 160, 10, 8000, 8000, 1 },
|
||||
{ SNGTC_CODEC_G726_32, IANA_G726_32_8000_1, "G726-32", "Sangoma G.726 32k", 40, 32000, 10000, 80, 160, 40, 8000, 8000, 1 },
|
||||
{ SNGTC_CODEC_G722, IANA_G722_A_8000_1, "G722", "Sangoma G722", 20, 64000, 10000, 80, 160, 80, 8000, 8000, 1 },
|
||||
|
||||
/* manually initialized */
|
||||
{ SNGTC_CODEC_GSM_FR, IANA_GSM_A_8000_1, "GSM", "Sangoma GSM", 20, 13200, 20000, 160, 320, 33, 8000, 8000, 0 },
|
||||
{ SNGTC_CODEC_G723_1_63, IANA_G723_A_8000_1, "G723", "Sangoma G723", 90, 6300, 30000, 240, 480, 24, 8000, 8000, 0 },
|
||||
{ SNGTC_CODEC_AMR_1220, IANA_AMR_WB_16000_1, "AMR", "Sangoma AMR", 20, 12200, 20000, 160, 320, 0, 8000, 8000, 0 },
|
||||
{ SNGTC_CODEC_AMR_1220, IANA_AMR_A_8000_1, "AMR", "Sangoma AMR", 20, 12200, 20000, 160, 320, 0, 8000, 8000, 0 },
|
||||
{ SNGTC_CODEC_SIREN7_24, IANA_SIREN7, "G7221", "Sangoma G722.1", 20, 24000, 20000, 320, 640, 60, 16000, 16000, 0 },
|
||||
{ SNGTC_CODEC_SIREN7_32, IANA_SIREN7, "G7221", "Sangoma G722.1", 20, 32000, 20000, 320, 640, 80, 16000, 16000, 0 },
|
||||
{ SNGTC_CODEC_ILBC_133, IANA_ILBC_133_8000_1, "iLBC", "Sangoma iLBC", 30, 13300, 30000, 240, 480, 50, 8000, 8000, 0 },
|
||||
@@ -131,6 +131,7 @@ struct codec_data {
|
||||
/* packet counters */
|
||||
unsigned long tx;
|
||||
unsigned long rx;
|
||||
unsigned long ticks;
|
||||
|
||||
/* Lost packets */
|
||||
long lastrxseqno;
|
||||
@@ -467,6 +468,8 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec
|
||||
func_start_time = switch_micro_time_now();
|
||||
}
|
||||
|
||||
sess->encoder.ticks++;
|
||||
|
||||
/* start assuming we will not encode anything */
|
||||
*encoded_data_len = 0;
|
||||
|
||||
@@ -547,7 +550,7 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec
|
||||
continue;
|
||||
}
|
||||
|
||||
if (encoded_frame.datalen != codec->implementation->encoded_bytes_per_packet) {
|
||||
if (codec->implementation->encoded_bytes_per_packet && encoded_frame.datalen != codec->implementation->encoded_bytes_per_packet) {
|
||||
/* seen when silence suppression is enabled */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring encoded frame of %d bytes intead of %d bytes\n", encoded_frame.datalen, codec->implementation->encoded_bytes_per_packet);
|
||||
continue;
|
||||
@@ -619,7 +622,7 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec
|
||||
sess->encoder.rtp_queue[sess->encoder.queue_rindex].datalen = 0;
|
||||
SAFE_INDEX_INC(sess->encoder.rtp_queue, sess->encoder.queue_rindex);
|
||||
sess->encoder.queue_size--;
|
||||
if (*encoded_data_len != codec->implementation->encoded_bytes_per_packet) {
|
||||
if (codec->implementation->encoded_bytes_per_packet && *encoded_data_len != codec->implementation->encoded_bytes_per_packet) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Returning odd encoded frame of %d bytes intead of %d bytes\n", *encoded_data_len, codec->implementation->encoded_bytes_per_packet);
|
||||
}
|
||||
} else {
|
||||
@@ -667,6 +670,7 @@ static switch_status_t switch_sangoma_decode(switch_codec_t *codec, /* codec ses
|
||||
}
|
||||
|
||||
dbuf_linear = decoded_data;
|
||||
sess->decoder.ticks++;
|
||||
|
||||
/* start assuming we will not decode anything */
|
||||
*decoded_data_len = 0;
|
||||
@@ -989,6 +993,7 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
stream->write_function(stream, "Rx %s at %d.%d.%d.%d:%d from %d.%d.%d.%d:%d\n\n", sess->impl->iananame, SNGTC_NIPV4(sess->encoder.reply.b.host_ip), sess->encoder.reply.b.host_udp_port,
|
||||
SNGTC_NIPV4(sess->encoder.reply.b.codec_ip), sess->encoder.reply.b.codec_udp_port);
|
||||
|
||||
stream->write_function(stream, "Ticks: %lu\n", sess->encoder.ticks);
|
||||
|
||||
stream->write_function(stream, "-- Inbound Stats --\n");
|
||||
stream->write_function(stream, "Rx Discarded: %lu\n", sess->encoder.rxdiscarded);
|
||||
@@ -1008,6 +1013,7 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
SNGTC_NIPV4(sess->decoder.reply.a.codec_ip), sess->decoder.reply.a.codec_udp_port);
|
||||
stream->write_function(stream, "Rx L16 at %d.%d.%d.%d:%d from %d.%d.%d.%d:%d\n\n", SNGTC_NIPV4(sess->decoder.reply.b.host_ip), sess->decoder.reply.b.host_udp_port,
|
||||
SNGTC_NIPV4(sess->decoder.reply.b.codec_ip), sess->decoder.reply.b.codec_udp_port);
|
||||
stream->write_function(stream, "Ticks: %lu\n", sess->decoder.ticks);
|
||||
|
||||
stream->write_function(stream, "-- Inbound Stats --\n");
|
||||
stream->write_function(stream, "Rx Discarded: %lu\n", sess->decoder.rxdiscarded);
|
||||
|
||||
@@ -164,7 +164,6 @@ SWITCH_STANDARD_DIALPLAN(asterisk_dialplan_hunt)
|
||||
int argc;
|
||||
char *argv[3] = { 0 };
|
||||
char *pattern = NULL;
|
||||
char *pri = NULL;
|
||||
char *app = NULL;
|
||||
char *argument = NULL;
|
||||
char *expression = NULL, expression_buf[1024] = "";
|
||||
@@ -242,7 +241,7 @@ SWITCH_STANDARD_DIALPLAN(asterisk_dialplan_hunt)
|
||||
switch_channel_set_variable(channel, "CHANNEL", switch_channel_get_name(channel));
|
||||
switch_channel_set_variable(channel, "UNIQUEID", switch_core_session_get_uuid(session));
|
||||
|
||||
pri = argv[1];
|
||||
//pri = argv[1];
|
||||
app = argv[2];
|
||||
|
||||
if ((argument = strchr(app, '('))) {
|
||||
|
||||
@@ -222,6 +222,11 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *
|
||||
proceed = 1;
|
||||
}
|
||||
} else {
|
||||
if (field && strchr(expression, '(')) {
|
||||
switch_channel_set_variable(channel, "DP_MATCH", NULL);
|
||||
switch_capture_regex(re, proceed, field_data, ovector, "DP_MATCH", (switch_cap_callback_t)switch_regex_set_var_callback, session);
|
||||
}
|
||||
|
||||
for (xaction = switch_xml_child(xcond, "action"); xaction; xaction = xaction->next) {
|
||||
char *application = (char *) switch_xml_attr_soft(xaction, "application");
|
||||
const char *loop = switch_xml_attr(xaction, "loop");
|
||||
|
||||
@@ -10,8 +10,10 @@ DING_DIR=$(BASE)/libs/libdingaling
|
||||
LOCAL_CFLAGS += -I$(DING_DIR)/src -I$(BASE)/libs/iksemel/include
|
||||
LOCAL_OBJS=$(DING_DIR)/src/libdingaling.o $(DING_DIR)/src/sha1.o $(IKS_LA)
|
||||
LOCAL_SOURCES=$(DING_DIR)/src/libdingaling.c $(DING_DIR)/src/sha1.c
|
||||
LOCAL_LDFLAGS=$(LIBGNUTLS_LIBS)
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
|
||||
$(IKS_LA): $(IKS_DIR) $(IKS_DIR)/.update
|
||||
@cd $(IKS_DIR) && $(MAKE)
|
||||
@$(TOUCH_TARGET)
|
||||
|
||||
@@ -65,19 +65,20 @@ typedef enum {
|
||||
TFLAG_CODEC_READY = (1 << 8),
|
||||
TFLAG_TRANSPORT = (1 << 9),
|
||||
TFLAG_ANSWER = (1 << 10),
|
||||
TFLAG_VAD_IN = (1 << 11),
|
||||
TFLAG_VAD_OUT = (1 << 12),
|
||||
TFLAG_VAD = (1 << 13),
|
||||
TFLAG_DO_CAND = (1 << 14),
|
||||
TFLAG_DO_DESC = (1 << 15),
|
||||
TFLAG_LANADDR = (1 << 16),
|
||||
TFLAG_AUTO = (1 << 17),
|
||||
TFLAG_DTMF = (1 << 18),
|
||||
TFLAG_TIMER = (1 << 19),
|
||||
TFLAG_TERM = (1 << 20),
|
||||
TFLAG_TRANSPORT_ACCEPT = (1 << 21),
|
||||
TFLAG_READY = (1 << 22),
|
||||
TFLAG_NAT_MAP = (1 << 22)
|
||||
TFLAG_VAD_NONE = (1 << 11),
|
||||
TFLAG_VAD_IN = (1 << 12),
|
||||
TFLAG_VAD_OUT = (1 << 13),
|
||||
TFLAG_VAD = (1 << 14),
|
||||
TFLAG_DO_CAND = (1 << 15),
|
||||
TFLAG_DO_DESC = (1 << 16),
|
||||
TFLAG_LANADDR = (1 << 17),
|
||||
TFLAG_AUTO = (1 << 18),
|
||||
TFLAG_DTMF = (1 << 19),
|
||||
TFLAG_TIMER = (1 << 20),
|
||||
TFLAG_TERM = (1 << 21),
|
||||
TFLAG_TRANSPORT_ACCEPT = (1 << 22),
|
||||
TFLAG_READY = (1 << 23),
|
||||
TFLAG_NAT_MAP = (1 << 24)
|
||||
} TFLAGS;
|
||||
|
||||
typedef enum {
|
||||
@@ -966,7 +967,7 @@ static int do_candidates(struct private_object *tech_pvt, int force)
|
||||
if (force || !switch_test_flag(tech_pvt, TFLAG_RTP_READY)) {
|
||||
ldl_candidate_t cand[1];
|
||||
char *advip = tech_pvt->profile->extip ? tech_pvt->profile->extip : tech_pvt->profile->ip;
|
||||
char *err = NULL;
|
||||
char *err = NULL, *address = NULL;
|
||||
|
||||
memset(cand, 0, sizeof(cand));
|
||||
switch_stun_random_string(tech_pvt->local_user, 16, NULL);
|
||||
@@ -975,10 +976,14 @@ static int do_candidates(struct private_object *tech_pvt, int force)
|
||||
if (switch_test_flag(tech_pvt, TFLAG_LANADDR)) {
|
||||
advip = tech_pvt->profile->ip;
|
||||
}
|
||||
address = advip;
|
||||
|
||||
if(address && !strncasecmp(address, "host:", 5)) {
|
||||
address = address + 5;
|
||||
}
|
||||
|
||||
cand[0].port = tech_pvt->adv_local_port;
|
||||
cand[0].address = advip;
|
||||
cand[0].address = address;
|
||||
|
||||
if (!strncasecmp(advip, "stun:", 5)) {
|
||||
char *stun_ip = advip + 5;
|
||||
@@ -1394,7 +1399,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
{
|
||||
struct private_object *tech_pvt = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
int payload = 0;
|
||||
//int payload = 0;
|
||||
|
||||
tech_pvt = (struct private_object *) switch_core_session_get_private(session);
|
||||
switch_assert(tech_pvt != NULL);
|
||||
@@ -1438,7 +1443,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
|
||||
|
||||
|
||||
payload = tech_pvt->read_frame.payload;
|
||||
//payload = tech_pvt->read_frame.payload;
|
||||
|
||||
#if 0
|
||||
elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000);
|
||||
@@ -1568,22 +1573,8 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
|
||||
channel_answer_channel(session);
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_BRIDGE:
|
||||
/*
|
||||
if (tech_pvt->rtp_session && switch_test_flag(tech_pvt->profile, TFLAG_TIMER)) {
|
||||
switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "De-activate timed RTP!\n");
|
||||
//switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_TIMER_RECLOCK);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
|
||||
/*
|
||||
if (tech_pvt->rtp_session && switch_test_flag(tech_pvt->profile, TFLAG_TIMER)) {
|
||||
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n");
|
||||
//switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_TIMER_RECLOCK);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2110,8 +2101,10 @@ static void set_profile_val(mdl_profile_t *profile, char *var, char *val)
|
||||
} else if (!strcasecmp(val, "both")) {
|
||||
switch_set_flag(profile, TFLAG_VAD_IN);
|
||||
switch_set_flag(profile, TFLAG_VAD_OUT);
|
||||
} else if (!strcasecmp(val, "none")) {
|
||||
switch_set_flag(profile, TFLAG_VAD_NONE);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid option %s for VAD\n", val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,24 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_gsmopen
|
||||
|
||||
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
|
||||
|
||||
SPANDSP_DIR=$(switch_srcdir)/libs/spandsp
|
||||
SPANDSP_BUILDDIR=$(switch_builddir)/libs/spandsp
|
||||
SPANDSP_LA=$(SPANDSP_BUILDDIR)/src/libspandsp.la
|
||||
|
||||
mod_LTLIBRARIES = mod_gsmopen.la
|
||||
mod_gsmopen_la_SOURCES = mod_gsmopen.cpp gsmopen_protocol.cpp
|
||||
mod_gsmopen_la_CFLAGS = $(AM_CFLAGS) -DGSMOPEN_SVN_VERSION=\"`cat $(switch_builddir)/.version`\"
|
||||
mod_gsmopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_gsmopen_la_LDFLAGS = -avoid-version -module -no-undefined -lasound -lgsmme -lspandsp
|
||||
mod_gsmopen_la_CFLAGS = $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff -I. -DGSMOPEN_SVN_VERSION=\"`cat $(switch_builddir)/.version`\"
|
||||
mod_gsmopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA)
|
||||
mod_gsmopen_la_LDFLAGS = -avoid-version -module -no-undefined -lasound -lgsmme
|
||||
|
||||
$(SPANDSP_LA): $(TIFF_LA) $(SPANDSP_DIR) $(SPANDSP_DIR)/.update
|
||||
cd $(SPANDSP_BUILDDIR) && $(MAKE) -j1
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(TIFF_LA): $(TIFF_DIR) $(TIFF_DIR)/.update
|
||||
cd $(TIFF_BUILDDIR) && $(MAKE) -j1
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
@@ -1,13 +1 @@
|
||||
faststart and codecs v CallProceeding due to h323plus, grep "Very Frustrating - S.H." in h323plus
|
||||
source and uncomment commented lines.
|
||||
|
||||
|
||||
exploration form developer of h323plus:
|
||||
|
||||
Yes that should be mera.
|
||||
|
||||
The problem is that Callproceeding does not always come from the remote it
|
||||
may be generated by the gatekeeper. MERA where sending fast start elements
|
||||
in the Call proceeding and connect. The call proceeding where not valid and
|
||||
causing the media to fail. Normally (although valid) EP's do not set Fast
|
||||
Start in Call proceeding so the code was disabled to resolve the MERA issue.
|
||||
seems none for now
|
||||
@@ -1,3 +1,6 @@
|
||||
make sure dtmfinband gets initialized
|
||||
make gk-identifier and gk-interface settings optional (documentation sayed that about gk-identifier already)
|
||||
fix race condition on destroying signaling thread in h323 library
|
||||
Adds an extra switch_rtp_destroy or switch_rtp_release_port when a session ends
|
||||
- to make sure the port is returned to FS. thx to Peter Olsson.
|
||||
fix issues with Progress message type if pre_answer enabled
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<!-- <param name="ptime-override-value" value="20"/> --> <!-- Override negotiated ptime value with this value -->
|
||||
<param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
|
||||
<param name="gk-identifer" value=""/> <!-- optional name of gk -->
|
||||
<param name="gk-interface" value=""/> <!-- mandatory listener interface name -->
|
||||
<param name="gk-interface" value=""/> <!-- optional UDP listener interface (IP:port) -->
|
||||
<param name="gk-retry" value="30"/> <!-- optional GK register retry timer -->
|
||||
<param name="faststart" value="true"/> <!-- optional -->
|
||||
<param name="h245tunneling" value="true"/> <!-- optional -->
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
* H323 endpoint interface for Freeswitch Modular Media Switching Software Library /
|
||||
* Soft-Switch Application
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* Copyright (c) 2010 Ilnitskiy Mixim (max.h323@gmail.com)
|
||||
* Copyright (c) 2010 Georgiewskiy Yuriy (bottleman@icf.org.ru)
|
||||
*
|
||||
* 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
|
||||
@@ -14,6 +17,12 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jan Willamowius.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
@@ -24,7 +33,7 @@
|
||||
*
|
||||
* mod_h323.cpp -- H323 endpoint
|
||||
*
|
||||
* Version 0.0.56
|
||||
* Version 0.0.57
|
||||
*/
|
||||
|
||||
//#define DEBUG_RTP_PACKETS
|
||||
@@ -215,6 +224,7 @@ class FSTrace : public ostream {
|
||||
public:
|
||||
Buffer()
|
||||
{
|
||||
// leave 2 chars room at end: 1 for overflow char and1 for \0
|
||||
setg(buffer, buffer, &buffer[sizeof(buffer)-2]);
|
||||
setp(buffer, &buffer[sizeof(buffer)-2]);
|
||||
}
|
||||
@@ -432,8 +442,8 @@ bool FSH323EndPoint::Initialise(switch_loadable_module_interface_t *iface)
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_gkAddress.IsEmpty() && !m_gkIdentifer.IsEmpty() && !m_gkInterface.IsEmpty()) {
|
||||
m_thread = new FSGkRegThread(this,&m_gkAddress,&m_gkIdentifer,&m_gkInterface,m_gkretry);
|
||||
if (!m_gkAddress.IsEmpty()) {
|
||||
m_thread = new FSGkRegThread(this, &m_gkAddress, &m_gkIdentifer, &m_gkInterface, m_gkretry);
|
||||
m_thread->SetAutoDelete();
|
||||
m_thread->Resume();
|
||||
}
|
||||
@@ -584,6 +594,7 @@ FSH323EndPoint::FSH323EndPoint()
|
||||
:m_faststart(true)
|
||||
,m_h245tunneling(true)
|
||||
,m_h245insetup(true)
|
||||
,m_dtmfinband(false)
|
||||
,m_thread(NULL)
|
||||
,m_stop_gk(false)
|
||||
,m_fax_old_asn(false)
|
||||
@@ -708,6 +719,7 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran
|
||||
|
||||
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_alloc(m_fsSession, sizeof(*tech_pvt));
|
||||
tech_pvt->me = this;
|
||||
tech_pvt->active_connection = true;
|
||||
switch_core_session_set_private(m_fsSession, tech_pvt);
|
||||
|
||||
switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(m_fsSession));
|
||||
@@ -748,8 +760,9 @@ FSH323Connection::~FSH323Connection()
|
||||
} else if (m_RTPlocalPort) {
|
||||
switch_rtp_release_port((const char *)m_RTPlocalIP.AsString(), m_RTPlocalPort);
|
||||
}
|
||||
|
||||
|
||||
tech_pvt->me = NULL;
|
||||
tech_pvt->active_connection = false;
|
||||
// switch_mutex_unlock(tech_pvt->h323_mutex);
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_unlock\n");
|
||||
}
|
||||
@@ -2387,6 +2400,9 @@ 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);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
* H323 endpoint interface for Freeswitch Modular Media Switching Software Library /
|
||||
* Soft-Switch Application
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* Copyright (c) 2010 Ilnitskiy Mixim (max.h323@gmail.com)
|
||||
* Copyright (c) 2010 Georgiewskiy Yuriy (bottleman@icf.org.ru)
|
||||
*
|
||||
* 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
|
||||
@@ -14,6 +17,11 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
@@ -24,7 +32,8 @@
|
||||
*
|
||||
* mod_h323.h -- H323 endpoint
|
||||
*
|
||||
*/
|
||||
* Version 0.0.57
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
|
||||
#pragma GCC visibility push(default)
|
||||
@@ -184,6 +193,7 @@ typedef struct {
|
||||
switch_mutex_t *h323_io_mutex;
|
||||
|
||||
FSH323Connection *me;
|
||||
bool active_connection;
|
||||
char *token;
|
||||
} h323_private_t;
|
||||
|
||||
|
||||
@@ -41,28 +41,25 @@
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
###############################################################################
|
||||
|
||||
K3L_FILE="k3l_2.1_client.sh"
|
||||
PARAM="0"
|
||||
|
||||
clean()
|
||||
if [ "$1" ]
|
||||
then
|
||||
PARAM=$1
|
||||
fi
|
||||
|
||||
help()
|
||||
{
|
||||
printf "$1"
|
||||
exit 1
|
||||
echo "Usage: getk3l.sh [OPTION]"
|
||||
echo
|
||||
echo " -h, --help print this help"
|
||||
echo " -d, --download only download the k3l package withou doing the installation"
|
||||
echo
|
||||
}
|
||||
|
||||
if [ `whoami` != 'root' ]
|
||||
then
|
||||
clean "Need to be root\n"
|
||||
fi
|
||||
|
||||
#if [ "w$FREESWITCH_PATH" == "w" ]
|
||||
#then
|
||||
# clean "FreeSWITCH source PATH is needed: \n\tSet \"FREESWITCH_PATH=\"\n"
|
||||
#fi
|
||||
|
||||
if ! which 'kserver' &> /dev/null
|
||||
then
|
||||
echo "k3l will be installed"
|
||||
K3L_FILE="k3l_2.1_client.sh"
|
||||
|
||||
download()
|
||||
{
|
||||
if [ "w`uname -m | grep x86_64`" == "w" ]
|
||||
then
|
||||
echo "Downloading i686 package"
|
||||
@@ -71,23 +68,49 @@ then
|
||||
echo "Downloading x86_64 package"
|
||||
wget -t15 -c --progress=bar:force -O $K3L_FILE.gz http://www.khomp.com.br/binaries/softpbx/freeswitch/k3l_2.1_client_x86-64.sh.gz
|
||||
fi
|
||||
}
|
||||
|
||||
gunzip $K3L_FILE.gz
|
||||
chmod 0755 $K3L_FILE
|
||||
clean()
|
||||
{
|
||||
printf "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
(./$K3L_FILE) || clean "Error on k3l install\n"
|
||||
|
||||
rm $K3L_FILE
|
||||
fi
|
||||
install()
|
||||
{
|
||||
if [ `whoami` != 'root' ]
|
||||
then
|
||||
clean "Need to be root to install !\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "w`kserver --version | grep 2.1`" == "w" ]
|
||||
if ! which 'kserver' &> /dev/null
|
||||
then
|
||||
download
|
||||
gunzip $K3L_FILE.gz
|
||||
chmod 0755 $K3L_FILE
|
||||
(./$K3L_FILE) || clean "Error on k3l install\n"
|
||||
rm $K3L_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
if [ $PARAM == '--help' -o $PARAM == '-h' ]
|
||||
then
|
||||
clean "k3l version 2.1 must be installed: \n\tUninstall the old version of k3l and try again\n"
|
||||
help
|
||||
exit 0
|
||||
elif [ $PARAM == '--download' -o $PARAM == '-d' ]
|
||||
then
|
||||
download
|
||||
exit 0
|
||||
else
|
||||
echo "k3l will be installed"
|
||||
install
|
||||
|
||||
if [ "w`kserver --version | grep 2.1`" == "w" ]
|
||||
then
|
||||
clean "k3l version 2.1 must be installed: \n\tUninstall the old version of k3l and try again\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Successfully installed!"
|
||||
fi
|
||||
|
||||
#make || clean "Error on compilation\n"
|
||||
|
||||
#make install || clean "Error on installation\n"
|
||||
|
||||
echo "Successfully installed!"
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ typedef enum {
|
||||
TFLAG_LINKED = (1 << 0),
|
||||
TFLAG_OUTBOUND = (1 << 1),
|
||||
TFLAG_WRITE = (1 << 2),
|
||||
TFLAG_CNG = (1 << 3),
|
||||
TFLAG_USEME = (1 << 3),
|
||||
TFLAG_BRIDGE = (1 << 4),
|
||||
TFLAG_BOWOUT = (1 << 5),
|
||||
TFLAG_BLEG = (1 << 6),
|
||||
@@ -158,7 +158,7 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
|
||||
|
||||
tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
|
||||
tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
|
||||
//switch_set_flag((&tech_pvt->cng_frame), SFF_CNG);
|
||||
|
||||
tech_pvt->cng_frame.datalen = 2;
|
||||
|
||||
tech_pvt->bowout_frame_count = (tech_pvt->read_codec.implementation->actual_samples_per_second /
|
||||
@@ -297,12 +297,10 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
|
||||
static void do_reset(private_t *tech_pvt)
|
||||
{
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_CNG);
|
||||
|
||||
switch_mutex_lock(tech_pvt->mutex);
|
||||
if (tech_pvt->other_tech_pvt) {
|
||||
switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_CNG);
|
||||
}
|
||||
switch_mutex_unlock(tech_pvt->mutex);
|
||||
}
|
||||
@@ -446,12 +444,6 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int
|
||||
|
||||
switch (sig) {
|
||||
case SWITCH_SIG_BREAK:
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_CNG);
|
||||
switch_mutex_lock(tech_pvt->mutex);
|
||||
if (tech_pvt->other_tech_pvt) {
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_CNG);
|
||||
}
|
||||
switch_mutex_unlock(tech_pvt->mutex);
|
||||
break;
|
||||
case SWITCH_SIG_KILL:
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
@@ -583,18 +575,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
tech_pvt->write_frame->codec = &tech_pvt->read_codec;
|
||||
*frame = tech_pvt->write_frame;
|
||||
tech_pvt->packet_count++;
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_CNG);
|
||||
switch_clear_flag(tech_pvt->write_frame, SFF_CNG);
|
||||
} else {
|
||||
switch_set_flag(tech_pvt, TFLAG_CNG);
|
||||
}
|
||||
|
||||
if (switch_test_flag(tech_pvt, TFLAG_CNG)) {
|
||||
*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);
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_CNG);
|
||||
}
|
||||
|
||||
|
||||
@@ -613,6 +599,17 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
return status;
|
||||
}
|
||||
|
||||
static void clear_queue(private_t *tech_pvt)
|
||||
{
|
||||
void *pop;
|
||||
|
||||
while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
switch_frame_t *frame = (switch_frame_t *) pop;
|
||||
switch_frame_free(&frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
|
||||
{
|
||||
switch_channel_t *channel = NULL;
|
||||
@@ -626,7 +623,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
switch_assert(tech_pvt != NULL);
|
||||
|
||||
if (switch_test_flag(frame, SFF_CNG) ||
|
||||
switch_test_flag(tech_pvt, TFLAG_CNG) || (switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
|
||||
(switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
|
||||
switch_core_timer_sync(&tech_pvt->timer);
|
||||
switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -672,23 +669,27 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
|
||||
if (switch_test_flag(tech_pvt, TFLAG_LINKED) && tech_pvt->other_tech_pvt) {
|
||||
switch_frame_t *clone;
|
||||
|
||||
|
||||
if (frame->codec->implementation != tech_pvt->write_codec.implementation) {
|
||||
/* change codecs to match */
|
||||
tech_init(tech_pvt, session, frame->codec);
|
||||
tech_init(tech_pvt->other_tech_pvt, tech_pvt->other_session, frame->codec);
|
||||
}
|
||||
|
||||
if (switch_queue_size(tech_pvt->other_tech_pvt->frame_queue) < FRAME_QUEUE_LEN) {
|
||||
if (switch_frame_dup(frame, &clone) != SWITCH_STATUS_SUCCESS) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_frame_free(&clone);
|
||||
}
|
||||
if (switch_frame_dup(frame, &clone) != SWITCH_STATUS_SUCCESS) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if ((status = switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone)) != SWITCH_STATUS_SUCCESS) {
|
||||
clear_queue(tech_pvt->other_tech_pvt);
|
||||
status = switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone);
|
||||
}
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
|
||||
} else {
|
||||
switch_frame_free(&clone);
|
||||
}
|
||||
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
@@ -747,22 +748,13 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
|
||||
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
|
||||
case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
|
||||
{
|
||||
void *pop;
|
||||
|
||||
done = 1;
|
||||
|
||||
while (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
switch_frame_t *frame = (switch_frame_t *) pop;
|
||||
switch_frame_free(&frame);
|
||||
}
|
||||
|
||||
while (switch_queue_trypop(tech_pvt->other_tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
switch_frame_t *frame = (switch_frame_t *) pop;
|
||||
switch_frame_free(&frame);
|
||||
}
|
||||
|
||||
clear_queue(tech_pvt);
|
||||
clear_queue(tech_pvt->other_tech_pvt);
|
||||
switch_core_timer_sync(&tech_pvt->timer);
|
||||
|
||||
switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1769,14 +1769,14 @@ static switch_status_t load_config(void)
|
||||
if (globals.outdev > -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Switching to default output device\n");
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an input device\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find an output device\n");
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (globals.ringdev < 0) {
|
||||
if (globals.outdev > -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No ring device configured, using output device\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid or no ring device configured, using output device as ring device\n");
|
||||
globals.ringdev = globals.outdev;
|
||||
}
|
||||
}
|
||||
@@ -3107,7 +3107,7 @@ SWITCH_STANDARD_API(pa_cmd)
|
||||
} else if (!strcmp(action, "call")) {
|
||||
switch_snprintf(cmd_buf, sizeof(cmd_buf), "call %s", wcmd);
|
||||
cmd = cmd_buf;
|
||||
} else if (!strcmp(action, "hangup") || !strcmp(action, "list") || !strcmp(action, "answer")) {
|
||||
} else if (!strcmp(action, "hangup") || !strcmp(action, "list") || !strcmp(action, "devlist") || !strcmp(action, "answer")) {
|
||||
cmd = action;
|
||||
}
|
||||
}
|
||||
@@ -3239,6 +3239,7 @@ SWITCH_STANDARD_API(pa_cmd)
|
||||
"<input name=action type=submit value=\"unmute\"> "
|
||||
"<input name=action type=submit value=\"indev\"> "
|
||||
"<input name=action type=submit value=\"outdev\"> "
|
||||
"<input name=action type=submit value=\"devlist\"> <br> "
|
||||
"<input name=action type=submit value=\"preparestream\"> "
|
||||
"<input name=action type=submit value=\"switchstream\"> "
|
||||
"<input name=action type=submit value=\"closestreams\"> "
|
||||
|
||||
@@ -58,7 +58,10 @@ static char devices_sql[] =
|
||||
" type INTEGER,\n"
|
||||
" max_streams INTEGER,\n"
|
||||
" port INTEGER,\n"
|
||||
" codec_string VARCHAR(255)\n"
|
||||
" codec_string VARCHAR(255),\n"
|
||||
" headset INTEGER,\n"
|
||||
" handset INTEGER,\n"
|
||||
" speaker INTEGER\n"
|
||||
");\n";
|
||||
|
||||
static char lines_sql[] =
|
||||
@@ -459,7 +462,6 @@ uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uin
|
||||
|
||||
switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force)
|
||||
{
|
||||
int ms;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
int resetting = 0;
|
||||
|
||||
@@ -539,7 +541,7 @@ switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force)
|
||||
}
|
||||
|
||||
tech_pvt->read_frame.rate = tech_pvt->rm_rate;
|
||||
ms = tech_pvt->write_codec.implementation->microseconds_per_packet / 1000;
|
||||
//ms = tech_pvt->write_codec.implementation->microseconds_per_packet / 1000;
|
||||
|
||||
if (!switch_core_codec_ready(&tech_pvt->read_codec)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
|
||||
@@ -877,7 +879,6 @@ switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
private_t *tech_pvt = switch_core_session_get_private(session);
|
||||
int payload = 0;
|
||||
|
||||
while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
|
||||
if (switch_channel_ready(channel)) {
|
||||
@@ -905,7 +906,7 @@ switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
payload = tech_pvt->read_frame.payload;
|
||||
//payload = tech_pvt->read_frame.payload;
|
||||
|
||||
if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
|
||||
switch_dtmf_t dtmf = { 0 };
|
||||
@@ -1317,6 +1318,9 @@ static int dump_device_callback(void *pArg, int argc, char **argv, char **column
|
||||
char *max_streams = argv[5];
|
||||
char *port = argv[6];
|
||||
char *codec_string = argv[7];
|
||||
char *headset = argv[8];
|
||||
char *handset = argv[9];
|
||||
char *speaker = argv[10];
|
||||
|
||||
const char *line = "=================================================================================================";
|
||||
stream->write_function(stream, "%s\n", line);
|
||||
@@ -1329,6 +1333,12 @@ static int dump_device_callback(void *pArg, int argc, char **argv, char **column
|
||||
stream->write_function(stream, "MaxStreams \t%s\n", max_streams);
|
||||
stream->write_function(stream, "Port \t%s\n", port);
|
||||
stream->write_function(stream, "Codecs \t%s\n", codec_string);
|
||||
stream->write_function(stream, "HeadsetId \t%s\n", headset);
|
||||
stream->write_function(stream, "Headset \t%s\n", skinny_accessory_state2str(atoi(headset)));
|
||||
stream->write_function(stream, "HandsetId \t%s\n", handset);
|
||||
stream->write_function(stream, "Handset \t%s\n", skinny_accessory_state2str(atoi(handset)));
|
||||
stream->write_function(stream, "SpeakerId \t%s\n", speaker);
|
||||
stream->write_function(stream, "Speaker \t%s\n", skinny_accessory_state2str(atoi(speaker)));
|
||||
stream->write_function(stream, "%s\n", line);
|
||||
|
||||
return 0;
|
||||
@@ -1337,7 +1347,7 @@ static int dump_device_callback(void *pArg, int argc, char **argv, char **column
|
||||
switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream)
|
||||
{
|
||||
char *sql;
|
||||
if ((sql = switch_mprintf("SELECT name, user_id, instance, ip, type, max_streams, port, codec_string "
|
||||
if ((sql = switch_mprintf("SELECT name, user_id, instance, ip, type, max_streams, port, codec_string, headset, handset, speaker "
|
||||
"FROM skinny_devices WHERE name='%s'",
|
||||
device_name))) {
|
||||
skinny_execute_sql_callback(profile, profile->sql_mutex, sql, dump_device_callback, stream);
|
||||
@@ -1916,10 +1926,10 @@ static switch_status_t load_skinny_config(void)
|
||||
switch_odbc_handle_exec(profile->master_odbc, active_lines_sql, NULL, NULL);
|
||||
} else {
|
||||
if ((db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_devices", NULL, devices_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_lines", NULL, lines_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_buttons", NULL, buttons_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_active_lines", NULL, active_lines_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT headset FROM skinny_devices", "DROP TABLE skinny_devices", devices_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_lines", "DROP TABLE skinny_lines", lines_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_buttons", "DROP TABLE skinny_buttons", buttons_sql);
|
||||
switch_core_db_test_reactive(db, "SELECT * FROM skinny_active_lines", "DROP TABLE skinny_active_lines", active_lines_sql);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n");
|
||||
continue;
|
||||
|
||||
@@ -178,7 +178,7 @@ struct PACKED soft_key_event_message {
|
||||
/* HeadsetStatusMessage */
|
||||
#define HEADSET_STATUS_MESSAGE 0x002B
|
||||
struct PACKED headset_status_message {
|
||||
uint32_t mode;
|
||||
uint32_t mode; /* 1=HeadsetOn; 2=HeadsetOff */
|
||||
};
|
||||
|
||||
/* RegisterAvailableLinesMessage */
|
||||
@@ -234,6 +234,23 @@ struct PACKED extended_data_message {
|
||||
#define DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE 0x0042
|
||||
/* See struct PACKED extended_data_message */
|
||||
|
||||
/* DialedPhoneBookMessage */
|
||||
#define DIALED_PHONE_BOOK_MESSAGE 0x0048
|
||||
struct PACKED dialed_phone_book_message {
|
||||
uint32_t number_index; /* must be shifted 4 bits right */
|
||||
uint32_t line_instance;
|
||||
uint32_t unknown;
|
||||
char phone_number[256];
|
||||
};
|
||||
|
||||
/* AccessoryStatusMessage */
|
||||
#define ACCESSORY_STATUS_MESSAGE 0x0049
|
||||
struct PACKED accessory_status_message {
|
||||
uint32_t accessory_id;
|
||||
uint32_t accessory_status;
|
||||
uint32_t unknown;
|
||||
};
|
||||
|
||||
/* RegisterAckMessage */
|
||||
#define REGISTER_ACK_MESSAGE 0x0081
|
||||
struct PACKED register_ack_message {
|
||||
@@ -507,7 +524,7 @@ struct PACKED display_prompt_status_message {
|
||||
};
|
||||
|
||||
/* ClearPromptStatusMessage */
|
||||
#define CLEAR_PROMPT_STATUS_MESSAGE 0x0113
|
||||
#define CLEAR_PROMPT_STATUS_MESSAGE 0x0113
|
||||
struct PACKED clear_prompt_status_message {
|
||||
uint32_t line_instance;
|
||||
uint32_t call_id;
|
||||
@@ -573,6 +590,15 @@ struct PACKED service_url_stat_res_message {
|
||||
#define USER_TO_DEVICE_DATA_VERSION1_MESSAGE 0x013F
|
||||
/* See struct PACKED extended_data_message */
|
||||
|
||||
/* DialedPhoneBookAckMessage */
|
||||
#define DIALED_PHONE_BOOK_ACK_MESSAGE 0x0152
|
||||
struct PACKED dialed_phone_book_ack_message {
|
||||
uint32_t number_index; /* must be shifted 4 bits right */
|
||||
uint32_t line_instance;
|
||||
uint32_t unknown;
|
||||
uint32_t unknown2;
|
||||
};
|
||||
|
||||
/* XMLAlarmMessage */
|
||||
#define XML_ALARM_MESSAGE 0x015A
|
||||
|
||||
@@ -614,6 +640,8 @@ union skinny_data {
|
||||
struct feature_stat_req_message feature_req;
|
||||
/* see field "extended_data" for DEVICE_TO_USER_DATA_VERSION1_MESSAGE */
|
||||
/* see field "extended_data" for DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE */
|
||||
struct dialed_phone_book_message dialed_phone_book;
|
||||
struct accessory_status_message accessory_status;
|
||||
struct register_ack_message reg_ack;
|
||||
struct start_tone_message start_tone;
|
||||
struct stop_tone_message stop_tone;
|
||||
@@ -651,6 +679,7 @@ union skinny_data {
|
||||
struct display_pri_notify_message display_pri_notify;
|
||||
struct service_url_stat_res_message service_url_res;
|
||||
/* see field "extended_data" for USER_TO_DEVICE_DATA_VERSION1_MESSAGE */
|
||||
struct dialed_phone_book_ack_message dialed_phone_book_ack;
|
||||
|
||||
struct data_message data;
|
||||
struct extended_data_message extended_data;
|
||||
|
||||
@@ -588,14 +588,12 @@ switch_call_cause_t skinny_ring_lines(private_t *tech_pvt, switch_core_session_t
|
||||
|
||||
switch_status_t skinny_session_ring_out(switch_core_session_t *session, listener_t *listener, uint32_t line_instance)
|
||||
{
|
||||
switch_channel_t *channel = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
|
||||
switch_assert(session);
|
||||
switch_assert(listener);
|
||||
switch_assert(listener->profile);
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
send_start_tone(listener, SKINNY_TONE_ALERT, 0, line_instance, tech_pvt->call_id);
|
||||
@@ -732,14 +730,12 @@ switch_status_t skinny_session_start_media(switch_core_session_t *session, liste
|
||||
|
||||
switch_status_t skinny_session_hold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance)
|
||||
{
|
||||
switch_channel_t *channel = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
|
||||
switch_assert(session);
|
||||
switch_assert(listener);
|
||||
switch_assert(listener->profile);
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
skinny_session_stop_media(session, listener, line_instance);
|
||||
@@ -760,17 +756,15 @@ switch_status_t skinny_session_hold_line(switch_core_session_t *session, listene
|
||||
|
||||
switch_status_t skinny_session_unhold_line(switch_core_session_t *session, listener_t *listener, uint32_t line_instance)
|
||||
{
|
||||
switch_channel_t *channel = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
|
||||
switch_assert(session);
|
||||
switch_assert(listener);
|
||||
switch_assert(listener->profile);
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
skinny_hold_active_calls(listener);
|
||||
skinny_hold_active_calls(listener);
|
||||
send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, tech_pvt->call_id);
|
||||
send_set_speaker_mode(listener, SKINNY_SPEAKER_ON);
|
||||
send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_RING_OUT, 0xffff);
|
||||
@@ -825,14 +819,12 @@ switch_status_t skinny_session_transfer(switch_core_session_t *session, listener
|
||||
|
||||
switch_status_t skinny_session_stop_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance)
|
||||
{
|
||||
switch_channel_t *channel = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
|
||||
switch_assert(session);
|
||||
switch_assert(listener);
|
||||
switch_assert(listener->profile);
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
@@ -1773,7 +1765,6 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn
|
||||
uint32_t call_id = 0;
|
||||
switch_core_session_t *session = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
|
||||
skinny_check_data_length(request, sizeof(request->data.soft_key_event.event));
|
||||
|
||||
@@ -1790,7 +1781,6 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn
|
||||
break;
|
||||
case SOFTKEY_NEWCALL:
|
||||
status = skinny_create_incoming_session(listener, &line_instance, &session);
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0);
|
||||
break;
|
||||
@@ -1874,13 +1864,10 @@ switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t
|
||||
switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
skinny_message_t *message;
|
||||
skinny_profile_t *profile;
|
||||
|
||||
switch_assert(listener->profile);
|
||||
switch_assert(listener->device_name);
|
||||
|
||||
profile = listener->profile;
|
||||
|
||||
message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template));
|
||||
message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE;
|
||||
message->length = 4 + sizeof(message->data.soft_key_template);
|
||||
@@ -1900,9 +1887,20 @@ switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, sk
|
||||
|
||||
switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
char *sql;
|
||||
|
||||
skinny_check_data_length(request, sizeof(request->data.headset_status));
|
||||
|
||||
/* Nothing to do */
|
||||
if ((sql = switch_mprintf(
|
||||
"UPDATE skinny_devices SET headset=%d WHERE name='%s' and instance=%d",
|
||||
(request->data.headset_status.mode==1) ? SKINNY_ACCESSORY_STATE_OFFHOOK : SKINNY_ACCESSORY_STATE_ONHOOK,
|
||||
listener->device_name,
|
||||
listener->device_instance
|
||||
))) {
|
||||
skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2012,6 +2010,66 @@ switch_status_t skinny_handle_extended_data_message(listener_t *listener, skinny
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
switch_status_t skinny_handle_dialed_phone_book_message(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
skinny_message_t *message;
|
||||
|
||||
skinny_check_data_length(request, sizeof(request->data.dialed_phone_book));
|
||||
|
||||
message = switch_core_alloc(listener->pool, 12+sizeof(message->data.dialed_phone_book_ack));
|
||||
message->type = DIALED_PHONE_BOOK_ACK_MESSAGE;
|
||||
message->length = 4 + sizeof(message->data.dialed_phone_book_ack);
|
||||
message->data.dialed_phone_book_ack.number_index = request->data.dialed_phone_book.number_index;
|
||||
message->data.dialed_phone_book_ack.line_instance = request->data.dialed_phone_book.line_instance;
|
||||
message->data.dialed_phone_book_ack.unknown = request->data.dialed_phone_book.unknown;
|
||||
message->data.dialed_phone_book_ack.unknown2 = 0;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
switch_status_t skinny_handle_accessory_status_message(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
char *sql;
|
||||
|
||||
skinny_check_data_length(request, sizeof(request->data.accessory_status));
|
||||
|
||||
switch(request->data.accessory_status.accessory_id) {
|
||||
case SKINNY_ACCESSORY_HEADSET:
|
||||
if ((sql = switch_mprintf(
|
||||
"UPDATE skinny_devices SET headset=%d WHERE name='%s' and instance=%d",
|
||||
request->data.accessory_status.accessory_status,
|
||||
listener->device_name,
|
||||
listener->device_instance
|
||||
))) {
|
||||
skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
break;
|
||||
case SKINNY_ACCESSORY_HANDSET:
|
||||
if ((sql = switch_mprintf(
|
||||
"UPDATE skinny_devices SET handset=%d WHERE name='%s' and instance=%d",
|
||||
request->data.accessory_status.accessory_status,
|
||||
listener->device_name,
|
||||
listener->device_instance
|
||||
))) {
|
||||
skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
break;
|
||||
case SKINNY_ACCESSORY_SPEAKER:
|
||||
if ((sql = switch_mprintf(
|
||||
"UPDATE skinny_devices SET speaker=%d WHERE name='%s' and instance=%d",
|
||||
request->data.accessory_status.accessory_status,
|
||||
listener->device_name,
|
||||
listener->device_instance
|
||||
))) {
|
||||
skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
@@ -2041,8 +2099,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
|
||||
listener->device_name, listener->device_instance);
|
||||
}
|
||||
if(zstr(listener->device_name) && request->type != REGISTER_MESSAGE && request->type != ALARM_MESSAGE && request->type != XML_ALARM_MESSAGE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Device should send a register message first.\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Device should send a register message first. Received %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
switch(request->type) {
|
||||
@@ -2106,11 +2164,15 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
|
||||
return skinny_handle_extended_data_message(listener, request);
|
||||
case DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE:
|
||||
return skinny_handle_extended_data_message(listener, request);
|
||||
case DIALED_PHONE_BOOK_MESSAGE:
|
||||
return skinny_handle_dialed_phone_book_message(listener, request);
|
||||
case ACCESSORY_STATUS_MESSAGE:
|
||||
return skinny_handle_accessory_status_message(listener, request);
|
||||
case XML_ALARM_MESSAGE:
|
||||
return skinny_handle_xml_alarm(listener, request);
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Unhandled request %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length);
|
||||
"Unhandled %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,223 +35,246 @@
|
||||
|
||||
/* Translation tables */
|
||||
struct skinny_table SKINNY_MESSAGE_TYPES[] = {
|
||||
{"KeepAliveMessage", KEEP_ALIVE_MESSAGE},
|
||||
{"RegisterMessage", REGISTER_MESSAGE},
|
||||
{"PortMessage", PORT_MESSAGE},
|
||||
{"KeypadButtonMessage", KEYPAD_BUTTON_MESSAGE},
|
||||
{"EnblocCallMessage", ENBLOC_CALL_MESSAGE},
|
||||
{"StimulusMessage", STIMULUS_MESSAGE},
|
||||
{"OffHookMessage", OFF_HOOK_MESSAGE},
|
||||
{"OnHookMessage", ON_HOOK_MESSAGE},
|
||||
{"ForwardStatReqMessage", FORWARD_STAT_REQ_MESSAGE},
|
||||
{"SpeedDialStatReqMessage", SPEED_DIAL_STAT_REQ_MESSAGE},
|
||||
{"LineStatReqMessage", LINE_STAT_REQ_MESSAGE},
|
||||
{"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE},
|
||||
{"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE},
|
||||
{"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE},
|
||||
{"VersionReqMessage", VERSION_REQ_MESSAGE},
|
||||
{"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE},
|
||||
{"AlarmMessage", ALARM_MESSAGE},
|
||||
{"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE},
|
||||
{"SoftKeySetReqMessage", SOFT_KEY_SET_REQ_MESSAGE},
|
||||
{"SoftKeyEventMessage", SOFT_KEY_EVENT_MESSAGE},
|
||||
{"UnregisterMessage", UNREGISTER_MESSAGE},
|
||||
{"SoftKeyTemplateReqMessage", SOFT_KEY_TEMPLATE_REQ_MESSAGE},
|
||||
{"HeadsetStatusMessage", HEADSET_STATUS_MESSAGE},
|
||||
{"RegisterAvailableLinesMessage", REGISTER_AVAILABLE_LINES_MESSAGE},
|
||||
{"DeviceToUserDataMessage", DEVICE_TO_USER_DATA_MESSAGE},
|
||||
{"DeviceToUserDataResponseMessage", DEVICE_TO_USER_DATA_RESPONSE_MESSAGE},
|
||||
{"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE},
|
||||
{"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE},
|
||||
{"DeviceToUserDataVersion1Message", DEVICE_TO_USER_DATA_VERSION1_MESSAGE},
|
||||
{"DeviceToUserDataResponseVersion1Message", DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE},
|
||||
{"RegisterAckMessage", REGISTER_ACK_MESSAGE},
|
||||
{"StartToneMessage", START_TONE_MESSAGE},
|
||||
{"StopToneMessage", STOP_TONE_MESSAGE},
|
||||
{"SetRingerMessage", SET_RINGER_MESSAGE},
|
||||
{"SetLampMessage", SET_LAMP_MESSAGE},
|
||||
{"SetSpeakerModeMessage", SET_SPEAKER_MODE_MESSAGE},
|
||||
{"StartMediaTransmissionMessage", START_MEDIA_TRANSMISSION_MESSAGE},
|
||||
{"StopMediaTransmissionMessage", STOP_MEDIA_TRANSMISSION_MESSAGE},
|
||||
{"CallInfoMessage", CALL_INFO_MESSAGE},
|
||||
{"ForwardStatMessage", FORWARD_STAT_MESSAGE},
|
||||
{"SpeedDialStatResMessage", SPEED_DIAL_STAT_RES_MESSAGE},
|
||||
{"LineStatResMessage", LINE_STAT_RES_MESSAGE},
|
||||
{"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE},
|
||||
{"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE},
|
||||
{"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE},
|
||||
{"VersionMessage", VERSION_MESSAGE},
|
||||
{"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE},
|
||||
{"RegisterRejectMessage", REGISTER_REJECT_MESSAGE},
|
||||
{"ResetMessage", RESET_MESSAGE},
|
||||
{"KeepAliveAckMessage", KEEP_ALIVE_ACK_MESSAGE},
|
||||
{"OpenReceiveChannelMessage", OPEN_RECEIVE_CHANNEL_MESSAGE},
|
||||
{"CloseReceiveChannelMessage", CLOSE_RECEIVE_CHANNEL_MESSAGE},
|
||||
{"SoftKeyTemplateResMessage", SOFT_KEY_TEMPLATE_RES_MESSAGE},
|
||||
{"SoftKeySetResMessage", SOFT_KEY_SET_RES_MESSAGE},
|
||||
{"SelectSoftKeysMessage", SELECT_SOFT_KEYS_MESSAGE},
|
||||
{"CallStateMessage", CALL_STATE_MESSAGE},
|
||||
{"DisplayPromptStatusMessage", DISPLAY_PROMPT_STATUS_MESSAGE},
|
||||
{"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE},
|
||||
{"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE},
|
||||
{"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE},
|
||||
{"BackSpaceReqMessage", BACK_SPACE_REQ_MESSAGE},
|
||||
{"DialedNumberMessage", DIALED_NUMBER_MESSAGE},
|
||||
{"UserToDeviceDataMessage", USER_TO_DEVICE_DATA_MESSAGE},
|
||||
{"FeatureResMessage", FEATURE_STAT_RES_MESSAGE},
|
||||
{"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE},
|
||||
{"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE},
|
||||
{"UserToDeviceDataVersion1Message", USER_TO_DEVICE_DATA_VERSION1_MESSAGE},
|
||||
{"XMLAlarmMessage", XML_ALARM_MESSAGE},
|
||||
{NULL, 0}
|
||||
{KEEP_ALIVE_MESSAGE, "KeepAliveMessage"},
|
||||
{REGISTER_MESSAGE, "RegisterMessage"},
|
||||
{PORT_MESSAGE, "PortMessage"},
|
||||
{KEYPAD_BUTTON_MESSAGE, "KeypadButtonMessage"},
|
||||
{ENBLOC_CALL_MESSAGE, "EnblocCallMessage"},
|
||||
{STIMULUS_MESSAGE, "StimulusMessage"},
|
||||
{OFF_HOOK_MESSAGE, "OffHookMessage"},
|
||||
{ON_HOOK_MESSAGE, "OnHookMessage"},
|
||||
{ FORWARD_STAT_REQ_MESSAGE, "ForwardStatReqMessage"},
|
||||
{SPEED_DIAL_STAT_REQ_MESSAGE, "SpeedDialStatReqMessage"},
|
||||
{LINE_STAT_REQ_MESSAGE, "LineStatReqMessage"},
|
||||
{CONFIG_STAT_REQ_MESSAGE, "ConfigStatReqMessage"},
|
||||
{TIME_DATE_REQ_MESSAGE, "TimeDateReqMessage"},
|
||||
{BUTTON_TEMPLATE_REQ_MESSAGE, "ButtonTemplateReqMessage"},
|
||||
{VERSION_REQ_MESSAGE, "VersionReqMessage"},
|
||||
{CAPABILITIES_RES_MESSAGE, "CapabilitiesReqMessage"},
|
||||
{ALARM_MESSAGE, "AlarmMessage"},
|
||||
{OPEN_RECEIVE_CHANNEL_ACK_MESSAGE, "OpenReceiveChannelAckMessage"},
|
||||
{SOFT_KEY_SET_REQ_MESSAGE, "SoftKeySetReqMessage"},
|
||||
{SOFT_KEY_EVENT_MESSAGE, "SoftKeyEventMessage"},
|
||||
{UNREGISTER_MESSAGE, "UnregisterMessage"},
|
||||
{SOFT_KEY_TEMPLATE_REQ_MESSAGE, "SoftKeyTemplateReqMessage"},
|
||||
{HEADSET_STATUS_MESSAGE, "HeadsetStatusMessage"},
|
||||
{REGISTER_AVAILABLE_LINES_MESSAGE, "RegisterAvailableLinesMessage"},
|
||||
{DEVICE_TO_USER_DATA_MESSAGE, "DeviceToUserDataMessage"},
|
||||
{DEVICE_TO_USER_DATA_RESPONSE_MESSAGE, "DeviceToUserDataResponseMessage"},
|
||||
{SERVICE_URL_STAT_REQ_MESSAGE, "ServiceUrlStatReqMessage"},
|
||||
{FEATURE_STAT_REQ_MESSAGE, "FeatureStatReqMessage"},
|
||||
{DEVICE_TO_USER_DATA_VERSION1_MESSAGE, "DeviceToUserDataVersion1Message"},
|
||||
{DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE, "DeviceToUserDataResponseVersion1Message"},
|
||||
{DIALED_PHONE_BOOK_MESSAGE, "DialedPhoneBookMessage"},
|
||||
{ACCESSORY_STATUS_MESSAGE, "AccessoryStatusMessage"},
|
||||
{REGISTER_ACK_MESSAGE, "RegisterAckMessage"},
|
||||
{START_TONE_MESSAGE, "StartToneMessage"},
|
||||
{STOP_TONE_MESSAGE, "StopToneMessage"},
|
||||
{SET_RINGER_MESSAGE, "SetRingerMessage"},
|
||||
{SET_LAMP_MESSAGE, "SetLampMessage"},
|
||||
{SET_SPEAKER_MODE_MESSAGE, "SetSpeakerModeMessage"},
|
||||
{START_MEDIA_TRANSMISSION_MESSAGE, "StartMediaTransmissionMessage"},
|
||||
{STOP_MEDIA_TRANSMISSION_MESSAGE, "StopMediaTransmissionMessage"},
|
||||
{CALL_INFO_MESSAGE, "CallInfoMessage"},
|
||||
{FORWARD_STAT_MESSAGE, "ForwardStatMessage"},
|
||||
{SPEED_DIAL_STAT_RES_MESSAGE, "SpeedDialStatResMessage"},
|
||||
{LINE_STAT_RES_MESSAGE, "LineStatResMessage"},
|
||||
{CONFIG_STAT_RES_MESSAGE, "ConfigStatResMessage"},
|
||||
{DEFINE_TIME_DATE_MESSAGE, "DefineTimeDateMessage"},
|
||||
{BUTTON_TEMPLATE_RES_MESSAGE, "ButtonTemplateResMessage"},
|
||||
{VERSION_MESSAGE, "VersionMessage"},
|
||||
{CAPABILITIES_REQ_MESSAGE, "CapabilitiesReqMessage"},
|
||||
{REGISTER_REJECT_MESSAGE, "RegisterRejectMessage"},
|
||||
{RESET_MESSAGE, "ResetMessage"},
|
||||
{KEEP_ALIVE_ACK_MESSAGE, "KeepAliveAckMessage"},
|
||||
{OPEN_RECEIVE_CHANNEL_MESSAGE, "OpenReceiveChannelMessage"},
|
||||
{CLOSE_RECEIVE_CHANNEL_MESSAGE, "CloseReceiveChannelMessage"},
|
||||
{SOFT_KEY_TEMPLATE_RES_MESSAGE, "SoftKeyTemplateResMessage"},
|
||||
{SOFT_KEY_SET_RES_MESSAGE, "SoftKeySetResMessage"},
|
||||
{SELECT_SOFT_KEYS_MESSAGE, "SelectSoftKeysMessage"},
|
||||
{CALL_STATE_MESSAGE, "CallStateMessage"},
|
||||
{DISPLAY_PROMPT_STATUS_MESSAGE, "DisplayPromptStatusMessage"},
|
||||
{CLEAR_PROMPT_STATUS_MESSAGE, "ClearPromptStatusMessage"},
|
||||
{ACTIVATE_CALL_PLANE_MESSAGE, "ActivateCallPlaneMessage"},
|
||||
{UNREGISTER_ACK_MESSAGE, "UnregisterAckMessage"},
|
||||
{BACK_SPACE_REQ_MESSAGE, "BackSpaceReqMessage"},
|
||||
{DIALED_NUMBER_MESSAGE, "DialedNumberMessage"},
|
||||
{USER_TO_DEVICE_DATA_MESSAGE, "UserToDeviceDataMessage"},
|
||||
{FEATURE_STAT_RES_MESSAGE, "FeatureResMessage"},
|
||||
{DISPLAY_PRI_NOTIFY_MESSAGE, "DisplayPriNotifyMessage"},
|
||||
{SERVICE_URL_STAT_RES_MESSAGE, "ServiceUrlStatMessage"},
|
||||
{USER_TO_DEVICE_DATA_VERSION1_MESSAGE, "UserToDeviceDataVersion1Message"},
|
||||
{DIALED_PHONE_BOOK_ACK_MESSAGE, "DialedPhoneBookAckMessage"},
|
||||
{XML_ALARM_MESSAGE, "XMLAlarmMessage"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2message_type, SKINNY_MESSAGE_TYPES, -1)
|
||||
|
||||
struct skinny_table SKINNY_DEVICE_TYPES[] = {
|
||||
{"Cisco 30 SP+", 1},
|
||||
{"Cisco 12 SP+", 2},
|
||||
{"Cisco 12 SP", 3},
|
||||
{"Cisco 12", 4},
|
||||
{"Cisco 30 VIP", 5},
|
||||
{"Cisco IP Phone 7910", 6},
|
||||
{"Cisco IP Phone 7960", 7},
|
||||
{"Cisco IP Phone 7940", 8},
|
||||
{"Cisco IP Phone 7935", 9},
|
||||
{"Cisco ATA 186", 12},
|
||||
{"Cisco IP Phone CP-7962G", 404},
|
||||
{"Cisco IP Phone CP-7965G", 436},
|
||||
{"Cisco IP Phone CP-7961G", 30018},
|
||||
{"Cisco IP Phone 7936", 30019},
|
||||
{NULL, 0}
|
||||
{1, "Cisco 30 SP+"},
|
||||
{2, "Cisco 12 SP+"},
|
||||
{3, "Cisco 12 SP"},
|
||||
{4, "Cisco 12"},
|
||||
{5, "Cisco 30 VIP"},
|
||||
{6, "Cisco IP Phone 7910"},
|
||||
{7, "Cisco IP Phone 7960"},
|
||||
{8, "Cisco IP Phone 7940"},
|
||||
{9, "Cisco IP Phone 7935"},
|
||||
{12, "Cisco ATA 186"},
|
||||
{365, "Cisco IP Phone CP-7921G"},
|
||||
{404, "Cisco IP Phone CP-7962G"},
|
||||
{436, "Cisco IP Phone CP-7965G"},
|
||||
{30018, "Cisco IP Phone CP-7961G"},
|
||||
{30019, "Cisco IP Phone 7936"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_device_type2str, SKINNY_DEVICE_TYPES, "UnknownDeviceType")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2device_type, SKINNY_DEVICE_TYPES, -1)
|
||||
|
||||
struct skinny_table SKINNY_RING_TYPES[] = {
|
||||
{"RingOff", SKINNY_RING_OFF},
|
||||
{"RingInside", SKINNY_RING_INSIDE},
|
||||
{"RingOutside", SKINNY_RING_OUTSIDE},
|
||||
{"RingFeature", SKINNY_RING_FEATURE},
|
||||
{NULL, 0}
|
||||
{SKINNY_RING_OFF, "RingOff"},
|
||||
{SKINNY_RING_INSIDE, "RingInside"},
|
||||
{SKINNY_RING_OUTSIDE, "RingOutside"},
|
||||
{SKINNY_RING_FEATURE, "RingFeature"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_ring_type2str, SKINNY_RING_TYPES, "RingTypeUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2ring_type, SKINNY_RING_TYPES, -1)
|
||||
|
||||
struct skinny_table SKINNY_RING_MODES[] = {
|
||||
{"RingForever", SKINNY_RING_FOREVER},
|
||||
{"RingOnce", SKINNY_RING_ONCE},
|
||||
{NULL, 0}
|
||||
{SKINNY_RING_FOREVER, "RingForever"},
|
||||
{SKINNY_RING_ONCE, "RingOnce"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_ring_mode2str, SKINNY_RING_MODES, "RingModeUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2ring_mode, SKINNY_RING_MODES, -1)
|
||||
|
||||
struct skinny_table SKINNY_BUTTONS[] = {
|
||||
{"Unknown", SKINNY_BUTTON_UNKNOWN},
|
||||
{"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL},
|
||||
{"SpeedDial", SKINNY_BUTTON_SPEED_DIAL},
|
||||
{"Hold", SKINNY_BUTTON_HOLD},
|
||||
{"Transfer", SKINNY_BUTTON_TRANSFER},
|
||||
{"Line", SKINNY_BUTTON_LINE},
|
||||
{"Voicemail", SKINNY_BUTTON_VOICEMAIL},
|
||||
{"Privacy", SKINNY_BUTTON_PRIVACY},
|
||||
{"ServiceUrl", SKINNY_BUTTON_SERVICE_URL},
|
||||
{"Undefined", SKINNY_BUTTON_UNDEFINED},
|
||||
{NULL, 0}
|
||||
{SKINNY_BUTTON_UNKNOWN, "Unknown"},
|
||||
{SKINNY_BUTTON_LAST_NUMBER_REDIAL, "LastNumberRedial"},
|
||||
{SKINNY_BUTTON_SPEED_DIAL, "SpeedDial"},
|
||||
{SKINNY_BUTTON_HOLD, "Hold"},
|
||||
{SKINNY_BUTTON_TRANSFER, "Transfer"},
|
||||
{SKINNY_BUTTON_LINE, "Line"},
|
||||
{SKINNY_BUTTON_VOICEMAIL, "Voicemail"},
|
||||
{SKINNY_BUTTON_PRIVACY, "Privacy"},
|
||||
{SKINNY_BUTTON_SERVICE_URL, "ServiceUrl"},
|
||||
{SKINNY_BUTTON_UNDEFINED, "Undefined"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_button2str, SKINNY_BUTTONS, "Unknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2button, SKINNY_BUTTONS, -1)
|
||||
|
||||
struct skinny_table SKINNY_SOFT_KEY_EVENTS[] = {
|
||||
{"SoftkeyRedial", SOFTKEY_REDIAL},
|
||||
{"SoftkeyNewcall", SOFTKEY_NEWCALL},
|
||||
{"SoftkeyHold", SOFTKEY_HOLD},
|
||||
{"SoftkeyTransfer", SOFTKEY_TRANSFER},
|
||||
{"SoftkeyCfwdall", SOFTKEY_CFWDALL},
|
||||
{"SoftkeyCfwdbusy", SOFTKEY_CFWDBUSY},
|
||||
{"SoftkeyCfwdnoanswer", SOFTKEY_CFWDNOANSWER},
|
||||
{"SoftkeyBackspace", SOFTKEY_BACKSPACE},
|
||||
{"SoftkeyEndcall", SOFTKEY_ENDCALL},
|
||||
{"SoftkeyResume", SOFTKEY_RESUME},
|
||||
{"SoftkeyAnswer", SOFTKEY_ANSWER },
|
||||
{"SoftkeyInfo", SOFTKEY_INFO},
|
||||
{"SoftkeyConfrm", SOFTKEY_CONFRM},
|
||||
{"SoftkeyPark", SOFTKEY_PARK},
|
||||
{"SoftkeyJoin", SOFTKEY_JOIN},
|
||||
{"SoftkeyMeetmeconfrm", SOFTKEY_MEETMECONFRM},
|
||||
{"SoftkeyCallpickup", SOFTKEY_CALLPICKUP},
|
||||
{"SoftkeyGrpcallpickup", SOFTKEY_GRPCALLPICKUP},
|
||||
{"SoftkeyDnd", SOFTKEY_DND},
|
||||
{"SoftkeyIdivert", SOFTKEY_IDIVERT},
|
||||
{NULL, 0}
|
||||
{SOFTKEY_REDIAL, "SoftkeyRedial"},
|
||||
{SOFTKEY_NEWCALL, "SoftkeyNewcall"},
|
||||
{SOFTKEY_HOLD, "SoftkeyHold"},
|
||||
{SOFTKEY_TRANSFER, "SoftkeyTransfer"},
|
||||
{SOFTKEY_CFWDALL, "SoftkeyCfwdall"},
|
||||
{SOFTKEY_CFWDBUSY, "SoftkeyCfwdbusy"},
|
||||
{SOFTKEY_CFWDNOANSWER, "SoftkeyCfwdnoanswer"},
|
||||
{SOFTKEY_BACKSPACE, "SoftkeyBackspace"},
|
||||
{SOFTKEY_ENDCALL, "SoftkeyEndcall"},
|
||||
{SOFTKEY_RESUME, "SoftkeyResume"},
|
||||
{SOFTKEY_ANSWER , "SoftkeyAnswer"},
|
||||
{SOFTKEY_INFO, "SoftkeyInfo"},
|
||||
{SOFTKEY_CONFRM, "SoftkeyConfrm"},
|
||||
{SOFTKEY_PARK, "SoftkeyPark"},
|
||||
{SOFTKEY_JOIN, "SoftkeyJoin"},
|
||||
{SOFTKEY_MEETMECONFRM, "SoftkeyMeetmeconfrm"},
|
||||
{SOFTKEY_CALLPICKUP, "SoftkeyCallpickup"},
|
||||
{SOFTKEY_GRPCALLPICKUP, "SoftkeyGrpcallpickup"},
|
||||
{SOFTKEY_DND, "SoftkeyDnd"},
|
||||
{SOFTKEY_IDIVERT, "SoftkeyIdivert"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_soft_key_event2str, SKINNY_SOFT_KEY_EVENTS, "SoftkeyUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2soft_key_event, SKINNY_SOFT_KEY_EVENTS, 0)
|
||||
|
||||
struct skinny_table SKINNY_LAMP_MODES[] = {
|
||||
{"Off", SKINNY_LAMP_OFF},
|
||||
{"On", SKINNY_LAMP_ON},
|
||||
{"Wink", SKINNY_LAMP_WINK},
|
||||
{"Flash", SKINNY_LAMP_FLASH},
|
||||
{"Blink", SKINNY_LAMP_BLINK},
|
||||
{NULL, 0}
|
||||
{SKINNY_LAMP_OFF, "Off"},
|
||||
{SKINNY_LAMP_ON, "On"},
|
||||
{SKINNY_LAMP_WINK, "Wink"},
|
||||
{SKINNY_LAMP_FLASH, "Flash"},
|
||||
{SKINNY_LAMP_BLINK, "Blink"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_lamp_mode2str, SKINNY_LAMP_MODES, "Unknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2lamp_mode, SKINNY_LAMP_MODES, -1)
|
||||
|
||||
struct skinny_table SKINNY_SPEAKER_MODES[] = {
|
||||
{"SpeakerOn", SKINNY_SPEAKER_ON},
|
||||
{"SpeakerOff", SKINNY_SPEAKER_OFF},
|
||||
{NULL, 0}
|
||||
{SKINNY_SPEAKER_ON, "SpeakerOn"},
|
||||
{SKINNY_SPEAKER_OFF, "SpeakerOff"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_speaker_mode2str, SKINNY_SPEAKER_MODES, "Unknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2speaker_mode, SKINNY_SPEAKER_MODES, -1)
|
||||
|
||||
struct skinny_table SKINNY_KEY_SETS[] = {
|
||||
{"KeySetOnHook", SKINNY_KEY_SET_ON_HOOK},
|
||||
{"KeySetConnected", SKINNY_KEY_SET_CONNECTED},
|
||||
{"KeySetOnHold", SKINNY_KEY_SET_ON_HOLD},
|
||||
{"KeySetRingIn", SKINNY_KEY_SET_RING_IN},
|
||||
{"KeySetOffHook", SKINNY_KEY_SET_OFF_HOOK},
|
||||
{"KeySetConnectedWithTransfer", SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER},
|
||||
{"KeySetDigitsAfterDialingFirstDigit", SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT},
|
||||
{"KeySetConnectedWithConference", SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE},
|
||||
{"KeySetRingOut", SKINNY_KEY_SET_RING_OUT},
|
||||
{"KeySetOffHookWithFeatures", SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES},
|
||||
{"KeySetInUseHint", SKINNY_KEY_SET_IN_USE_HINT},
|
||||
{NULL, 0}
|
||||
{SKINNY_KEY_SET_ON_HOOK, "KeySetOnHook"},
|
||||
{SKINNY_KEY_SET_CONNECTED, "KeySetConnected"},
|
||||
{SKINNY_KEY_SET_ON_HOLD, "KeySetOnHold"},
|
||||
{SKINNY_KEY_SET_RING_IN, "KeySetRingIn"},
|
||||
{SKINNY_KEY_SET_OFF_HOOK, "KeySetOffHook"},
|
||||
{SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER, "KeySetConnectedWithTransfer"},
|
||||
{SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, "KeySetDigitsAfterDialingFirstDigit"},
|
||||
{SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE, "KeySetConnectedWithConference"},
|
||||
{SKINNY_KEY_SET_RING_OUT, "KeySetRingOut"},
|
||||
{SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES, "KeySetOffHookWithFeatures"},
|
||||
{SKINNY_KEY_SET_IN_USE_HINT, "KeySetInUseHint"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_soft_key_set2str, SKINNY_KEY_SETS, "UNKNOWN_SOFT_KEY_SET")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2soft_key_set, SKINNY_KEY_SETS, -1)
|
||||
|
||||
struct skinny_table SKINNY_CALL_STATES[] = {
|
||||
{"OffHook", SKINNY_OFF_HOOK},
|
||||
{"OnHook", SKINNY_ON_HOOK},
|
||||
{"RingOut", SKINNY_RING_OUT},
|
||||
{"RingIn", SKINNY_RING_IN},
|
||||
{"Connected", SKINNY_CONNECTED},
|
||||
{"Busy", SKINNY_BUSY},
|
||||
{"LineInUse", SKINNY_LINE_IN_USE},
|
||||
{"Hold", SKINNY_HOLD},
|
||||
{"CallWaiting", SKINNY_CALL_WAITING},
|
||||
{"CallTransfer", SKINNY_CALL_TRANSFER},
|
||||
{"CallPark", SKINNY_CALL_PARK},
|
||||
{"Proceed", SKINNY_PROCEED},
|
||||
{"InUseRemotely", SKINNY_IN_USE_REMOTELY},
|
||||
{"InvalidNumber", SKINNY_INVALID_NUMBER},
|
||||
{NULL, 0}
|
||||
{SKINNY_OFF_HOOK, "OffHook"},
|
||||
{SKINNY_ON_HOOK, "OnHook"},
|
||||
{SKINNY_RING_OUT, "RingOut"},
|
||||
{SKINNY_RING_IN, "RingIn"},
|
||||
{SKINNY_CONNECTED, "Connected"},
|
||||
{SKINNY_BUSY, "Busy"},
|
||||
{SKINNY_LINE_IN_USE, "LineInUse"},
|
||||
{SKINNY_HOLD, "Hold"},
|
||||
{SKINNY_CALL_WAITING, "CallWaiting"},
|
||||
{SKINNY_CALL_TRANSFER, "CallTransfer"},
|
||||
{SKINNY_CALL_PARK, "CallPark"},
|
||||
{SKINNY_PROCEED, "Proceed"},
|
||||
{SKINNY_IN_USE_REMOTELY, "InUseRemotely"},
|
||||
{SKINNY_INVALID_NUMBER, "InvalidNumber"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_call_state2str, SKINNY_CALL_STATES, "CallStateUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2call_state, SKINNY_CALL_STATES, -1)
|
||||
|
||||
struct skinny_table SKINNY_DEVICE_RESET_TYPES[] = {
|
||||
{"DeviceReset", SKINNY_DEVICE_RESET},
|
||||
{"DeviceRestart", SKINNY_DEVICE_RESTART},
|
||||
{NULL, 0}
|
||||
{SKINNY_DEVICE_RESET, "DeviceReset"},
|
||||
{SKINNY_DEVICE_RESTART, "DeviceRestart"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_device_reset_type2str, SKINNY_DEVICE_RESET_TYPES, "DeviceResetTypeUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2device_reset_type, SKINNY_DEVICE_RESET_TYPES, -1)
|
||||
|
||||
struct skinny_table SKINNY_ACCESSORY_TYPES[] = {
|
||||
{SKINNY_ACCESSORY_NONE, "AccessoryNone"},
|
||||
{SKINNY_ACCESSORY_HEADSET, "Headset"},
|
||||
{SKINNY_ACCESSORY_HANDSET, "Handset"},
|
||||
{SKINNY_ACCESSORY_SPEAKER, "Speaker"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_accessory_type2str, SKINNY_ACCESSORY_TYPES, "AccessoryUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2accessory_type, SKINNY_ACCESSORY_TYPES, -1)
|
||||
|
||||
struct skinny_table SKINNY_ACCESSORY_STATES[] = {
|
||||
{SKINNY_ACCESSORY_STATE_NONE, "AccessoryNoState"},
|
||||
{SKINNY_ACCESSORY_STATE_OFFHOOK, "OffHook"},
|
||||
{SKINNY_ACCESSORY_STATE_ONHOOK, "OnHook"},
|
||||
{0, NULL}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_accessory_state2str, SKINNY_ACCESSORY_STATES, "AccessoryStateUnknown")
|
||||
SKINNY_DECLARE_STR2ID(skinny_str2accessory_state, SKINNY_ACCESSORY_STATES, -1)
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
/* SKINNY TABLES */
|
||||
/*****************************************************************************/
|
||||
struct skinny_table {
|
||||
const char *name;
|
||||
uint32_t id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define SKINNY_DECLARE_ID2STR(func, TABLE, DEFAULT_STR) \
|
||||
@@ -87,12 +87,12 @@ uint32_t func(const char *str)\
|
||||
}
|
||||
|
||||
|
||||
extern struct skinny_table SKINNY_MESSAGE_TYPES[69];
|
||||
extern struct skinny_table SKINNY_MESSAGE_TYPES[72];
|
||||
const char *skinny_message_type2str(uint32_t id);
|
||||
uint32_t skinny_str2message_type(const char *str);
|
||||
#define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)
|
||||
|
||||
extern struct skinny_table SKINNY_DEVICE_TYPES[15];
|
||||
extern struct skinny_table SKINNY_DEVICE_TYPES[16];
|
||||
const char *skinny_device_type2str(uint32_t id);
|
||||
uint32_t skinny_str2device_type(const char *str);
|
||||
#define SKINNY_PUSH_DEVICE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_DEVICE_TYPES)
|
||||
@@ -248,6 +248,27 @@ const char *skinny_device_reset_type2str(uint32_t id);
|
||||
uint32_t skinny_str2device_reset_type(const char *str);
|
||||
#define SKINNY_PUSH_DEVICE_RESET_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_DEVICE_RESET_TYPES)
|
||||
|
||||
enum skinny_accessory_types {
|
||||
SKINNY_ACCESSORY_NONE = 0x00,
|
||||
SKINNY_ACCESSORY_HEADSET = 0x01,
|
||||
SKINNY_ACCESSORY_HANDSET = 0x02,
|
||||
SKINNY_ACCESSORY_SPEAKER = 0x03
|
||||
};
|
||||
extern struct skinny_table SKINNY_ACCESSORY_TYPES[5];
|
||||
const char *skinny_accessory_type2str(uint32_t id);
|
||||
uint32_t skinny_str2accessory_type(const char *str);
|
||||
#define SKINNY_PUSH_ACCESSORY_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_ACCESSORY_TYPES)
|
||||
|
||||
enum skinny_accessory_states {
|
||||
SKINNY_ACCESSORY_STATE_NONE = 0x00,
|
||||
SKINNY_ACCESSORY_STATE_OFFHOOK = 0x01,
|
||||
SKINNY_ACCESSORY_STATE_ONHOOK = 0x02
|
||||
};
|
||||
extern struct skinny_table SKINNY_ACCESSORY_STATES[4];
|
||||
const char *skinny_accessory_state2str(uint32_t id);
|
||||
uint32_t skinny_str2accessory_state(const char *str);
|
||||
#define SKINNY_PUSH_ACCESSORY_STATES SKINNY_DECLARE_PUSH_MATCH(SKINNY_ACCESSORY_STATES)
|
||||
|
||||
#endif /* _SKINNY_TABLES_H */
|
||||
|
||||
/* For Emacs:
|
||||
|
||||
@@ -1,7 +1,24 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_skypopen
|
||||
|
||||
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
|
||||
|
||||
SPANDSP_DIR=$(switch_srcdir)/libs/spandsp
|
||||
SPANDSP_BUILDDIR=$(switch_builddir)/libs/spandsp
|
||||
SPANDSP_LA=$(SPANDSP_BUILDDIR)/src/libspandsp.la
|
||||
|
||||
mod_LTLIBRARIES = mod_skypopen.la
|
||||
mod_skypopen_la_SOURCES = mod_skypopen.c skypopen_protocol.c
|
||||
mod_skypopen_la_CFLAGS = $(AM_CFLAGS) -DSKYPOPEN_C_VER=\"`git log -1 --format="%h" skypopen_protocol.c`\" -DMODSKYPOPEN_C_VER=\"`git log -1 --format="%h" mod_skypopen.c`\" -I../../../../libs/spandsp/src -I../../../..//libs/tiff-3.8.2/libtiff
|
||||
mod_skypopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_skypopen_la_LDFLAGS = -L../../../../libs/spandsp/src -avoid-version -module -no-undefined -shared -lX11 -lspandsp
|
||||
mod_skypopen_la_CFLAGS = $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff -I. -DSKYPOPEN_C_VER=\"`git log -1 --format="%h" skypopen_protocol.c`\" -DMODSKYPOPEN_C_VER=\"`git log -1 --format="%h" mod_skypopen.c`\"
|
||||
mod_skypopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA)
|
||||
mod_skypopen_la_LDFLAGS = -avoid-version -module -no-undefined -shared -lX11
|
||||
|
||||
$(SPANDSP_LA): $(TIFF_LA) $(SPANDSP_DIR) $(SPANDSP_DIR)/.update
|
||||
cd $(SPANDSP_BUILDDIR) && $(MAKE) -j1
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
$(TIFF_LA): $(TIFF_DIR) $(TIFF_DIR)/.update
|
||||
cd $(TIFF_BUILDDIR) && $(MAKE) -j1
|
||||
$(TOUCH_TARGET)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
./dummy.c
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user