Merge branch 'master' into smgmaster

Conflicts:
	src/switch_console.c
This commit is contained in:
Moises Silva committed 2011-05-22 17:53:14 -04:00
commit 950e936111
296 files changed
+11586 -7566

No files matched your search

+4
View File
@@ -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;
+10
View File
@@ -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 */
+2 -1
View File
@@ -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;
};
@@ -597,7 +598,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);
+6
View File
@@ -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
@@ -2205,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);
+81
View File
@@ -0,0 +1,81 @@
/*
* 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);
#if defined(HAVE_OPENSSL)
switch_ssl_init_ssl_locks();
#endif
}
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) {
#if defined(HAVE_OPENSSL)
switch_ssl_destroy_ssl_locks();
#endif
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:
*/
+1 -1
View File
@@ -285,7 +285,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
/*!
+4 -4
View File
@@ -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
+107
View File
@@ -0,0 +1,107 @@
/*
* 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++) {
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
+2
View File
@@ -136,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"
@@ -488,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;
+39 -17
View File
@@ -239,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") ||\
@@ -268,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);
@@ -500,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
@@ -653,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);
+2
View File
@@ -417,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
-2
View File
@@ -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
+2 -2
View File
@@ -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>
@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>mod_callcenter</ProjectName>
<ProjectGuid>{47886A6C-CCA6-4F9F-A7D4-F97D06FB2B1A}</ProjectGuid>
<RootNamespace>mod_callcenter</RootNamespace>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\..\..\w32\module_release.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\..\..\w32\module_debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\..\..\w32\module_release.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\..\..\w32\module_debug.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
</ClCompile>
<Link>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
</ClCompile>
<Link>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
</ClCompile>
<Link>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
</ClCompile>
<Link>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="mod_callcenter.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -37,10 +37,7 @@
#define CC_AGENT_TYPE_UUID_STANDBY "uuid-standby"
#define CC_SQLITE_DB_NAME "callcenter"
/* TODO
drop caller if no agent login
dont allow new caller
*/
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_callcenter_shutdown);
SWITCH_MODULE_RUNTIME_FUNCTION(mod_callcenter_runtime);
@@ -249,6 +246,16 @@ static char tiers_sql[] =
static switch_xml_config_int_options_t config_int_0_86400 = { SWITCH_TRUE, 0, SWITCH_TRUE, 86400 };
/* TODO This is temporary until we either move it to the core, or use it differently in the module */
switch_time_t local_epoch_time_now(switch_time_t *t)
{
switch_time_t now = switch_micro_time_now() / 1000000; /* APR_USEC_PER_SEC */
if (t) {
*t = now;
}
return now;
}
const char * cc_tier_state2str(cc_tier_state_t state)
{
uint8_t x;
@@ -656,8 +663,6 @@ static cc_queue_t *load_queue(const char *queue_name)
cc_queue_t *queue = NULL;
switch_xml_t x_queues, x_queue, cfg, xml;
switch_event_t *event = NULL;
switch_cache_db_handle_t *dbh = NULL;
char *sql = NULL;
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);
@@ -700,30 +705,10 @@ static cc_queue_t *load_queue(const char *queue_name)
queue->last_agent_exist = 0;
queue->last_agent_exist_check = 0;
if (!(dbh = cc_get_db_handle())) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n");
goto end;
}
switch_cache_db_test_reactive(dbh, "select count(session_uuid) from members", "drop table members", members_sql);
switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", NULL, "alter table agents add ready_time integer not null default 0;"
"alter table agents add reject_delay_time integer not null default 0;"
"alter table agents add busy_delay_time integer not null default 0;");
switch_cache_db_test_reactive(dbh, "select count(no_answer_delay_time) from agents", NULL, "alter table agents add no_answer_delay_time integer not null default 0;");
switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", "drop table agents", agents_sql);
switch_cache_db_test_reactive(dbh, "select count(queue) from tiers", "drop table tiers" , tiers_sql);
switch_mutex_init(&queue->mutex, SWITCH_MUTEX_NESTED, queue->pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added queue %s\n", queue->name);
switch_core_hash_insert(globals.queue_hash, queue->name, queue);
/* Reset a unclean shutdown */
sql = switch_mprintf("UPDATE agents SET state = 'Waiting', uuid = '' WHERE system = 'single_box';"
"UPDATE tiers SET state = 'Ready' WHERE agent IN (SELECT name FROM agents WHERE system = 'single_box');"
"UPDATE members SET state = '%q', session_uuid = '' WHERE system = 'single_box';",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
}
end:
@@ -925,13 +910,13 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
if (cc_agent_str2status(value) != CC_AGENT_STATUS_UNKNOWN) {
/* Reset values on available only */
if (cc_agent_str2status(value) == CC_AGENT_STATUS_AVAILABLE) {
sql = switch_mprintf("UPDATE agents SET status = '%q', last_status_change = '%ld', talk_time = 0, calls_answered = 0, no_answer_count = 0"
sql = switch_mprintf("UPDATE agents SET status = '%q', last_status_change = '%" SWITCH_TIME_T_FMT "', talk_time = 0, calls_answered = 0, no_answer_count = 0"
" WHERE name = '%q' AND NOT status = '%q'",
value, (long) switch_epoch_time_now(NULL),
value, local_epoch_time_now(NULL),
agent, value);
} else {
sql = switch_mprintf("UPDATE agents SET status = '%q', last_status_change = '%ld' WHERE name = '%q'",
value, (long) switch_epoch_time_now(NULL), agent);
sql = switch_mprintf("UPDATE agents SET status = '%q', last_status_change = '%" SWITCH_TIME_T_FMT "' WHERE name = '%q'",
value, local_epoch_time_now(NULL), agent);
}
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -943,7 +928,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (!switch_strlen_zero(res)) {
switch_core_session_hupall_matching_var("cc_member_uuid", res, SWITCH_CAUSE_ORIGINATOR_CANCEL);
switch_core_session_hupall_matching_var("cc_member_pre_answer_uuid", res, SWITCH_CAUSE_ORIGINATOR_CANCEL);
}
}
@@ -966,8 +951,8 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
if (cc_agent_str2state(value) != CC_AGENT_STATE_RECEIVING) {
sql = switch_mprintf("UPDATE agents SET state = '%q' WHERE name = '%q'", value, agent);
} else {
sql = switch_mprintf("UPDATE agents SET state = '%q', last_offered_call = '%ld' WHERE name = '%q'",
value, (long) switch_epoch_time_now(NULL), agent);
sql = switch_mprintf("UPDATE agents SET state = '%q', last_offered_call = '%" SWITCH_TIME_T_FMT "' WHERE name = '%q'",
value, local_epoch_time_now(NULL), agent);
}
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -1262,11 +1247,15 @@ end:
static switch_status_t load_config(void)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_xml_t cfg, xml, settings, param, x_queues, x_queue, x_agents, x_agent, x_tiers, x_tier;
switch_cache_db_handle_t *dbh = NULL;
char *sql = NULL;
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 SWITCH_STATUS_TERM;
status = SWITCH_STATUS_TERM;
goto end;
}
switch_mutex_lock(globals.mutex);
@@ -1297,6 +1286,30 @@ static switch_status_t load_config(void)
globals.dbname = strdup(CC_SQLITE_DB_NAME);
}
/* Initialize database */
if (!(dbh = cc_get_db_handle())) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n");
status = SWITCH_STATUS_TERM;
goto end;
}
switch_cache_db_test_reactive(dbh, "select count(session_uuid) from members", "drop table members", members_sql);
switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", NULL, "alter table agents add ready_time integer not null default 0;"
"alter table agents add reject_delay_time integer not null default 0;"
"alter table agents add busy_delay_time integer not null default 0;");
switch_cache_db_test_reactive(dbh, "select count(no_answer_delay_time) from agents", NULL, "alter table agents add no_answer_delay_time integer not null default 0;");
switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", "drop table agents", agents_sql);
switch_cache_db_test_reactive(dbh, "select count(queue) from tiers", "drop table tiers" , tiers_sql);
switch_cache_db_release_db_handle(&dbh);
/* Reset a unclean shutdown */
sql = switch_mprintf("update agents set state = 'Waiting', uuid = '' where system = 'single_box';"
"update tiers set state = 'Ready' where agent IN (select name from agents where system = 'single_box');"
"update members set state = '%q', session_uuid = '' where system = 'single_box';",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
/* Loading queue into memory struct */
if ((x_queues = switch_xml_child(cfg, "queues"))) {
for (x_queue = switch_xml_child(x_queues, "queue"); x_queue; x_queue = x_queue->next) {
@@ -1342,11 +1355,14 @@ static switch_status_t load_config(void)
}
}
end:
switch_mutex_unlock(globals.mutex);
switch_xml_free(xml);
if (xml) {
switch_xml_free(xml);
}
return SWITCH_STATUS_SUCCESS;
return status;
}
static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *thread, void *obj)
@@ -1371,8 +1387,11 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* member is gone before we could process it */
if (!member_session) {
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q' AND state != '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), h->member_uuid, cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Member %s <%s> with uuid %s in queue %s is gone just before we assigned an agent\n", h->member_cid_name, h->member_cid_number, h->member_session_uuid, h->queue_name);
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%" SWITCH_TIME_T_FMT "' WHERE system = 'single_box' AND uuid = '%q' AND state != '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), local_epoch_time_now(NULL), h->member_uuid, cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -1405,7 +1424,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_side", "%s", "agent");
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true");
t_agent_called = switch_epoch_time_now(NULL);
t_agent_called = local_epoch_time_now(NULL);
dialstr = switch_mprintf("%s", h->originate_string);
status = switch_ivr_originate(NULL, &agent_session, &cause, dialstr, 60, NULL, h->member_cid_name, h->member_cid_number, NULL, ovars, SOF_NONE, NULL);
switch_safe_free(dialstr);
@@ -1440,7 +1459,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
cc_agent_update("uuid", "", h->agent_name);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid agent type '%s' for agent '%s', aborting member offering", h->agent_type, h->agent_name);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Invalid agent type '%s' for agent '%s', aborting member offering", h->agent_type, h->agent_name);
status = SWITCH_CAUSE_USER_NOT_REGISTERED;
}
@@ -1507,7 +1526,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_core_session_hupall_matching_var("cc_member_pre_answer_uuid", h->member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
}
t_agent_answered = switch_epoch_time_now(NULL);
t_agent_answered = local_epoch_time_now(NULL);
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(agent_channel, event);
@@ -1516,9 +1535,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%" SWITCH_TIME_T_FMT, t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%" SWITCH_TIME_T_FMT, t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%" SWITCH_TIME_T_FMT, t_member_called);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
@@ -1527,12 +1546,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
}
/* for xml_cdr needs */
switch_channel_set_variable(member_channel, "cc_agent", h->agent_name);
switch_channel_set_variable_printf(member_channel, "cc_queue_answered_epoch", "%ld", (long) switch_epoch_time_now(NULL));
switch_channel_set_variable_printf(member_channel, "cc_queue_answered_epoch", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
/* Set UUID of the Agent channel */
sql = switch_mprintf("UPDATE agents SET uuid = '%q', last_bridge_start = '%ld', calls_answered = calls_answered + 1, no_answer_count = 0"
sql = switch_mprintf("UPDATE agents SET uuid = '%q', last_bridge_start = '%" SWITCH_TIME_T_FMT "', calls_answered = calls_answered + 1, no_answer_count = 0"
" WHERE name = '%q' AND system = '%q'",
agent_uuid, (long) switch_epoch_time_now(NULL),
agent_uuid, local_epoch_time_now(NULL),
h->agent_name, h->agent_system);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -1551,13 +1570,16 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" <%s> from queue %s%s\n",
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" <%s> from queue %s%s\n",
h->agent_name, h->member_cid_name, h->member_cid_number, h->queue_name, (h->record_template?" (Recorded)":""));
switch_ivr_uuid_bridge(h->member_session_uuid, switch_core_session_get_uuid(agent_session));
/* This is used for the waiting caller to quit waiting for a agent */
switch_channel_set_variable(member_channel, "cc_agent_uuid", agent_uuid);
/* This is used for the waiting caller to quit waiting for a agent */
switch_channel_set_variable(member_channel, "cc_agent_found", "true");
/* Wait until the member hangup or the agent hangup. This will quit also if the agent transfer the call */
while(switch_channel_up(member_channel) && switch_channel_up(agent_channel) && globals.running) {
switch_yield(100000);
@@ -1572,10 +1594,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Bridge-Terminated-Time", "%ld", (long) switch_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%" SWITCH_TIME_T_FMT, t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%" SWITCH_TIME_T_FMT, t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%" SWITCH_TIME_T_FMT, t_member_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Bridge-Terminated-Time", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
@@ -1583,12 +1605,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_fire(&event);
}
/* for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_queue_terminated_epoch", "%ld", (long) switch_epoch_time_now(NULL));
switch_channel_set_variable_printf(member_channel, "cc_queue_terminated_epoch", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
/* Update Agents Items */
/* Do not remove uuid of the agent if we are a standby agent */
sql = switch_mprintf("UPDATE agents SET %s last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';"
, (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system);
sql = switch_mprintf("UPDATE agents SET %s last_bridge_end = %" SWITCH_TIME_T_FMT ", talk_time = talk_time + (%" SWITCH_TIME_T_FMT "-last_bridge_start) WHERE name = '%q' AND system = '%q';"
, (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), local_epoch_time_now(NULL), local_epoch_time_now(NULL), h->agent_name, h->agent_system);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -1607,10 +1629,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%" SWITCH_TIME_T_FMT, t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%" SWITCH_TIME_T_FMT, t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Leaving-Time", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%" SWITCH_TIME_T_FMT, t_member_called);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
@@ -1629,7 +1651,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n", h->agent_name, switch_channel_cause2str(cause));
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n", h->agent_name, switch_channel_cause2str(cause));
switch (cause) {
/* When we hang-up agents that did not answer in ring-all strategy */
@@ -1658,7 +1680,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* Put Agent on break because he didn't answer often */
if (h->max_no_answer > 0 && (h->no_answer_count + 1) >= h->max_no_answer) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s reach maximum no answer of %d, Putting agent on break\n",
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Agent %s reach maximum no answer of %d, Putting agent on break\n",
h->agent_name, h->max_no_answer);
cc_agent_update("status", cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), h->agent_name);
}
@@ -1668,9 +1690,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* Put agent to sleep for some time if necessary */
if (delay_next_agent_call > 0) {
char ready_epoch[64];
switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, switch_epoch_time_now(NULL) + delay_next_agent_call);
switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL) + delay_next_agent_call);
cc_agent_update("ready_time", ready_epoch , h->agent_name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s sleeping for %d seconds\n", h->agent_name, delay_next_agent_call);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Agent %s sleeping for %d seconds\n", h->agent_name, delay_next_agent_call);
}
/* Fire up event when contact agent fails */
@@ -1763,9 +1785,10 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
const char *agent_wrap_up_time = argv[11];
const char *agent_state = argv[12];
const char *agent_ready_time = argv[13];
const char *agent_tier_level = argv[14];
const char *agent_type = argv[15];
const char *agent_uuid = argv[16];
const char *agent_tier_position = argv[14];
const char *agent_tier_level = argv[15];
const char *agent_type = argv[16];
const char *agent_uuid = argv[17];
switch_bool_t contact_agent = SWITCH_TRUE;
@@ -1778,11 +1801,11 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
if (cbt->tier_rule_no_agent_no_wait == SWITCH_TRUE && cbt->tier_agent_available == 0) {
cbt->tier = atoi(agent_tier_level);
/* Multiple the tier level by the tier wait time */
} else if (cbt->tier_rule_wait_multiply_level == SWITCH_TRUE && (long) switch_epoch_time_now(NULL) - atol(cbt->member_joined_epoch) >= atoi(agent_tier_level) * cbt->tier_rule_wait_second) {
} else if (cbt->tier_rule_wait_multiply_level == SWITCH_TRUE && (long) local_epoch_time_now(NULL) - atol(cbt->member_joined_epoch) >= atoi(agent_tier_level) * cbt->tier_rule_wait_second) {
cbt->tier = atoi(agent_tier_level);
cbt->tier_agent_available = 0;
/* Just check if joined is bigger than next tier wait time */
} else if (cbt->tier_rule_wait_multiply_level == SWITCH_FALSE && (long) switch_epoch_time_now(NULL) - atol(cbt->member_joined_epoch) >= cbt->tier_rule_wait_second) {
} else if (cbt->tier_rule_wait_multiply_level == SWITCH_FALSE && (long) local_epoch_time_now(NULL) - atol(cbt->member_joined_epoch) >= cbt->tier_rule_wait_second) {
cbt->tier = atoi(agent_tier_level);
cbt->tier_agent_available = 0;
} else {
@@ -1799,10 +1822,10 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
if (! (!strcasecmp(agent_state, cc_agent_state2str(CC_AGENT_STATE_WAITING)))) {
contact_agent = SWITCH_FALSE;
}
if (! (atol(agent_last_bridge_end) < ((long) switch_epoch_time_now(NULL) - atol(agent_wrap_up_time)))) {
if (! (atol(agent_last_bridge_end) < ((long) local_epoch_time_now(NULL) - atol(agent_wrap_up_time)))) {
contact_agent = SWITCH_FALSE;
}
if (! (atol(agent_ready_time) <= (long) switch_epoch_time_now(NULL))) {
if (! (atol(agent_ready_time) <= (long) local_epoch_time_now(NULL))) {
contact_agent = SWITCH_FALSE;
}
if (! (strcasecmp(agent_status, cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK)))) {
@@ -1877,8 +1900,16 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
h->reject_delay_time = atoi(agent_reject_delay_time);
h->busy_delay_time = atoi(agent_busy_delay_time);
h->no_answer_delay_time = atoi(agent_no_answer_delay_time);
if (!strcasecmp(cbt->strategy, "top-down")) {
switch_core_session_t *member_session = switch_core_session_locate(cbt->member_session_uuid);
if (member_session) {
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
switch_channel_set_variable(member_channel, "cc_last_agent_tier_position", agent_tier_position);
switch_channel_set_variable(member_channel, "cc_last_agent_tier_level", agent_tier_level);
switch_core_session_rwunlock(member_session);
}
}
cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_RECEIVING), h->agent_name);
sql = switch_mprintf(
@@ -1918,7 +1949,6 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
switch_bool_t tier_rule_wait_multiply_level;
switch_bool_t tier_rule_no_agent_no_wait;
uint32_t discard_abandoned_after;
switch_bool_t abandoned_resume_allowed;
agent_callback_t cbt;
const char *member_state = NULL;
const char *member_abandoned_epoch = NULL;
@@ -1945,7 +1975,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
tier_rule_wait_multiply_level = queue->tier_rule_wait_multiply_level;
tier_rule_no_agent_no_wait = queue->tier_rule_no_agent_no_wait;
discard_abandoned_after = queue->discard_abandoned_after;
abandoned_resume_allowed = queue->abandoned_resume_allowed;
if (queue->record_template) {
queue_record_template = strdup(queue->record_template);
}
@@ -1955,13 +1985,13 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
/* Checking for cleanup Abandonded calls from the db */
if (!strcasecmp(member_state, cc_member_state2str(CC_MEMBER_STATE_ABANDONED))) {
long abandoned_epoch = atol(member_abandoned_epoch);
switch_time_t abandoned_epoch = atoll(member_abandoned_epoch);
if (abandoned_epoch == 0) {
abandoned_epoch = atol(cbt.member_joined_epoch);
abandoned_epoch = atoll(cbt.member_joined_epoch);
}
/* Once we pass a certain point, we want to get rid of the abandoned call */
if (abandoned_epoch + discard_abandoned_after < (long) switch_epoch_time_now(NULL)) {
sql = switch_mprintf("DELETE FROM members WHERE system = 'single_box' AND uuid = '%q' AND (abandoned_epoch = '%ld' OR joined_epoch = '%q')", cbt.member_uuid, abandoned_epoch, cbt.member_joined_epoch);
if (abandoned_epoch + discard_abandoned_after < local_epoch_time_now(NULL)) {
sql = switch_mprintf("DELETE FROM members WHERE system = 'single_box' AND uuid = '%q' AND (abandoned_epoch = '%" SWITCH_TIME_T_FMT "' OR joined_epoch = '%q')", cbt.member_uuid, abandoned_epoch, cbt.member_joined_epoch);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
}
@@ -1985,45 +2015,104 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
cbt.strategy = queue_strategy;
cbt.record_template = queue_record_template;
cbt.agent_found = SWITCH_FALSE;
if (!strcasecmp(queue->strategy, "longest-idle-agent")) {
sql_order_by = switch_mprintf("level, agents.last_offered_call, position");
} else if (!strcasecmp(queue_strategy, "agent-with-least-talk-time")) {
sql_order_by = switch_mprintf("level, agents.talk_time, position");
} else if (!strcasecmp(queue_strategy, "agent-with-fewest-calls")) {
sql_order_by = switch_mprintf("level, agents.calls_answered, position");
} else if (!strcasecmp(queue_strategy, "ring-all")) {
sql = switch_mprintf("UPDATE members SET state = '%q' WHERE state = '%q' AND uuid = '%q' AND system = 'single_box'",
cc_member_state2str(CC_MEMBER_STATE_TRYING), cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
sql_order_by = switch_mprintf("level, position");
} else if(!strcasecmp(queue_strategy, "sequentially-by-agent-order")) {
sql_order_by = switch_mprintf("level, position, agents.last_offered_call"); /* Default to last_offered_call, let add new strategy if needing it differently */
} else {
/* If the strategy doesn't exist, just fallback to the following */
sql_order_by = switch_mprintf("level, position, agents.last_offered_call");
}
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.level, agents.type, agents.uuid FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" ORDER BY %q",
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND),
sql_order_by);
if (!strcasecmp(queue->strategy, "top-down")) {
/* WARNING this use channel variable to help dispatch... might need to be reviewed to save it in DB to make this multi server prooft in the future */
switch_core_session_t *member_session = switch_core_session_locate(cbt.member_session_uuid);
int position = 0, level = 0;
const char *last_agent_tier_position, *last_agent_tier_level;
if (member_session) {
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
if ((last_agent_tier_position = switch_channel_get_variable(member_channel, "cc_last_agent_tier_position"))) {
position = atoi(last_agent_tier_position);
}
if ((last_agent_tier_level = switch_channel_get_variable(member_channel, "cc_last_agent_tier_level"))) {
level = atoi(last_agent_tier_level);
}
switch_core_session_rwunlock(member_session);
}
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.position as tiers_position, tiers.level as tiers_level, agents.type, agents.uuid, agents.last_offered_call as agents_last_offered_call, 1 as dyn_order FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" AND tiers.position > %d"
" AND tiers.level = %d"
" UNION "
"SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.position as tiers_position, tiers.level as tiers_level, agents.type, agents.uuid, agents.last_offered_call as agents_last_offered_call, 2 as dyn_order FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" ORDER BY dyn_order asc, tiers_level, tiers_position, agents_last_offered_call",
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND),
position,
level,
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND)
);
} else if (!strcasecmp(queue->strategy, "round-robin")) {
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.position as tiers_position, tiers.level as tiers_level, agents.type, agents.uuid, agents.last_offered_call as agents_last_offered_call, 1 as dyn_order FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" AND tiers.position > (SELECT tiers.position FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent) WHERE tiers.queue = '%q' AND agents.last_offered_call > 0 ORDER BY agents.last_offered_call DESC LIMIT 1)"
" AND tiers.level = (SELECT tiers.level FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent) WHERE tiers.queue = '%q' AND agents.last_offered_call > 0 ORDER BY agents.last_offered_call DESC LIMIT 1)"
" UNION "
"SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.position as tiers_position, tiers.level as tiers_level, agents.type, agents.uuid, agents.last_offered_call as agents_last_offered_call, 2 as dyn_order FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" ORDER BY dyn_order asc, tiers_level, tiers_position, agents_last_offered_call",
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND),
queue_name,
queue_name,
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND)
);
} else {
if (!strcasecmp(queue->strategy, "longest-idle-agent")) {
sql_order_by = switch_mprintf("level, agents.last_offered_call, position");
} else if (!strcasecmp(queue_strategy, "agent-with-least-talk-time")) {
sql_order_by = switch_mprintf("level, agents.talk_time, position");
} else if (!strcasecmp(queue_strategy, "agent-with-fewest-calls")) {
sql_order_by = switch_mprintf("level, agents.calls_answered, position");
} else if (!strcasecmp(queue_strategy, "ring-all")) {
sql = switch_mprintf("UPDATE members SET state = '%q' WHERE state = '%q' AND uuid = '%q' AND system = 'single_box'",
cc_member_state2str(CC_MEMBER_STATE_TRYING), cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
sql_order_by = switch_mprintf("level, position");
} else if(!strcasecmp(queue_strategy, "random")) {
sql_order_by = switch_mprintf("level, random()");
} else if(!strcasecmp(queue_strategy, "sequentially-by-agent-order")) {
sql_order_by = switch_mprintf("level, position, agents.last_offered_call"); /* Default to last_offered_call, let add new strategy if needing it differently */
} else {
/* If the strategy doesn't exist, just fallback to the following */
sql_order_by = switch_mprintf("level, position, agents.last_offered_call");
}
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.position, tiers.level, agents.type, agents.uuid FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" ORDER BY %q",
queue_name,
cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND),
sql_order_by);
switch_safe_free(sql_order_by);
}
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, agents_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
switch_safe_free(sql_order_by);
/* We update a field in the queue struct so we can kick caller out if waiting for too long with no agent */
if (!cbt.queue_name || !(queue = get_queue(cbt.queue_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", cbt.queue_name);
goto end;
} else {
queue->last_agent_exist_check = switch_epoch_time_now(NULL);
queue->last_agent_exist_check = local_epoch_time_now(NULL);
if (cbt.agent_found) {
queue->last_agent_exist = queue->last_agent_exist_check;
}
@@ -2062,9 +2151,9 @@ void *SWITCH_THREAD_FUNC cc_agent_dispatch_thread_run(switch_thread_t *thread, v
while (globals.running == 1) {
char *sql = NULL;
sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%ld-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch FROM members"
sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch FROM members"
" WHERE state = '%q' OR state = '%q' OR (serving_agent = 'ring-all' AND state = '%q') ORDER BY score DESC",
(long) switch_epoch_time_now(NULL),
local_epoch_time_now(NULL),
cc_member_state2str(CC_MEMBER_STATE_WAITING), cc_member_state2str(CC_MEMBER_STATE_ABANDONED), cc_member_state2str(CC_MEMBER_STATE_TRYING));
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, members_callback, NULL /* Call back variables */);
@@ -2113,6 +2202,8 @@ struct member_thread_helper {
const char *queue_name;
const char *member_uuid;
const char *member_session_uuid;
const char *member_cid_name;
const char *member_cid_number;
switch_time_t t_member_called;
cc_member_cancel_reason_t member_cancel_reason;
@@ -2126,10 +2217,6 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
switch_core_session_t *member_session = switch_core_session_locate(m->member_session_uuid);
switch_channel_t *member_channel = NULL;
switch_mutex_lock(globals.mutex);
globals.threads++;
switch_mutex_unlock(globals.mutex);
if (member_session) {
member_channel = switch_core_session_get_channel(member_session);
} else {
@@ -2137,15 +2224,20 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
return NULL;
}
switch_mutex_lock(globals.mutex);
globals.threads++;
switch_mutex_unlock(globals.mutex);
while(switch_channel_ready(member_channel) && m->running && globals.running) {
cc_queue_t *queue = NULL;
if (!m->queue_name || !(queue = get_queue(m->queue_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found\n", m->queue_name);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Queue %s not found\n", m->queue_name);
break;
}
/* Make the Caller Leave if he went over his max wait time */
if (queue->max_wait_time > 0 && queue->max_wait_time <= switch_epoch_time_now(NULL) - m->t_member_called) {
if (queue->max_wait_time > 0 && queue->max_wait_time <= local_epoch_time_now(NULL) - m->t_member_called) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> in queue '%s' reached max wait time\n", m->member_cid_name, m->member_cid_number, m->queue_name);
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_TIMEOUT;
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
}
@@ -2153,6 +2245,7 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
/* Will drop the caller if no agent was found for more than X seconds */
if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - queue->max_wait_time_with_no_agent_time_reached &&
queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> in queue '%s' reached max wait with no agent time\n", m->member_cid_name, m->member_cid_number, m->queue_name);
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT;
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
}
@@ -2218,7 +2311,6 @@ static switch_status_t moh_on_dtmf(switch_core_session_t *session, void *input,
SWITCH_STANDARD_APP(callcenter_function)
{
int argc = 0;
char *argv[6] = { 0 };
char *mydata = NULL;
cc_queue_t *queue = NULL;
@@ -2238,17 +2330,19 @@ SWITCH_STANDARD_APP(callcenter_function)
const char *cur_moh = NULL;
char start_epoch[64];
switch_event_t *event;
switch_time_t t_member_called = switch_epoch_time_now(NULL);
switch_time_t t_member_called = local_epoch_time_now(NULL);
long abandoned_epoch = 0;
const char *agent_uuid = NULL;
switch_uuid_t smember_uuid;
char member_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = "";
switch_bool_t agent_found = SWITCH_FALSE;
switch_bool_t moh_valid = SWITCH_TRUE;
const char *p;
if (!zstr(data)) {
mydata = switch_core_session_strdup(member_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_LOG, SWITCH_LOG_WARNING, "No Queue name provided\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "No Queue name provided\n");
goto end;
}
@@ -2257,7 +2351,7 @@ SWITCH_STANDARD_APP(callcenter_function)
}
if (!queue_name || !(queue = get_queue(queue_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found\n", queue_name);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Queue %s not found\n", queue_name);
goto end;
}
@@ -2303,7 +2397,7 @@ SWITCH_STANDARD_APP(callcenter_function)
/* If system, will add the total time the session is up to the base score */
if (!switch_strlen_zero(start_epoch) && !strcasecmp("system", queue->time_base_score)) {
cc_base_score_int += ((long) switch_epoch_time_now(NULL) - atol(start_epoch));
cc_base_score_int += ((long) local_epoch_time_now(NULL) - atol(start_epoch));
}
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
@@ -2317,19 +2411,21 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_event_fire(&event);
}
/* for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_queue_joined_epoch", "%ld", (long) switch_epoch_time_now(NULL));
switch_channel_set_variable_printf(member_channel, "cc_queue_joined_epoch", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
switch_channel_set_variable(member_channel, "cc_queue", queue_name);
if (abandoned_epoch == 0) {
/* Add the caller to the member queue */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> joining queue %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
sql = switch_mprintf("INSERT INTO members"
" (queue,system,uuid,session_uuid,system_epoch,joined_epoch,base_score,skill_score,cid_number,cid_name,serving_agent,serving_system,state)"
" VALUES('%q','single_box','%q','%q','%q','%ld','%d','%d','%q','%q','%q','','%q')",
" VALUES('%q','single_box','%q','%q','%q','%" SWITCH_TIME_T_FMT "','%d','%d','%q','%q','%q','','%q')",
queue_name,
member_uuid,
member_session_uuid,
start_epoch,
(long) switch_epoch_time_now(NULL),
local_epoch_time_now(NULL),
cc_base_score_int,
0 /*TODO SKILL score*/,
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")),
@@ -2340,21 +2436,24 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_safe_free(sql);
} else {
char res[256];
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> restoring it previous position in queue %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
/* Update abandoned member */
sql = switch_mprintf("UPDATE members SET session_uuid = '%q', state = '%q', rejoined_epoch = '%ld' WHERE uuid = '%q' AND state = '%q'",
member_session_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), member_uuid, cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
sql = switch_mprintf("UPDATE members SET session_uuid = '%q', state = '%q', rejoined_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND state = '%q'",
member_session_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), local_epoch_time_now(NULL), member_uuid, cc_member_state2str(CC_MEMBER_STATE_ABANDONED));
cc_execute_sql(queue, sql, NULL);
switch_safe_free(sql);
/* Confirm we took that member in */
sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND session_uuid = '%q' AND state = '%q' AND queue = '%q'", member_session, member_session_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name);
sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND session_uuid = '%q' AND state = '%q' AND queue = '%q'", member_uuid, member_session_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name);
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
if (atol(res) == 0) {
/* Failed to get the member !!! */
/* TODO Loop back to just create a uuid and add the member as a new member */
/* TODO ERROR MSG */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_ERROR, "Member %s <%s> restoring action failed in queue %s, exiting\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
queue_rwunlock(queue);
goto end;
}
@@ -2371,6 +2470,8 @@ SWITCH_STANDARD_APP(callcenter_function)
h->pool = pool;
h->member_uuid = switch_core_strdup(h->pool, member_uuid);
h->member_session_uuid = switch_core_strdup(h->pool, member_session_uuid);
h->member_cid_name = switch_core_strdup(h->pool, switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
h->member_cid_number = switch_core_strdup(h->pool, switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
h->queue_name = switch_core_strdup(h->pool, queue_name);
h->t_member_called = t_member_called;
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NONE;
@@ -2399,7 +2500,7 @@ SWITCH_STANDARD_APP(callcenter_function)
args.buflen = sizeof(h);
/* An agent was found, time to exit and let the bridge do it job */
if ((agent_uuid = switch_channel_get_variable(member_channel, "cc_agent_uuid"))) {
if ((p = switch_channel_get_variable(member_channel, "cc_agent_found")) && (agent_found = switch_true(p))) {
break;
}
/* If the member thread set a different reason, we monitor it so we can quit the wait */
@@ -2409,10 +2510,15 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_core_session_flush_private_events(member_session);
if (cur_moh) {
if (moh_valid && cur_moh) {
switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args);
if (!SWITCH_READ_ACCEPTABLE(status)) {
if (status == SWITCH_STATUS_FALSE /* Invalid Recording */ && SWITCH_READ_ACCEPTABLE(status)) {
/* Sadly, there doesn't seem to be a return to switch_ivr_play_file that tell you the file wasn't found. FALSE also mean that the channel got switch to BRAKE state, so we check for read acceptable */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Couldn't play file '%s', continuing wait with no audio\n", cur_moh);
moh_valid = SWITCH_FALSE;
} else if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
@@ -2424,34 +2530,42 @@ SWITCH_STANDARD_APP(callcenter_function)
}
/* Make sure that an agent was not found, since we could have break out before settign it previously */
if (!agent_found && (p = switch_channel_get_variable(member_channel, "cc_agent_found"))) {
agent_found = switch_true(p);
}
/* Stop Member Thread */
if (h) {
h->running = 0;
}
/* Check if we were removed be cause FS Core(BREAK) asked us too */
if (h->member_cancel_reason == CC_MEMBER_CANCEL_REASON_NONE && !switch_channel_get_variable(member_channel, "cc_agent_uuid")) {
if (h->member_cancel_reason == CC_MEMBER_CANCEL_REASON_NONE && !agent_found) {
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_BREAK_OUT;
}
switch_channel_set_variable(member_channel, "cc_agent_found", NULL);
/* Canceled for some reason */
if (!switch_channel_up(member_channel) || h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> abandoned waiting in queue %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid);
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%" SWITCH_TIME_T_FMT "' WHERE system = 'single_box' AND uuid = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), local_epoch_time_now(NULL), member_uuid);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
/* Hangup any callback agents */
switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
switch_core_session_hupall_matching_var("cc_member_pre_answer_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
/* Generate an event */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(member_channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Leaving-Time", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Member-Joined-Time", "%" SWITCH_TIME_T_FMT, t_member_called);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Cancel");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cancel-Reason", cc_member_cancel_reason2str(h->member_cancel_reason));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-UUID", member_uuid);
@@ -2462,20 +2576,22 @@ SWITCH_STANDARD_APP(callcenter_function)
}
/* Update some channel variables for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%ld", (long) switch_epoch_time_now(NULL));
switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%" SWITCH_TIME_T_FMT, local_epoch_time_now(NULL));
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "cancel");
switch_channel_set_variable_printf(member_channel, "cc_cancel_reason", "%s", cc_member_cancel_reason2str(h->member_cancel_reason));
/* Print some debug log information */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n",
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n",
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")),
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")),
queue_name, cc_member_cancel_reason2str(h->member_cancel_reason));
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> is answered by an agent in queue %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), member_uuid);
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%" SWITCH_TIME_T_FMT "' WHERE system = 'single_box' AND uuid = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), local_epoch_time_now(NULL), member_uuid);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -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);
@@ -249,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;
}
@@ -520,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;
}
@@ -2601,7 +2605,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])));
@@ -2635,7 +2638,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");
}
@@ -2648,7 +2651,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])));
@@ -2678,7 +2680,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");
}
@@ -2763,8 +2765,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;
}
@@ -2781,7 +2781,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;
@@ -3863,13 +3863,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");
@@ -3884,7 +3881,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];
@@ -4378,10 +4375,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);
@@ -4689,13 +4686,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;
@@ -5156,6 +5152,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>");
@@ -156,7 +156,9 @@ typedef enum {
CFLAG_VID_FLOOR = (1 << 8),
CFLAG_WASTE_BANDWIDTH = (1 << 9),
CFLAG_OUTCALL = (1 << 10),
CFLAG_INHASH = (1 << 11)
CFLAG_INHASH = (1 << 11),
CFLAG_EXIT_SOUND = (1 << 12),
CFLAG_ENTER_SOUND = (1 << 13)
} conf_flag_t;
typedef enum {
@@ -198,7 +200,6 @@ typedef enum {
EFLAG_FLOOR_CHANGE = (1 << 25),
EFLAG_MUTE_DETECT = (1 << 26),
EFLAG_RECORD = (1 << 27),
EFLAG_AUTO_GAIN_LEVEL = (1 << 28)
} event_type_t;
typedef struct conference_file_node {
@@ -717,12 +718,14 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
if (!switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ) && !zstr(conference->enter_sound)) {
const char * enter_sound = switch_channel_get_variable(channel, "conference_enter_sound");
if (!zstr(enter_sound)) {
conference_play_file(conference, (char *)enter_sound, CONF_DEFAULT_LEADIN,
switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
} else {
conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session),
!switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) {
if (!zstr(enter_sound)) {
conference_play_file(conference, (char *)enter_sound, CONF_DEFAULT_LEADIN,
switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
} else {
conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session),
!switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
}
}
}
}
@@ -774,7 +777,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
}
switch_channel_clear_app_flag_key("conf_silent", channel, CONF_SILENT_REQ);
switch_channel_set_app_flag_key("conf_silent", channel, CONF_SILENT_DONE);
switch_ivr_dmachine_create(&member->dmachine, "mod_conference", NULL, 500, 0, NULL, NULL, NULL);
@@ -811,12 +814,19 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
switch_event_t *event;
conference_file_node_t *member_fnode;
switch_speech_handle_t *member_sh;
const char *exit_sound = NULL;
switch_assert(conference != NULL);
switch_assert(member != NULL);
switch_thread_rwlock_wrlock(member->rwlock);
if (member->session && (exit_sound = switch_channel_get_variable(switch_core_session_get_channel(member->session), "conference_exit_sound"))) {
conference_play_file(conference, (char *)exit_sound, CONF_DEFAULT_LEADIN,
switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
}
lock_member(member);
member_fnode = member->fnode;
member_sh = member->sh;
@@ -906,7 +916,7 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
|| (switch_test_flag(conference, CFLAG_DYNAMIC) && conference->count == 0)) {
switch_set_flag(conference, CFLAG_DESTRUCT);
} else {
if (conference->exit_sound) {
if (!exit_sound && conference->exit_sound && switch_test_flag(conference, CFLAG_EXIT_SOUND)) {
conference_play_file(conference, conference->exit_sound, 0, switch_core_session_get_channel(member->session), 0);
}
if (conference->count == 1 && conference->alone_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) {
@@ -944,7 +954,7 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
conference_member_t *imember;
switch_frame_t *vid_frame;
switch_status_t status;
int has_vid = 1, req_iframe = 0;
int has_vid = 1;// req_iframe = 0;
int yield = 0;
uint32_t last_member = 0;
switch_core_session_t *session;
@@ -979,7 +989,7 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
if (!SWITCH_READ_ACCEPTABLE(status) || !conference->floor_holder || switch_test_flag(vid_frame, SFF_CNG)) {
conference->floor_holder = NULL;
req_iframe = 0;
//req_iframe = 0;
goto do_continue;
}
@@ -1014,7 +1024,7 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
goto do_continue;
}
req_iframe = 0;
//req_iframe = 0;
}
last_member = conference->floor_holder->id;
@@ -1619,7 +1629,7 @@ static void conference_loop_fn_energy_up(conference_member_t *member, caller_con
if (member == NULL)
return;
lock_member(member);
member->energy_level += 200;
if (member->energy_level > 1800) {
member->energy_level = 1800;
@@ -1632,7 +1642,6 @@ static void conference_loop_fn_energy_up(conference_member_t *member, caller_con
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->energy_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Energy level %d", member->energy_level);
//conference_member_say(member, msg, 0);
@@ -1656,7 +1665,6 @@ static void conference_loop_fn_energy_equ_conf(conference_member_t *member, call
if (member == NULL)
return;
lock_member(member);
member->energy_level = member->conference->energy_level;
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
@@ -1666,7 +1674,6 @@ static void conference_loop_fn_energy_equ_conf(conference_member_t *member, call
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->energy_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Energy level %d", member->energy_level);
//conference_member_say(member, msg, 0);
@@ -1687,7 +1694,6 @@ static void conference_loop_fn_energy_dn(conference_member_t *member, caller_con
if (member == NULL)
return;
lock_member(member);
member->energy_level -= 200;
if (member->energy_level < 0) {
member->energy_level = 0;
@@ -1700,7 +1706,6 @@ static void conference_loop_fn_energy_dn(conference_member_t *member, caller_con
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->energy_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Energy level %d", member->energy_level);
//conference_member_say(member, msg, 0);
@@ -1721,7 +1726,6 @@ static void conference_loop_fn_volume_talk_up(conference_member_t *member, calle
if (member == NULL)
return;
lock_member(member);
member->volume_out_level++;
switch_normalize_volume(member->volume_out_level);
@@ -1732,7 +1736,6 @@ static void conference_loop_fn_volume_talk_up(conference_member_t *member, calle
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_out_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
//conference_member_say(member, msg, 0);
@@ -1755,7 +1758,6 @@ static void conference_loop_fn_volume_talk_zero(conference_member_t *member, cal
if (member == NULL)
return;
lock_member(member);
member->volume_out_level = 0;
if (test_eflag(member->conference, EFLAG_VOLUME_LEVEL) &&
@@ -1765,7 +1767,6 @@ static void conference_loop_fn_volume_talk_zero(conference_member_t *member, cal
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_out_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
//conference_member_say(member, msg, 0);
@@ -1788,7 +1789,6 @@ static void conference_loop_fn_volume_talk_dn(conference_member_t *member, calle
if (member == NULL)
return;
lock_member(member);
member->volume_out_level--;
switch_normalize_volume(member->volume_out_level);
@@ -1799,7 +1799,6 @@ static void conference_loop_fn_volume_talk_dn(conference_member_t *member, calle
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_out_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
//conference_member_say(member, msg, 0);
@@ -1821,7 +1820,6 @@ static void conference_loop_fn_volume_listen_up(conference_member_t *member, cal
if (member == NULL)
return;
lock_member(member);
member->volume_in_level++;
switch_normalize_volume(member->volume_in_level);
@@ -1832,7 +1830,6 @@ static void conference_loop_fn_volume_listen_up(conference_member_t *member, cal
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_in_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Gain level %d", member->volume_in_level);
//conference_member_say(member, msg, 0);
@@ -1855,7 +1852,6 @@ static void conference_loop_fn_volume_listen_zero(conference_member_t *member, c
if (member == NULL)
return;
lock_member(member);
member->volume_in_level = 0;
if (test_eflag(member->conference, EFLAG_GAIN_LEVEL) &&
@@ -1865,7 +1861,6 @@ static void conference_loop_fn_volume_listen_zero(conference_member_t *member, c
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_in_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Gain level %d", member->volume_in_level);
//conference_member_say(member, msg, 0);
@@ -1888,7 +1883,6 @@ static void conference_loop_fn_volume_listen_dn(conference_member_t *member, cal
if (member == NULL)
return;
lock_member(member);
member->volume_in_level--;
switch_normalize_volume(member->volume_in_level);
@@ -1899,7 +1893,6 @@ static void conference_loop_fn_volume_listen_dn(conference_member_t *member, cal
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_in_level);
switch_event_fire(&event);
}
unlock_member(member);
//switch_snprintf(msg, sizeof(msg), "Gain level %d", member->volume_in_level);
//conference_member_say(member, msg, 0);
@@ -1992,22 +1985,20 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont
switch_event_fire(&event);
}
if ((mydata = switch_core_session_strdup(member->session, action->expanded_data))) {
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
if (argc > 0) {
app = argv[0];
}
if (argc > 1) {
arg = argv[1];
}
mydata = strdup(action->expanded_data);
switch_assert(mydata);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty execute app string [%s]\n",
(char *) action->expanded_data);
goto done;
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
if (argc > 0) {
app = argv[0];
}
if (argc > 1) {
arg = argv[1];
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Unable to allocate memory to duplicate execute_app data.\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty execute app string [%s]\n",
(char *) action->expanded_data);
goto done;
}
@@ -2025,8 +2016,11 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont
switch_core_session_execute_application(member->session, app, arg);
switch_core_session_set_read_codec(member->session, &member->read_codec);
switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
done:
switch_safe_free(mydata);
return;
}
@@ -2068,7 +2062,7 @@ static void clear_avg(conference_member_t *member)
static void check_agc_levels(conference_member_t *member)
{
int x = 0, y = member->agc_volume_in_level;
int x = 0;
if (!member->avg_score) return;
@@ -2083,8 +2077,6 @@ static void check_agc_levels(conference_member_t *member)
}
if (x) {
switch_event_t *event;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7,
"AGC %s:%d diff:%d level:%d cur:%d avg:%d vol:%d %s\n",
member->conference->name,
@@ -2092,17 +2084,6 @@ static void check_agc_levels(conference_member_t *member)
member->score, member->avg_score, member->agc_volume_in_level, x > 0 ? "+++" : "---");
clear_avg(member);
if (test_eflag(member->conference, EFLAG_AUTO_GAIN_LEVEL) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_member_data(member, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "auto-gain-level");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-Level", "%d", y);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->agc_volume_in_level);
switch_event_fire(&event);
}
}
}
@@ -2507,30 +2488,20 @@ static void conference_loop_output(conference_member_t *member)
switch_timer_t timer = { 0 };
uint32_t interval;
uint32_t samples;
uint32_t csamples;
//uint32_t csamples;
uint32_t tsamples;
uint32_t flush_len;
uint32_t low_count, bytes;
call_list_t *call_list, *cp;
int restarting = -1;
switch_codec_implementation_t read_impl = { 0 };
top:
switch_core_session_get_read_impl(member->session, &read_impl);
restarting++;
if (switch_test_flag(member, MFLAG_RESTART)) {
switch_clear_flag(member, MFLAG_RESTART);
switch_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
switch_core_timer_destroy(&timer);
}
channel = switch_core_session_get_channel(member->session);
interval = read_impl.microseconds_per_packet / 1000;
samples = switch_samples_per_packet(member->conference->rate, interval);
csamples = samples;
//csamples = samples;
tsamples = member->orig_read_impl.samples_per_packet;
flush_len = 0;
low_count = 0;
@@ -2552,82 +2523,77 @@ static void conference_loop_output(conference_member_t *member)
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Setup timer %s success interval: %u samples: %u\n",
member->conference->timer_name, interval, tsamples);
if (!restarting) {
write_frame.data = data = switch_core_session_alloc(member->session, SWITCH_RECOMMENDED_BUFFER_SIZE);
write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
}
write_frame.data = data = switch_core_session_alloc(member->session, SWITCH_RECOMMENDED_BUFFER_SIZE);
write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
write_frame.codec = &member->write_codec;
if (!restarting) {
/* Start the input thread */
launch_conference_loop_input(member, switch_core_session_get_pool(member->session));
/* Start the input thread */
launch_conference_loop_input(member, switch_core_session_get_pool(member->session));
if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) {
const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name");
const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number");
const char *toval = switch_channel_get_variable(channel, "conference_auto_outcall_timeout");
const char *flags = switch_channel_get_variable(channel, "conference_auto_outcall_flags");
const char *profile = switch_channel_get_variable(channel, "conference_auto_outcall_profile");
const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce");
const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix");
int to = 60;
if (ann && !switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ)) {
member->conference->special_announce = switch_core_strdup(member->conference->pool, ann);
}
switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
switch_set_flag(member->conference, CFLAG_OUTCALL);
if (toval) {
to = atoi(toval);
if (to < 10 || to > 500) {
to = 60;
}
}
for (cp = call_list; cp; cp = cp->next) {
int argc;
char *argv[512] = { 0 };
char *cpstr = strdup(cp->string);
int x = 0;
switch_assert(cpstr);
argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
for (x = 0; x < argc; x++) {
char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
switch_assert(dial_str);
conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL,
profile, &member->conference->cancel_cause);
switch_safe_free(dial_str);
}
switch_safe_free(cpstr);
}
do {
switch_ivr_sleep(member->session, 500, SWITCH_TRUE, NULL);
} while(switch_channel_up(channel) && member->conference->originating);
if (!switch_channel_ready(channel)) {
member->conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
goto end;
}
conference_member_play_file(member, "tone_stream://%(500,0,640)", 0);
if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) {
const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name");
const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number");
const char *toval = switch_channel_get_variable(channel, "conference_auto_outcall_timeout");
const char *flags = switch_channel_get_variable(channel, "conference_auto_outcall_flags");
const char *profile = switch_channel_get_variable(channel, "conference_auto_outcall_profile");
const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce");
const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix");
int to = 60;
if (ann && !switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ)) {
member->conference->special_announce = switch_core_strdup(member->conference->pool, ann);
}
switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
switch_set_flag(member->conference, CFLAG_OUTCALL);
if (toval) {
to = atoi(toval);
if (to < 10 || to > 500) {
to = 60;
}
}
for (cp = call_list; cp; cp = cp->next) {
int argc;
char *argv[512] = { 0 };
char *cpstr = strdup(cp->string);
int x = 0;
switch_assert(cpstr);
argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
for (x = 0; x < argc; x++) {
char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
switch_assert(dial_str);
conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL,
profile, &member->conference->cancel_cause);
switch_safe_free(dial_str);
}
switch_safe_free(cpstr);
}
switch_channel_set_app_flag(channel, CF_APP_TAGGED);
do {
switch_ivr_sleep(member->session, 500, SWITCH_TRUE, NULL);
} while(switch_channel_up(channel) && member->conference->originating);
switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
if (!switch_channel_ready(channel)) {
member->conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
goto end;
}
conference_member_play_file(member, "tone_stream://%(500,0,640)", 0);
}
if (!switch_test_flag(member->conference, CFLAG_ANSWERED)) {
switch_channel_answer(channel);
}
if (restarting) {
switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
}
/* Fair WARNING, If you expect the caller to hear anything or for digit handling to be processed, */
/* you better not block this thread loop for more than the duration of member->conference->timer_name! */
while (switch_test_flag(member, MFLAG_RUNNING) && switch_test_flag(member, MFLAG_ITHREAD)
@@ -2640,11 +2606,6 @@ static void conference_loop_output(conference_member_t *member)
switch_mutex_lock(member->write_mutex);
if (switch_test_flag(member, MFLAG_RESTART)) {
switch_mutex_unlock(member->write_mutex);
goto top;
}
if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
if (event->event_id == SWITCH_EVENT_MESSAGE) {
char *from = switch_event_get_header(event, "from");
@@ -2830,7 +2791,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
conference_record_t *rec = (conference_record_t *) obj;
conference_obj_t *conference = rec->conference;
uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval);
uint32_t low_count = 0, mux_used;
uint32_t mux_used;
char *vval;
switch_timer_t timer = { 0 };
uint32_t rlen;
@@ -2957,7 +2918,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
if (mux_used >= data_buf_len) {
/* Flush the output buffer and write all the data (presumably muxed) to the file */
switch_mutex_lock(member->audio_out_mutex);
low_count = 0;
//low_count = 0;
if ((rlen = (uint32_t) switch_buffer_read(member->mux_buffer, data_buf, data_buf_len))) {
len = (switch_size_t) rlen / sizeof(int16_t);
@@ -2993,14 +2954,14 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
end:
for(;;) {
switch_mutex_lock(member->audio_out_mutex);
while(!no_data) {
switch_mutex_lock(member->audio_out_mutex);
if ((rlen = (uint32_t) switch_buffer_read(member->mux_buffer, data_buf, data_buf_len))) {
len = (switch_size_t) rlen / sizeof(int16_t);
switch_core_file_write(&fh, data_buf, &len);
} else {
break;
}
no_data = 1;
}
switch_mutex_unlock(member->audio_out_mutex);
}
@@ -3780,18 +3741,18 @@ static switch_status_t conf_api_sub_kick(conference_member_t *member, switch_str
{
switch_event_t *event;
if (member == NULL)
if (member == NULL) {
return SWITCH_STATUS_GENERR;
lock_member(member);
}
switch_clear_flag(member, MFLAG_RUNNING);
switch_set_flag_locked(member, MFLAG_KICKED);
switch_core_session_kill_channel(member->session, SWITCH_SIG_BREAK);
unlock_member(member);
if (stream != NULL) {
stream->write_function(stream, "OK kicked %u\n", member->id);
}
if (member->conference && test_eflag(member->conference, EFLAG_KICK_MEMBER)) {
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_member_data(member, event);
@@ -3799,6 +3760,7 @@ static switch_status_t conf_api_sub_kick(conference_member_t *member, switch_str
switch_event_fire(&event);
}
}
return SWITCH_STATUS_SUCCESS;
}
@@ -4023,7 +3985,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
switch_snprintf(i, sizeof(i), "%u", conference->rate);
switch_xml_set_attr_d(x_conference, "rate", ival);
switch_xml_set_attr_d(x_conference, "uuid", conference->uuid_str);
if (switch_test_flag(conference, CFLAG_LOCKED)) {
switch_xml_set_attr_d(x_conference, "locked", "true");
}
@@ -4056,6 +4018,14 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
switch_xml_set_attr_d(x_conference, "dynamic", "true");
}
if (switch_test_flag(conference, CFLAG_EXIT_SOUND)) {
switch_xml_set_attr_d(x_conference, "exit_sound", "true");
}
if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) {
switch_xml_set_attr_d(x_conference, "enter_sound", "true");
}
if (conference->record_count > 0) {
switch_xml_set_attr_d(x_conference, "recording", "true");
}
@@ -4078,7 +4048,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
switch_channel_t *channel;
switch_caller_profile_t *profile;
char *uuid;
char *name;
//char *name;
uint32_t count = 0;
switch_xml_t x_tag;
int toff = 0;
@@ -4091,7 +4061,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
uuid = switch_core_session_get_uuid(member->session);
channel = switch_core_session_get_channel(member->session);
profile = switch_channel_get_caller_profile(channel);
name = switch_channel_get_name(channel);
//name = switch_channel_get_name(channel);
x_member = switch_xml_add_child_d(x_members, "member", moff++);
@@ -4516,6 +4486,107 @@ static switch_status_t conf_api_sub_unlock(conference_obj_t *conference, switch_
return 0;
}
static switch_status_t conf_api_sub_exit_sound(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
switch_event_t *event;
switch_assert(conference != NULL);
switch_assert(stream != NULL);
if (argc <= 2) {
stream->write_function(stream, "Not enough args\n");
return SWITCH_STATUS_GENERR;
}
if ( !strcasecmp(argv[2], "on") ) {
switch_set_flag_locked(conference, CFLAG_EXIT_SOUND);
stream->write_function(stream, "OK %s exit sounds on (%s)\n", argv[0], conference->exit_sound);
if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "exit-sounds-on");
switch_event_fire(&event);
}
} else if ( !strcasecmp(argv[2], "off") || !strcasecmp(argv[2], "none") ) {
switch_clear_flag_locked(conference, CFLAG_EXIT_SOUND);
stream->write_function(stream, "OK %s exit sounds off (%s)\n", argv[0], conference->exit_sound);
if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "exit-sounds-off");
switch_event_fire(&event);
}
} else if ( !strcasecmp(argv[2], "file") ) {
if (! argv[3]) {
stream->write_function(stream, "No filename specified\n");
} else {
/* TODO: if possible, verify file exists before setting it */
stream->write_function(stream,"Old exit sound: [%s]\n", conference->exit_sound);
conference->exit_sound = switch_core_strdup(conference->pool, argv[3]);
stream->write_function(stream, "OK %s exit sound file set to %s\n", argv[0], conference->exit_sound);
if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "exit-sound-file-changed");
switch_event_fire(&event);
}
}
} else {
stream->write_function(stream, "Bad args\n");
return SWITCH_STATUS_GENERR;
}
return 0;
}
static switch_status_t conf_api_sub_enter_sound(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
switch_event_t *event;
switch_assert(conference != NULL);
switch_assert(stream != NULL);
if (argc <= 2) {
stream->write_function(stream, "Not enough args\n");
return SWITCH_STATUS_GENERR;
}
if ( !strcasecmp(argv[2], "on") ) {
switch_set_flag_locked(conference, CFLAG_ENTER_SOUND);
stream->write_function(stream, "OK %s enter sounds on (%s)\n", argv[0], conference->enter_sound);
if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "enter-sounds-on");
switch_event_fire(&event);
}
} else if ( !strcasecmp(argv[2], "off") || !strcasecmp(argv[2], "none") ) {
switch_clear_flag_locked(conference, CFLAG_ENTER_SOUND);
stream->write_function(stream, "OK %s enter sounds off (%s)\n", argv[0], conference->enter_sound);
if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "enter-sounds-off");
switch_event_fire(&event);
}
} else if ( !strcasecmp(argv[2], "file") ) {
if (! argv[3]) {
stream->write_function(stream, "No filename specified\n");
} else {
/* TODO: verify file exists before setting it */
conference->enter_sound = switch_core_strdup(conference->pool, argv[3]);
stream->write_function(stream, "OK %s enter sound file set to %s\n", argv[0], conference->enter_sound);
if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "enter-sound-file-changed");
switch_event_fire(&event);
}
}
} else {
stream->write_function(stream, "Bad args\n");
return SWITCH_STATUS_GENERR;
}
return 0;
}
static switch_status_t conf_api_sub_dial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
switch_call_cause_t cause;
@@ -4720,7 +4791,9 @@ typedef enum {
CONF_API_COMMAND_BGDIAL,
CONF_API_COMMAND_TRANSFER,
CONF_API_COMMAND_RECORD,
CONF_API_COMMAND_NORECORD
CONF_API_COMMAND_NORECORD,
CONF_API_COMMAND_EXIT_SOUND,
CONF_API_COMMAND_ENTER_SOUND,
} api_command_type_t;
/* API Interface Function sub-commands */
@@ -4750,6 +4823,8 @@ static api_command_t conf_api_sub_commands[] = {
{"transfer", (void_fn_t) & conf_api_sub_transfer, CONF_API_SUB_ARGS_SPLIT, "transfer", "<conference_name> <member id> [...<member id>]"},
{"record", (void_fn_t) & conf_api_sub_record, CONF_API_SUB_ARGS_SPLIT, "record", "<filename>"},
{"norecord", (void_fn_t) & conf_api_sub_norecord, CONF_API_SUB_ARGS_SPLIT, "norecord", "<[filename|all]>"},
{"exit_sound", (void_fn_t) & conf_api_sub_exit_sound, CONF_API_SUB_ARGS_SPLIT, "exit_sound", "on|off|none|file <filename>"},
{"enter_sound", (void_fn_t) & conf_api_sub_enter_sound, CONF_API_SUB_ARGS_SPLIT, "enter_sound", "on|off|none|file <filename>"},
{"pin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "pin", "<pin#>"},
{"nopin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "nopin", ""},
};
@@ -5330,7 +5405,7 @@ static void set_cflags(const char *flags, uint32_t *f)
} else if (!strcasecmp(argv[i], "waste-bandwidth")) {
*f |= CFLAG_WASTE_BANDWIDTH;
}
}
}
free(dup);
}
@@ -5543,7 +5618,7 @@ static int setup_media(conference_member_t *member, conference_obj_t *conference
SWITCH_STANDARD_APP(conference_function)
{
switch_codec_t *read_codec = NULL;
uint32_t flags = 0;
//uint32_t flags = 0;
conference_member_t member = { 0 };
conference_obj_t *conference = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
@@ -5931,7 +6006,7 @@ SWITCH_STANDARD_APP(conference_function)
member.pool = switch_core_session_get_pool(session);
if (setup_media(&member, conference)) {
flags = 0;
//flags = 0;
goto done;
}
@@ -6220,7 +6295,6 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
uint32_t announce_count = 0;
char *maxmember_sound = NULL;
uint32_t rate = 8000, interval = 20;
switch_status_t status;
int comfort_noise_level = 0;
char *suppress_events = NULL;
char *verbose_events = NULL;
@@ -6434,7 +6508,6 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
/* Setup a memory pool to use. */
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n");
status = SWITCH_STATUS_TERM;
conference = NULL;
goto end;
}
@@ -6443,7 +6516,6 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
/* Create the conference object. */
if (!(conference = switch_core_alloc(pool, sizeof(*conference)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
status = SWITCH_STATUS_TERM;
conference = NULL;
goto end;
}
@@ -6620,7 +6692,10 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
switch_uuid_format(uuid_str, &uuid);
conference->uuid_str = switch_core_strdup(conference->pool, uuid_str);
/* Set enter sound and exit sound flags so that default is on */
switch_set_flag(conference, CFLAG_ENTER_SOUND);
switch_set_flag(conference, CFLAG_EXIT_SOUND);
/* Activate the conference mutex for exclusivity */
switch_mutex_init(&conference->mutex, SWITCH_MUTEX_NESTED, conference->pool);
switch_mutex_init(&conference->flag_mutex, SWITCH_MUTEX_NESTED, conference->pool);
-3
View File
@@ -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";
}
+1 -1
View File
@@ -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");
+15 -8
View File
@@ -1552,7 +1552,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");
@@ -1582,10 +1583,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;
}
}
@@ -2291,14 +2298,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;
@@ -2483,7 +2490,7 @@ SWITCH_STANDARD_APP(audio_bridge_function)
const char *transfer_on_fail = NULL;
char *tof_data = NULL;
char *tof_array[4] = { 0 };
int tof_arrayc = 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;
@@ -2503,7 +2510,7 @@ SWITCH_STANDARD_APP(audio_bridge_function)
transfer_on_fail = switch_channel_get_variable(caller_channel, "transfer_on_fail");
tof_data = switch_core_session_strdup(session, transfer_on_fail);
tof_arrayc = switch_split(tof_data, ' ', tof_array);
switch_split(tof_data, ' ', tof_array);
transfer_on_fail = tof_array[0];
failure_causes = switch_channel_get_variable(caller_channel, "failure_causes");
+21
View File
@@ -70,6 +70,8 @@ static struct {
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);
@@ -109,6 +111,10 @@ 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");
@@ -120,7 +126,13 @@ static switch_status_t load_config(void)
} 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")) {
@@ -164,6 +176,7 @@ static switch_status_t load_config(void)
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;
}
}
@@ -403,6 +416,7 @@ switch_status_t ldns_lookup(const char *number, const char *root, const char *se
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");
@@ -430,6 +444,13 @@ switch_status_t ldns_lookup(const char *number, const char *root, const char *se
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,
+2 -2
View File
@@ -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);
+4 -9
View File
@@ -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);
+29 -8
View File
@@ -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");
+1 -2
View File
@@ -565,12 +565,11 @@ switch_status_t ladspa_session(switch_core_session_t *session, const char *flags
static void ladspa_parse(switch_core_session_t *session, const char *data)
{
char *argv[5] = { 0 };
int argc;
char *lbuf;
if (data) {
lbuf = strdup(data);
argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
ladspa_session(session, argv[0], argv[1], argv[2], argv[3]);
free(lbuf);
}
+41 -23
View File
@@ -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;
@@ -247,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;
@@ -621,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")) {
@@ -666,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,
@@ -760,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;
}
@@ -821,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);
}
@@ -843,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);
@@ -1062,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 ");
@@ -1076,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) {
@@ -1238,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);
@@ -1265,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");
@@ -1642,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 };
@@ -1767,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) {
@@ -1802,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);
}
@@ -1880,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");
}
+29
View File
@@ -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
+130
View File
@@ -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;
}
+49
View File
@@ -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_ */
+249
View File
@@ -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
*/
+30
View File
@@ -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);
+599
View File
@@ -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
*/
+31
View File
@@ -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>
+376
View File
@@ -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 -->
+175
View File
@@ -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);
}
+16
View File
@@ -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_ */
+5 -5
View File
@@ -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;
+2 -2
View File
@@ -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];
+76 -14
View File
@@ -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:
-2
View File
@@ -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;
+1 -2
View File
@@ -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,12 +2514,26 @@ 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 {
switch_safe_free(file_path);
file_path = (char *) path;
}
@@ -2957,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];
@@ -2973,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;
@@ -3030,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")) {
@@ -3073,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 {
@@ -3259,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);
@@ -3301,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;
@@ -3315,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 (;;) {
@@ -4329,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;
@@ -4341,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;
@@ -4480,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(&params, 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;
@@ -4521,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;
}
+54 -2
View File
@@ -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.");
+1 -1
View File
@@ -3369,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 {
@@ -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]);
}
@@ -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, '('))) {
@@ -30,6 +30,7 @@
*
*/
#include <switch.h>
#include <switch_ssl.h>
#include <switch_stun.h>
#include <libdingaling.h>
@@ -1399,7 +1400,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);
@@ -1443,7 +1444,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);
@@ -1911,6 +1912,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dingaling_load)
SWITCH_ADD_API(api_interface, "dingaling", "DingaLing Menu", dingaling, DINGALING_SYNTAX);
SWITCH_ADD_CHAT(chat_interface, MDL_CHAT_PROTO, chat_send);
switch_ssl_init_ssl_locks();
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
@@ -2008,6 +2012,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_dingaling_shutdown)
switch_safe_free(globals.codec_string);
switch_safe_free(globals.codec_rates_string);
switch_ssl_destroy_ssl_locks();
return SWITCH_STATUS_SUCCESS;
}
+20 -3
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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
+1 -1
View File
@@ -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 -->
+23 -7
View File
@@ -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;
}
+13 -3
View File
@@ -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;
+56 -33
View File
@@ -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!"
+29 -37
View File
@@ -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:
@@ -2415,7 +2415,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;
}
}
@@ -2543,6 +2543,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\"> "
+3 -1
View File
@@ -251,7 +251,7 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
PABLIO_Stream *aStream;
long numFrames;
//long numBytes;
int channels = 1;
//int channels = 1;
if (!(inputParameters || outputParameters)) {
return -1;
@@ -262,11 +262,13 @@ PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
switch_assert(aStream);
memset(aStream, 0, sizeof(PABLIO_Stream));
/*
if (inputParameters) {
channels = inputParameters->channelCount;
} else if (outputParameters) {
channels = outputParameters->channelCount;
}
*/
numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5);
aStream->bytesPerFrame = bytesPerSample;
+20 -10
View File
@@ -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;
+31 -2
View File
@@ -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;
+80 -18
View File
@@ -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;
}
}
+186 -163
View File
@@ -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
+24 -3
View File
@@ -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:
+20 -3
View File
@@ -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
@@ -0,0 +1,99 @@
<?xml version="1.0"?>
<config version="1.0" serial="3885" timestamp="1303333464.70">
<Lib>
<BCM>
<_2>00001000A563932E7DE5A581942041A820F8437512A079C7ACB1B73281F191D109521E265BCD38C4133596B834AD9AA1D6BB5E1AC3D59E8675785321F722D39FBFAFB9A24E6482FA3030FFA3692D2C4A53BBCE9DC63F25D10207A20FA969982FEDC1DCC2A7C599071F4735E52AB2E06E34CA232C08B3AA2FB88A0C4A5763E0CD23C3AA37D1D2A7D6EED691EE99BA08BE294F68C24F9AE777DAF294F0AEB8346325A978DC6CF7C210AD11EF3F38111F6D98F388CF41CCBA40ABE9F0D6CBBD3118BA0588344953DF3C5E88B2CCAEDE2E692F320D20EBF16D7DB36156E617C0CC9FB2855D7FDB4C7F8638CC9830E7448D5EAE301A2810277062989841EE679E00E4E277615FEC038DE3A0A20DD7C6A2A00DFBC6A2A00DA6E2B6F404FDC6A2A00DFEC6A2A00DF7FBBB990CF2C6A2A00D8EB4FE8A0C8FB4FE8A0C95C7A6E00CF5FBBB990CD6C7A6E00CD0F896950CCCE2B6F40485CCA2A00DA1D8EEA50DFDFBBB990CA7C7A6E00CA8C7A6E00CA9C7A6E00C97C7A6E00C90B4FE8A0CFE90D59308C290D59308D1E2B6F404C5E2B6F404C6AAF18705C7AAF18705C8AAF18705BBD8EEA50DBCD8EEA50DBDD8EEA50D93CCA2A00D94CCA2A00DEFE2B6F40491B4FE8A0CE2FBBB990CE3FBBB990CBED8EEA50DA0CCA2A00DA1CCA2A00DA6B4FE8A0CA7B4FE8A0CCED8EEA50DA3CCA2A00DA4CCA2A00D84E698AD0DB8C7A6E00CD9E2B6F404E0E2B6F40486E698AD0DFDF896950C0013A60400173D0018DE0200190300AB01F40300449875044518C15F9A278109D4BBAC4E8109D408A6238109D5A63304810904460CC15F9A26303ED408A624303E0047B054004801004980A305004A80E90F004BE0A801004C80A305004D01005CAC02045E5A50FC55465BA050FC55475BA050FC55485BA0C32EFDEE5BA0C32EFDEF5BA0C2A5BC4A5BA0C2A5BC4B5BA0D4BBAC055BA0D4BBAC145BA0D4BBAC215BA0D408A3575BA0D408A37D5BA0D408A37E5BA08275487E5BA0827548425BA00060B817046506CC09A3D6303E04AE018C0125F8D500021A25F9D500011A162102200301220125FFD50025FAD5000C03E4000D2580D6000F060125F8D5000302172105050103080D06010501011C210302060125FCD50025F9D5000A25FDD50025FED5000A0D06020502050119211305020380808080100C05010D0380808080100B25FDD5000C01080005000380808080100D060307010503220101220104AC01BF012597CE002597CE002590CE0019152590CE002597CE000B033C1815210220030122012593CE0014212E2594CE002103030B220125A5CE00030F172103030B22012596CE00142103030B22012597CE00142103030B22012599CE00142103030A220125A5CE00030A1A2590CE002592CE000B031E1B15142103030A220125A4CE000380201D14210303092201259BCE0014210A2594CE002103030B2201259DCE00142103030822012593CE002103012201259ECE001421030306220103022201006800006901006A01006C987504740CC2A5BC4C303ED408A34C303E007828047912CC09A3D3303E82754864303E4E8DB16F303E047DBF010203020800050003020D0B0601030308000500020501030508000500021A03060800050003041A16030508000500021D160C0A0C060203D00F251205020A03020D0A050103D00F0C0A0603010800050003FFFFFFFF0F18030208000500021D141506042512020800050003030D05040C10030205040B0C06050306050505020A0C060603040800050003050800050003E400180C0607050703E400250A0B250A011C0C0A0314100608050303C03E0F03B8171005060388270F03DC0B100508047E5E0380010304080005000B03040D250403E4000F03140D0A2503250203030D0A0B0110060101080005000380020D0302080005000380020D172103010601250A03E4001B210D0501030A03E400250A210303DF002002250A0B0D0F0601050100800180EA49008101E003036F3139352E34362E3235332E3235333A313233353000038201706F6F6C313D2A2E6C6976657461622E736B7970653B706F6F6C323D7765622E6578747261732E736B7970653B706F6F6C333D6578747261732E646F776E6C6F6164732E736B7970653B706F6F6C343D2A2E736B79706566696E642E736B7970653B706F6F6C353D2A2E7072656D69756D2E736B7970653B706F6F6C363D2A2E6D756C74696D656469612E736B7970653B706F6F6C373D2A2E6D756C74696D656469612E6D657461636166653B706F6F6C383D2A2E6D756C74696D656469612E6461696C796D6F74696F6E3B706F6F6C393D2A2E6D756C74696D656469612E6D6574616F6D6E69747572653B706F6F6C31303D77686174736E65772E736B7970653B706F6F6C31313D7061792E736B7970653B706F6F6C31323D7365637572652E7061792E736B7970653B706F6F6C31333D2A2E70696373746F72653B706F6F6C31343D2A2E6D796163636F756E742E736B7970653B706F6F6C31353D2A2E62696269743B706F6F6C31363D2A2E70726F6363796265723B706F6F6C31373D747261636B696E672E6F6D6E69747572653B706F6F6C31383D676F2E736B7970653B706F6F6C31393D747261636B2E736B7970657C706F6F6C313D3139342E3139322E3139392E3235313A31323335303B706F6F6C323D3139342E3139322E3139392E3235323A31323335303B706F6F6C333D3139342E3139322E3139392E3235323A31323335303B706F6F6C343D3139342E3136352E3138382E3130313A31323335303B706F6F6C353D3139332E39352E3135342E31353A31323335313B706F6F6C363D3139342E3136352E3138382E3130303A31323335303B706F6F6C373D3139342E3136352E3138382E3130303A31323335303B706F6F6C383D3139342E3136352E3138382E3130303A31323335303B706F6F6C393D3139342E3136352E3138382E3130303A31323335303B706F6F6C31303D3230342E392E3136332E3134313A31323335303B706F6F6C31313D3139352E34362E3235332E3234353A31323335303B706F6F6C31323D3139352E34362E3235332E3234353A31323335303B706F6F6C31333D3139332E39352E3135342E31343A31323335313B706F6F6C31343D3139332E39352E3135342E31343A31323335313B706F6F6C31353D3139332E39352E3135342E31343A31323335313B706F6F6C31363D3139332E39352E3135342E31343A31323335313B706F6F6C31373D3139342E3136352E3138382E3130303A31323335303B706F6F6C31383D3139342E3136352E3138382E3130303A31323335303B706F6F6C31393D3139332E39352E3135342E31343A31323335310003B101706F6F6C313D2A2E6C6976657461622E736B7970653B706F6F6C323D7765622E6578747261732E736B797065206578747261732E646F776E6C6F6164732E736B7970653B706F6F6C333D2A2Line truncated
<_256>000010011AC0AA3BA66DF7FB48228AE35F9BB4A032FE4A6A898DA7A1A5AE37DC59FB3D09607F1CACD46A5DBC008DABF8F09C797DF5A8903307D04C318825CEA7C481303C655A9EEE099E9A0AF1158373B458BB8FDACB336A6EC63C043E6782688E2350B417DDDDFF96B474DAEA7D1DF3742303B79111FC752BFB5D6887A5B822F945CC761FAF6E80DE5EC60868768CB8A9F9C876137806DCEA0DD1300181558ABFDBA26592078F5F84195C526D8C7F339EF82700FD93F8FB71ADA5ED3E977D27FA52D1F489EF5DA0A9E00B146BADCBDEBFB0DFEBCD61E5B8352A49893357E0DC3A736743929DA975782EA4D8184605FD064641986C47706D264281C876F926BF58003E9E</_256>
<_3>0000100498ECF8A7A4585F76C930739A1EAE590DE96D9EF3AA9B231E67965F3F08ECFC493E1DA23ECDE17A85C94CBE034E88F9414E9BBC82F32AAFCFFB2C09F6F57A478238BAEC9EEF2BB9C67F71257722E6786D88D6400F6B7D81450FB3B6CCCC3986E3782D2387E354EBA9099331AEF510D479C6601D2383D866E2B5B525DF0BA975D58C120EFAE88C89EE365FC696CC891B77F67CFA18FDE8E95DDAC25A7C7D70FA7A1414BAE593856A658888C622836006C1C131B4B2E805554DCFA52F3EFD34C1B759BF8A302E491835DCE701E84D37ED150C8ADD699AD3DCA9F515123C5B5AD94E253E173BA3465E64A0079D5EF4E6075E66D0F5FBC3D9BC25C4E80C4CB2FE9B87040003000004D00F0005D00F050041040400B80125C20003141B14230025D50003031B14230024E100142300250003191714230025EA0003141714230025EA00011724EA00140A14230025E400030F1C14230025FC00011A24FF000A14230025FF00011A142300258001011A14230025E10025E10003A006100A0309031725000325180C0A25C20003140B0C03040D0A03882725C3000C0A03E43225C4000C0A0602050228038407DC08FA1E0601050102050203FA1E1C0603250028061D1E1F202122060105010205010503050141060300636F756E74206279207175616C697479000001CC080002040003000004010005010501410603006261647175616C69747920636F756E742062792076657273696F6E000001D6080002070003000004010005010501410603006261647175616C6974792073756D2062792076657273696F6E000001E0080002070003000004010005010500410304005424E400142300250003191714230025EA0003141714230025EA00011724EA00140A14230025FC00011A24FF000A14230025FF00011A142300258001011A14230025E40025E40028043CB401D804901C060105010205014106030073756D206F66206C61737463616C6C206475726174696F6E73000001B009000201000300000480A3050005B054050141060300636F756E74206279206C61737463616C6C206475726174696F6E000001BA090002050003000004010005010500410204005025EB00011C142300250003191714230025EA0003141714230025EA00011724EA00140A14230025FC00011A24FF000A14230025FF00011A142300258001011A14230025EB0028031E32D0000601050102050141060300636F756E742062792073797374656D20637075207573616765000001940A0002040003000004010005010500410204004F25EC00011C142300250003191714230025EA0003141714230025EA00011724EA00140A14230025FC00011A24FF000A14230025FF00011A142300258001011A14230025EC0028030F1E320601050102050141060300636F756E742062792070726F63657373206370752075736167650000019E0A0002040003000004010005010500410304006824C20014230024E60014230025E600011A14230025EC00011C142300250003191714230025EA0003141714230025EA00011724EA00140A14230025FC00011A24FF000A14230025FF00011A142300258001011A14230025EC0028030F1E320601050102050125C2000501410603006A6974746572636F756E742062792070726F6365737320637075207573616765000001F80A0002040003000004010005010501410603006A69747465722062792070726F6365737320637075207573616765000001820B0002040003000004D00F0005D00F0500410304004424E700142300250003191714230025EA0003141714230025EA00011724EA00140A14230025FC00011A24FF000A14230025FF00011A142300258001011A1423000225E700050141060300706F74656E7469616C207463702066616C6C6261636B73000001DC0B00020100030000040100050105014106030061637475616C207463702066616C6C6261636B73000001E60B00020100030000040100050105004103040056240C142300250C030A1814230025EA0003141714230025EA00011724EA00140A14230024E70014230025E700011A14230024E50014230025E500011C0602250C29050306070809280401020405060105010205010502050141060300636F756E74206279206E617474797065000001C00C0002050003000004010005010501410603007564706661696C75726573206279206E617474797065000001CA0C0002050003000004010005010500410204001B25D90014230025D90025DA000B0602050228030102040601050102050141060300636F756E74206279206E726F666D756C74696368617473000001A40D0002040003000004010005010500410304001425F700011C14230025000319171423000225F90005014106030075736572732077686F206861766520636F6D706C65746564204943000001880E0002010003000004010005010501410603006C617374204943207969656C6420676C6F62616C73756D000001920E0002010003000004E8070005500500410304001224F60014230025000319171423000225F60005014106030075736572732077686F206861766520494320737570706F7274000001EC0E0002010003000004010005010501410603004943207374617274757020636F756E7420676C6F62616C73756D000001F60E00020100030000046400051405004102040025240C142300250C030A18142300250C011C142300250C280802030405060708090601050102050141060300636F756E74206279206E617474797065000001D00F0002090003000004010005010500410404001A250003191714230025E20025E30025FC00280201020601050102050141060300766964656F2073656E642063617061626C650000019811000201000300000401000501050141060300766964656F20706172616C6C656C2063616C6C730000019911000201000300000414000502050141060300636F756E7420627920766964656F2063616C6C73206D616465000001A2110002030003000004010005010500410204003A250003191714230025EA0003141714230025EA00011724EA00140A14230024E50014230025E50003031914230025E50028030102030601050102050141060300636F756E742062792073747265616D7472616E73706F7274000001FC11000204000300000401000501050041090400E00125C20003141B25E400030F1C1514230024E100142300250003191714230025EA0003141725EA0001171514230025FF002580010A011A14230025E60003031A25E50003031A1514230024F5001423002412142300249F0114230025C30025E10025E10003A006100A03A0060B0309031725000325180C0A25C20003140B0C03040D0A2512030A0C251025F5001703CC080C0A1C160602020502250003231B241D150603050305020503150503251D03808080808Line truncated
<_4>000010052A0B6759B71FBC1EF05BE97DFEA4EE6C1E15AF19ED70DEC1130B14C13CE41246D302B9662592907E3CA508A57702B5C00C2A05170857FA22012E0F235B425B4D919B23A541D3AD6E948FC634DE71A29493634884DFD5E9D89C5D951CBCD71B9B3ABFD3C4E2779BB1817D76E7C223CA36BD75A6A05B730AF138057E4048B2FFDD522BB588EC0B9D3E014BF9E354EB608150BC613C739D9E8C7465F05F047FAF7AFA3EE89B9B58BF0FC35F07B55CF3E4B59A7C4ED48B1C0C7F0305E6AC2E80AAEAD6064EB6ACDC1806FCE0B5CB66F0840DA7F0FE7B228E3898E3E42A9AFEFE13DDF019EF8D8F02A631AF2615BBC6E1EDB65C89A775F642C88109E6247EC4B463DC302E2A2E323000050541020006020307322E302E2A2E3100050541030006020307322E302E2A2E3200000AE4ED8009050541030006020307322E302E2A2E33000009B3E6CC990B050541040006020307322E302E2A2E3400000AE4ED8009000BA00B050541030006020308322E302E2A2E35000307322E302E2A2E3900050541040006020308322E302E2A2E39000307322E302E2A2E313100000AE4ED8009050541040006020308322E302E2A2E3131000307322E302E2A2E3135000009E6CC99B306050541050006020308322E302E2A2E3135000307322E302E2A2E323000000AE4ED8009000BA00B050041050303557067726164655465737433000301332E302E302E3130300003044E6963654272616E6400050541040006020307332E302E302E2A0003074E6963654272616E6400000AE4ED8009050541040006020307322E302E302E2A0003074E6963654272616E6400000AE4ED80090500410E0303557067726164655465737433000301332E302E302E31303000050541040006020307332E302E302E39390003074F746865724272616E6400000AE4ED8009050541040006020307322E302E302E39390003074F746865724272616E6400000AE4ED8009050541040006020307332E302E302E39380003074F746865724272616E64000009B3E6CC990B050541040006020307322E302E302E39380003074F746865724272616E64000009B3E6CC990B050541050006020307332E302E302E39370003074F746865724272616E6400000AE4ED8009000BA00B050541050006020307322E302E302E39370003074F746865724272616E6400000AE4ED8009000BA00B050541030006020307332E302E302E393900000AE4ED8009050541030006020307322E302E302E393900000AE4ED8009050541030006020307332E302E302E3938000009B3E6CC990B050541030006020307322E302E302E3938000009B3E6CC990B050541040006020307332E302E302E393700000AE4ED8009000BA00B050541040006020307322E302E302E393700000AE4ED8009000BA00B0500410303033130303031000301302E302E302E313000050541020006020307302E302E302E3900</_4>
<_5>00001006739CA527EF827847E16F23CD52458C3EBA3460A42935EC6948BEFA626B49E3BDF279FC62486E2DDBCA19609ED23D31F4E5175920F282AD74A74A997C3909E67B622480C68A058E886C7D5F3C40954880D7798CD61CEA0FBAFB389BE5B2B8A887348F7AADB4DF642B194B814047CDA0E698EDDE61DFA731DCA5883A76F913D8C94066718054E85ADA7AE009F2B2A9AF762FDCB9B6CAF64C156911E3AB172CFD795F66FB6E8E15048A54E4AB17979D6C447DEBADE75CC6F606050D980061112AFF9AE7C7BF8065D711949E41FA4C8B6CBF0916BB395B3E186A7D617D353C6BFFC687FE79475DFA095D113D70B828FB597BC3665B7C9C3669CA9CBE5D308D3FC23803044E45544745415200050541020006040307302E392E302E2A000500410503033130303033000301312E302E302E3137000304534D4300050541020006040307302E392E302E313200050541020006020307302E392E302E3230000500410503033130303033000301312E312E302E313000030442454C4B494E00050541020006040307302E392E302E313200050541020006020307302E392E302E3230000500410503033130303033000301312E302E302E3137000304454447452D434F524500050541020006040307302E392E302E313200050541020006020307302E392E302E3230000500410503033130303033000301312E302E302E31330003044C4F474954454300050541020006040307302E392E302E313200050541020006020307302E392E302E3230000500410503033130303035000301312E342E38382E31333636000304544F50434F4D00050541020006040307312E342E38382E3133353600050541020006020307312E342E38382E31333635000500410503033130303035000301312E342E38382E313336360003045043484F4D4500050541020006040307312E342E38382E3133353600050541020006020307312E342E38382E31333635000500410403033130303036000301302E302E302E313000050541020006040307302E302E302E3500050541020006020307302E302E302E39000500410503033130303037000301312E302E312E330003045445434F00050541020006040307312E302E302E3800050541020006020307312E302E312E31000500410503033130303038000301302E392E332E3339370003044C494E4B53595300050541020006040307302E382E332E2A00050541020006020307302E392E332E333932000500410503033130303038000301302E392E332E3339370003044E45544745415200050541020006040307302E382E332E2A00050541020006020307302E392E332E333932000500410503033130303038000301302E392E332E3339370003045048494C49505300050541020006040307302E382E332E2A00050541020006020307302E392E332E333932000500410403033130303130000301302E392E302E31310003044C494E4B53595300050541020006040307302E392E302E3130000500410403033130303130000301302E392E302E313100030442554646414C4F00050541020006040307302E392E302E3130000500410503033130303132000301312E302E302E310003044353544E00050541020006040307302E302E302E3500050541020006020307302E302E302E39000500410503033130303133000301302E302E332E3234000304414B00050541020006040307302E302E312E323400050541020006020307302E302E322E3234000500410303033130303134000301312E372E34332E33382E3200050541020006040307312E372E32332E32372E34000500410503033130303135000301312E322E31372E30000304415A5445434800050541020006040307312E322E31312E3000050541020006020307312E322E31352E30000500410303033130303230000301312E302E302E343700050541030006020308312E302E302E3233000307312E302E302E3233000500410403033130303234000301332E322E302E323800050541030006040308332E302E302E35000307332E302E302E3500050541030006020308332E312E302E31000307332E322E302E38000500410503033130303232000301302E302E302E3900030450414E41534F4E494300050541020006040307302E302E302E3100050541020006020307302E302E302E38000500410503033130303232000301302E302E302E3900030450414E41534F4E4943434F4E53554D455200050541020006040307302E302E302E3100050541020006020307302E302E302E3800</_5>
</BCM>
<BackboneInited>1</BackboneInited>
<Chat>
<FriendlyNameMaxSize>400</FriendlyNameMaxSize>
</Chat>
<Connection>
<Bandwidth>
<CurSlotLength>8118</CurSlotLength>
<InHistory>39,64,8184</InHistory>
<OutHistory>37,50,13164</OutHistory>
</Bandwidth>
<DisablePort80>1</DisablePort80>
<EventServers>
<DirectlyConnected>1</DirectlyConnected>
</EventServers>
<Firewall>
<TcpInHistory>-1431699456</TcpInHistory>
<UdpInHistory>-1431699456</UdpInHistory>
<UdpOutHistory>1610612735</UdpOutHistory>
</Firewall>
<HostCache>41C801050041050200D9AF0D45D9E900010400028788BCED0400038788BCED04000400050041050200BB0AB3FDD1A40001040002B7DCBCED040003B7DCBCED040004000500410502005C3766C2DA6B00010400029FB2BCED0400039FB2BCED04000400050041050200D9F8DC20CA33000104000296DAAAED04000396DAAAED0400040005004105020063847B3765900001040002D794BDED040003D794BDED040004000500410502004E80142FD3C70001040002CF86BDED040003CF86BDED04000400050041050200C3B213EA24A50001040002BF89BBED040003BF89BBED040004000500410502006FFEF1BA804C0001040002CF86BDED040003CF86BDED0400040005004105020052ED923CB3A700010400028788BCED0400038788BCED040004000500410502005243330D305B000104000283FFB2ED04000383FFB2ED040004000500410502006FF9438E9E5D0001040002CF86BDED040003CF86BDED04000400050041050200585515F19D77000104000283FFB2ED04000383FFB2ED04000400050041050200729EE3A8DD460001040002CF86BDED040003CF86BDED040004000500410502004572795D3BB300010400029FB2BCED0400039FB2BCED040004000500410502009F94D72CABA40001040002CF86BDED040003CF86BDED0400040005004105020095052D9C81090001040002B7DCBCED040003B7DCBCED040004000500410502005859A15FD7FC0001040002DC8FB5ED040003DC8FB5ED0400040005004105020059D7AB3EBBFB0001020002F8FABCED040003CF86BDED04000400050041050200BB2481B9390E0001040002CF86BDED040003CF86BDED0400040005004105020059D7F395A7BA0001040002B7DCBCED040003B7DCBCED040004000500410502006DC4BEF5D52E0001040002B0DFBAED040003B0DFBAED040004000500410502004B6E709CF4290001040002B7DCBCED040003B7DCBCED040004000500410502007A7D5CEC2B8D0001040002CF86BDED040003CF86BDED040004000500410502006FFFA8AFB19D0001040002B7DCBCED040003B7DCBCED040004000500410502003E4475A07A6F0001040002B7DCBCED040003B7DCBCED040004000500410502003EDD8384A4F90001040002BF89BBED040003BF89BBED04000400050041050200560FBFA4E4900001040002B7DCBCED040003B7DCBCED04000400050041050200C24FAEEE43F10001040002B3CEB5ED040003B3CEB5ED040004000500410502004F378778C6F30001040002CF86BDED040003CF86BDED04000400050041050200C94418BB0EDF0001040002B7DCBCED040003B7DCBCED040004000500410502003B75A58BECB30001040002CF86BDED040003CF86BDED04000400050041050200772A7A0908890001040002CF86BDED040003CF86BDED0400040005004105020048BB63586DE100010400029088BCED0400039088BCED040004000500410502005544F881BEDA000104000283FFB2ED04000383FFB2ED040004000500410502005B4C1468EDF80001040002B7DCBCED040003B7DCBCED04000400050041050200538BAF3F934F0001040002B3CEB5ED040003B3CEB5ED0400040005004105020055D6F93A4FD70001040002D7B3BBED040003D7B3BBED04000400050041050200D5D64561E55F00010400028788BCED0400038788BCED0400040005004105020046ADF229B8570001040002CF86BDED040003CF86BDED04000400050041050200D5151C19FFD600010200029FB2BCED040003B7DCBCED04000400050041050200973CA35DB82400010400029FB2BCED0400039FB2BCED04000400050041050200C249E5B953700001040002CF86BDED040003CF86BDED04000400050041050200722C69D8C4F500010400029FB2BCED0400039FB2BCED0400040005004105020058CBB311F2400001040002DC8FB5ED040003DC8FB5ED040004000500410502004BB7A090766E0001040002CF86BDED040003CF86BDED040004000500410502007DEF80FBEBD90001040002EFDDBBED040003EFDDBBED0400040005004105020076A03698F87A0001040002CF86BDED040003CF86BDED0400040005004105020050E5DFDD0C700001040002CF86BDED040003CF86BDED040004000500410502004D4C85E0CEC80001040002CF86BDED040003CF86BDED040004000500410502006FEA6BCD92A10001020002F8FABCED040003CF86BDED0400040005004105020043BAA930F28600010400029FB2BCED0400039FB2BCED04000400050041050200722DB82DDB780001040002CF86BDED040003CF86BDED0400040005004105020052E995118B9F0001040002CF86BDED040003CF86BDED040004000500410502005403013B36D20001040002EFDDBBED040003EFDDBBED04000400050041050200B27C0C920B260001040002B7DCBCED040003B7DCBCED04000400050041050200D9AF0997A7450001040002BCD9AAED040003BCD9AAED04000400050041050200BC00130BB5F60001040002CF86BDED040003CF86BDED04000400050041050200591FF23B53830001040002CF86BDED040003CF86BDED04000400050041050200557EB01367590001040002CF86BDED040003CF86BDED04000400050041050200505F157093A2000102000297A4BCED04000397A4BCED040004000500410502003A036C495C670001040002CF86BDED040003CF86BDED0400040005004105020050D8CF0B7D480001040002B7DCBCED040003B7DCBCED040004000500410502004E34E4D0FF250001040002B7DCBCED040003B7DCBCED040004000500410502007A1E50A46E770001040002CF86BDED040003CF86BDED040004000500410502005F18C666CBB80001040002EFDDBBED040003EFDDBBED04000400050041050200C19335603A9E0001040002DC8FB5ED040003DC8FB5ED0400040005004105020097142BD7DF890001040002AFDFBAED040003AFDFBAED0400040005004105020052F3355FFED400010400029FB2BCED0400039FB2BCED04000400050041050200BCBA857EECDF0001040002D7B3BBED040003D7B3BBED04000400050041050200729259D605EF0001040002CF86BDED040003CF86BDED04000400050041050200BEC2F57655B300010400029FB2BCED0400039FB2BCED040004000500410502005BD905C8304B0001020002A8EEBBED0400038788BCED0400040005004105020055F2C0360F360001040002EFDDBBED040003EFDDBBED0400040005004105020082C01DB9605D00010400028788BCED0400038788BCED04000400050041050200BC73B8FB30360001040002CF86BDED040003CF86BDED0400040005004105020050390E32DF8B0001040002B0DFBAED040003B0DFBAED040004000500410502005BCE8A2D7B8000010400028788BCED0400038788BCED0400040005004105020042292BB45D2D0001040002CF86BDED040003Line truncated
<HttpsProxy>
<Enable>0</Enable>
</HttpsProxy>
<LastIP>-645574544</LastIP>
<LastProbingFailed>0</LastProbingFailed>
<ListeningPort>47500</ListeningPort>
<LoginServers>
<DirectlyConnected>1</DirectlyConnected>
</LoginServers>
<NatTracker>
<ContraProbeResults>217.133.80.112:1076 217.133.80.112:47500 217.133.80.112:1083 217.133.80.112:1083 217.133.80.112:49734</ContraProbeResults>
<PreviousNatType>7</PreviousNatType>
<ProbeResults>
<_1303289856>6C81442204F3D9855070B98CAE5879A505F3D9855070B98C4D4320134B66D9855070B98C5F4E60ED0D34D98550700434</_1303289856>
<_1303293952>4287274ED659D9855070B98C4287274ED74BD9855070B98C4287274EC15CD9855070B98C4287274ECE92D9855070B98C4287274EA75BD9855070B98C4287274E4B98D9855070B98C4287274EAA2DD9855070B98C4287274EA175D9855070B98C4287274ED735D9855070B98C4287274EAE25D9855070B98C4287274E1A2BD9855070B98C3D7D44372576D9855070B98CCF86DF304366D9855070B98C3D2E02A2259CD9855070B98C4287274EB98CD9855070B98C</_1303293952>
<_1303298048>2E3363049108D9855070B98C2E3795FA3202D9855070B98C2E2F6F42E86DD9855070B98CB4B0620AA528D9855070B98C</_1303298048>
<_1303306240>5F1894D8122BD9855070B98C2E40484969A3D9855070B98CD592A70A5566D9855070B98C2E26119F8DBED9855070B98C2E3754264E48D9855070B98C</_1303306240>
<_1303314432>4D2BFFCAEC6CD9855070043B54BAD08D05E0D9855070B98C9D9D4DA11995D9855070B98C59584CCBB5CED9855070B98C972AC71733DDD9855070B98C</_1303314432>
<_1303322624>5F3B0DCEB535D9855070043BD5150C1746D3D9855070B98C4D4B8646EF29D9855070B98CD5152F4D12BBD9855070B98C</_1303322624>
<_1303326720>59D0D11D89DCD9855070C2462E755D8E1E97D9855070B98C2E492F875789D9855070B98C2E378784E9C6D9855070B98C2E2F6F6B48FCD9855070B98C</_1303326720>
</ProbeResults>
<UsedIPList>
<_1303289856>9A4A56D31C619325C6601C71B23E13FDFAF5CA49F15C34A4E33F239B524D6BBC226021F010D2270A3B48DFA2E8CDB6FD37531B1118DB2D471CB980D0</_1303289856>
<_1303293952>D5A2186D0B45088ADDFA7B626C0904CED47E3DF13172672AED483E1EAD69DB781ABEC0D8812B1B5EFF91BC28C67FB5A3404D875A</_1303293952>
<_1303298048>DB0EC5161D10171C7C6A4C7109DD</_1303298048>
<_1303302144>5379BD98</_1303302144>
<_1303306240>88B19442A48D863ED54D712EEC36D53127BCE36653FE</_1303306240>
<_1303310336>1908404B0F7BA3BE952CB1C533456D3CDA410BCB774AF93880FB8BD8C110</_1303310336>
<_1303314432>4B015AD444DD027FD3F61B2A51A53BA0</_1303314432>
<_1303322624>878BAF81A9F053B39E35081485E24B4EDA5F79D37E176C409B6E237A336451F42CFA7CEC013C98A18B51</_1303322624>
<_1303326720>CFB137906F6CCE77246BD5B6B434875570B1F9B9140C85D5114EE6953110B04F3557C0D1686D46A9F69106521979AE49E19F8622F93A</_1303326720>
<_1303330816>BA4B81F735FDCDA4E4EF57ACF8A37051C66401E41CA4E562A5A49ACC2E246CCE</_1303330816>
</UsedIPList>
</NatTracker>
<PresenceServers>
<DirectlyConnected>1</DirectlyConnected>
</PresenceServers>
<SipServers>
<DirectlyConnected>1</DirectlyConnected>
</SipServers>
<SocksProxy>
<Enable>0</Enable>
</SocksProxy>
<StatsServers>
<DirectlyConnected>1</DirectlyConnected>
</StatsServers>
</Connection>
<Localnode>
<NodeID>9BF92EA4B417A7F6</NodeID>
</Localnode>
<PropsManager>
<PermaProps>4102030E322F322E302E302E37322F31373400000FF6EB9ADC04</PermaProps>
</PropsManager>
<VoiceEng>
<AGC>0</AGC>
</VoiceEng>
</Lib>
<UI>
<Installed>2</Installed>
<Language>en</Language>
<Pos>
<Height>357</Height>
<Width>258</Width>
<X>0</X>
<Y>0</Y>
</Pos>
<SavePassword>0</SavePassword>
</UI>
</config>
@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<config version="1.0" serial="3315" timestamp="1303209780.1">
<Lib>
<Account>
<IdleTimeForAway>300</IdleTimeForAway>
<IdleTimeForNA>1800</IdleTimeForNA>
<Migration>63</Migration>
</Account>
<Call>
<DPC>41010300676D6172757A7A3400</DPC>
<FirstSkypeoutTime>1268962216</FirstSkypeoutTime>
</Call>
<CentralStorage>
<LastBackoff>0</LastBackoff>
<LastFailure>0</LastFailure>
<LastSync>1303202372</LastSync>
<NeedSync>0</NeedSync>
<SyncSet>
<p>
<email>35716ecf:2</email>
<profile>98e6c103:0</profile>
</p>
<u>&#10; </u>
</SyncSet>
</CentralStorage>
<Chat>
<ActivityTS>1</ActivityTS>
<DialogPartner>3</DialogPartner>
<HistoryDays>65535</HistoryDays>
<MigrationDone>1266110339</MigrationDone>
</Chat>
<Contacts>
<Migration>1</Migration>
</Contacts>
<Message>
<DisableHistory>1</DisableHistory>
</Message>
<Notification>
<LastID>1000000166</LastID>
<LastPoll>1303166852</LastPoll>
<LastSearch>1303209779</LastSearch>
</Notification>
<PM>
<pslut>1267114269</pslut>
</PM>
<ProfilePopulated>2</ProfilePopulated>
<PropsManager>
<PermaProps>4109008620EBA4DDDB0400FA0100009E2001009420FB09008520B1A58BDD04008120CCD9E6E3040093209B0A00F501820200F801A3B608</PermaProps>
</PropsManager>
<StatsSender>
<CollectorLastSent>1267114267</CollectorLastSent>
<CollectorSeq>11</CollectorSeq>
<Saved>4263C0064DD5ACF9A03594DAB928D2B81510</Saved>
</StatsSender>
<Video>
<AdvertPolicy>noone</AdvertPolicy>
<Disable>1</Disable>
<RecvPolicy>noone</RecvPolicy>
</Video>
<table_insert_history>
<_59908281a5de1c9c602d40fe1f815199a1601558ebea75accdfae8b723bb342e>1303296179 23160:21600:1303209779 9589:7200:1303209779 8707:21600:1303209779</_59908281a5de1c9c602d40fe1f815199a1601558ebea75accdfae8b723bb342e>
</table_insert_history>
</Lib>
<UI>
<API>
<Authorizations>skypopen</Authorizations>
<BlockedPrograms></BlockedPrograms>
</API>
<AutoUpdate>0</AutoUpdate>
<CaptureDevice>2</CaptureDevice>
<RingDevice>2</RingDevice>
<SoundDevice>2</SoundDevice>
</UI>
</config>
@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<config version="1.0" serial="3315" timestamp="1303209780.1">
<Lib>
<Account>
<IdleTimeForAway>300</IdleTimeForAway>
<IdleTimeForNA>1800</IdleTimeForNA>
<Migration>63</Migration>
</Account>
<Call>
<DPC>41010300676D6172757A7A3400</DPC>
<FirstSkypeoutTime>1268962216</FirstSkypeoutTime>
</Call>
<CentralStorage>
<LastBackoff>0</LastBackoff>
<LastFailure>0</LastFailure>
<LastSync>1303202372</LastSync>
<NeedSync>0</NeedSync>
<SyncSet>
<p>
<email>35716ecf:2</email>
<profile>98e6c103:0</profile>
</p>
<u>&#10; </u>
</SyncSet>
</CentralStorage>
<Chat>
<ActivityTS>1</ActivityTS>
<DialogPartner>3</DialogPartner>
<HistoryDays>65535</HistoryDays>
<MigrationDone>1266110339</MigrationDone>
</Chat>
<Contacts>
<Migration>1</Migration>
</Contacts>
<Message>
<DisableHistory>1</DisableHistory>
</Message>
<Notification>
<LastID>1000000166</LastID>
<LastPoll>1303166852</LastPoll>
<LastSearch>1303209779</LastSearch>
</Notification>
<PM>
<pslut>1267114269</pslut>
</PM>
<ProfilePopulated>2</ProfilePopulated>
<PropsManager>
<PermaProps>4109008620EBA4DDDB0400FA0100009E2001009420FB09008520B1A58BDD04008120CCD9E6E3040093209B0A00F501820200F801A3B608</PermaProps>
</PropsManager>
<StatsSender>
<CollectorLastSent>1267114267</CollectorLastSent>
<CollectorSeq>11</CollectorSeq>
<Saved>4263C0064DD5ACF9A03594DAB928D2B81510</Saved>
</StatsSender>
<Video>
<AdvertPolicy>noone</AdvertPolicy>
<Disable>1</Disable>
<RecvPolicy>noone</RecvPolicy>
</Video>
<table_insert_history>
<_59908281a5de1c9c602d40fe1f815199a1601558ebea75accdfae8b723bb342e>1303296179 23160:21600:1303209779 9589:7200:1303209779 8707:21600:1303209779</_59908281a5de1c9c602d40fe1f815199a1601558ebea75accdfae8b723bb342e>
</table_insert_history>
</Lib>
<UI>
<API>
<Authorizations>skypopen</Authorizations>
<BlockedPrograms></BlockedPrograms>
</API>
<AutoUpdate>0</AutoUpdate>
<CaptureDevice>2</CaptureDevice>
<RingDevice>2</RingDevice>
<SoundDevice>2</SoundDevice>
</UI>
</config>
Loaded 100 of 296 files, more files were not shown because too many files have changed in this diff. Show more