Merge branch 'master' of fs-git:freeswitch

This commit is contained in:
Raymond Chandler 2011-08-18 13:17:47 -04:00
commit 2b74046f41
35 changed files with 651 additions and 2340 deletions

View File

@ -8,4 +8,58 @@
</match>
</input>
</macro>
<macro name="enter_dest_number">
<input pattern="^(.*)$">
<match>
<action function="sleep" data="1000"/>
<action function="play-file" data="ivr/ivr-enter_destination_telephone_number.wav"/>
<action function="sleep" data="1000"/>
</match>
</input>
</macro>
<macro name="enter_src_number">
<input pattern="^(.*)$">
<match>
<action function="sleep" data="1000"/>
<action function="play-file" data="ivr/ivr-enter_source_telephone_number.wav"/>
<action function="sleep" data="1000"/>
</match>
</input>
</macro>
<macro name="call_forward_set">
<input pattern="^(\d+):(\d+)$">
<match>
<action function="sleep" data="1000"/>
<action function="play-file" data="ivr/ivr-extension_number.wav"/>
<action function="sleep" data="400"/>
<action function="say" data="$1" method="iterated" type="number"/>
<action function="sleep" data="400"/>
<action function="play-file" data="digits/2.wav"/>
<action function="sleep" data="1000"/>
<action function="play-file" data="ivr/ivr-extension_number.wav"/>
<action function="sleep" data="400"/>
<action function="say" data="$2" method="iterated" type="number"/>
<action function="sleep" data="1000"/>
<action function="play-file" data="ivr/ivr-call_forwarding_has_been_set.wav"/>
<action function="sleep" data="1500"/>
</match>
</input>
</macro>
<macro name="call_forward_cancel">
<input pattern="^(\d+)$">
<match>
<action function="sleep" data="1000"/>
<action function="play-file" data="ivr/ivr-extension_number.wav"/>
<action function="sleep" data="400"/>
<action function="say" data="$1" method="iterated" type="number"/>
<action function="play-file" data="ivr/ivr-call_forwarding_has_been_cancelled.wav"/>
<action function="sleep" data="1500"/>
</match>
</input>
</macro>
</include>

View File

@ -1,4 +1,4 @@
#! /bin/sh
srcpath=$(dirname $0 2>/dev/null ) || srcpath="."
$srcpath/configure "$@" --with-pic --with-glib=no --disable-shared --without-doxygen
$srcpath/configure "$@" --with-pic --with-glib=no --disable-shared --without-doxygen --disable-stun

View File

@ -625,7 +625,7 @@ SWITCH_DECLARE(void) switch_channel_mark_hold(switch_channel_t *channel, switch_
/** @} */
SWITCH_DECLARE(switch_status_t) switch_channel_execute_on(switch_channel_t *channel, const char *variable_prefix);
SWITCH_DECLARE(switch_status_t) switch_channel_api_on(switch_channel_t *channel, const char *variable_prefix);
SWITCH_END_EXTERN_C
#endif

View File

@ -131,12 +131,21 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_COPY_XML_CDR_VARIABLE "copy_xml_cdr"
#define SWITCH_CURRENT_APPLICATION_VARIABLE "current_application"
#define SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE "proto_specific_hangup_cause"
#define SWITCH_CHANNEL_EXECUTE_ON_ANSWER_VARIABLE "execute_on_answer"
#define SWITCH_CHANNEL_EXECUTE_ON_PRE_ANSWER_VARIABLE "execute_on_pre_answer"
#define SWITCH_CHANNEL_EXECUTE_ON_MEDIA_VARIABLE "execute_on_media"
#define SWITCH_CHANNEL_API_ON_ANSWER_VARIABLE "api_on_answer"
#define SWITCH_CHANNEL_EXECUTE_ON_RING_VARIABLE "execute_on_ring"
#define SWITCH_CHANNEL_EXECUTE_ON_TONE_DETECT_VARIABLE "execute_on_tone_detect"
#define SWITCH_CHANNEL_EXECUTE_ON_ORIGINATE_VARIABLE "execute_on_originate"
#define SWITCH_CHANNEL_API_ON_ANSWER_VARIABLE "api_on_answer"
#define SWITCH_CHANNEL_API_ON_PRE_ANSWER_VARIABLE "api_on_pre_answer"
#define SWITCH_CHANNEL_API_ON_MEDIA_VARIABLE "api_on_media"
#define SWITCH_CHANNEL_API_ON_RING_VARIABLE "api_on_ring"
#define SWITCH_CHANNEL_API_ON_TONE_DETECT_VARIABLE "api_on_tone_detect"
#define SWITCH_CHANNEL_API_ON_ORIGINATE_VARIABLE "api_on_originate"
#define SWITCH_CALL_TIMEOUT_VARIABLE "call_timeout"
#define SWITCH_HOLDING_UUID_VARIABLE "holding_uuid"
#define SWITCH_SOFT_HOLDING_UUID_VARIABLE "soft_holding_uuid"

View File

@ -850,7 +850,7 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
switch_event_t *event;
char res[256];
/* Check to see if agent already exist */
/* Check to see if agent already exists */
sql = switch_mprintf("SELECT count(*) FROM agents WHERE name = '%q'", agent);
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
@ -860,8 +860,8 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
goto done;
}
if (!strcasecmp(key, "status") ) {
/* Check to see if agent already exist */
if (!strcasecmp(key, "status") || !strcasecmp(key, "state") || !strcasecmp(key, "uuid") ) {
/* Check to see if agent already exists */
sql = switch_mprintf("SELECT %q FROM agents WHERE name = '%q'", key, agent);
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
@ -869,9 +869,15 @@ cc_status_t cc_agent_get(const char *key, const char *agent, char *ret_result, s
result = CC_STATUS_SUCCESS;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
char tmpname[256];
if (!strcasecmp(key, "uuid")) {
switch_snprintf(tmpname, sizeof(tmpname), "CC-Agent-UUID");
} else {
switch_snprintf(tmpname, sizeof(tmpname), "CC-Agent-%c%s", (char) switch_toupper(key[0]), key+1);
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-get");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", res);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-%s-get", key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, tmpname, res);
switch_event_fire(&event);
}
@ -1400,6 +1406,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* Proceed contact the agent to offer the member */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
switch_caller_profile_t *member_profile = switch_channel_get_caller_profile(member_channel);
const char *member_dnis = member_profile->rdnis;
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-offering");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
@ -1409,6 +1419,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Number", h->member_cid_number);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-DNIS", member_dnis);
switch_event_fire(&event);
}
@ -1548,6 +1559,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
t_agent_answered = local_epoch_time_now(NULL);
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_caller_profile_t *member_profile = switch_channel_get_caller_profile(member_channel);
const char *member_dnis = member_profile->rdnis;
switch_channel_event_set_data(agent_channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-start");
@ -1561,6 +1575,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-Session-UUID", h->member_session_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Name", h->member_cid_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-CID-Number", h->member_cid_number);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Member-DNIS", member_dnis);
switch_event_fire(&event);
}
/* for xml_cdr needs */
@ -2676,7 +2691,9 @@ static int list_result_callback(void *pArg, int argc, char **argv, char **column
"\tcallcenter_config agent set busy_delay_time [agent_name] [wait second] | \n"\
"\tcallcenter_config agent set no_answer_delay_time [agent_name] [wait second] | \n"\
"\tcallcenter_config agent get status [agent_name] | \n" \
"\tcallcenter_config agent list | \n" \
"\tcallcenter_config agent get state [agent_name] | \n" \
"\tcallcenter_config agent get uuid [agent_name] | \n" \
"\tcallcenter_config agent list [[agent_name]] | \n" \
"\tcallcenter_config tier add [queue_name] [agent_name] [level] [position] | \n" \
"\tcallcenter_config tier set state [queue_name] [agent_name] [state] | \n" \
"\tcallcenter_config tier set level [queue_name] [agent_name] [level] | \n" \
@ -2832,7 +2849,14 @@ SWITCH_STANDARD_API(cc_config_api_function)
struct list_result cbt;
cbt.row_process = 0;
cbt.stream = stream;
sql = switch_mprintf("SELECT * FROM agents");
if ( argc-initial_argc > 1 ) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
goto done;
} else if ( argc-initial_argc == 1 ) {
sql = switch_mprintf("SELECT * FROM agents WHERE name='%q'", argv[0 + initial_argc]);
} else {
sql = switch_mprintf("SELECT * FROM agents");
}
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");

View File

@ -3669,7 +3669,9 @@ static switch_status_t file_string_file_close(switch_file_handle_t *handle)
{
file_string_context_t *context = handle->private_info;
switch_core_file_close(&context->fh);
if (switch_test_flag((&context->fh), SWITCH_FILE_OPEN)) {
switch_core_file_close(&context->fh);
}
return SWITCH_STATUS_SUCCESS;
}

View File

@ -1,3 +0,0 @@
BASE=../../../..
LOCAL_OBJS=ivr.o util.o config.o menu.o
include $(BASE)/build/modmake.rules

View File

@ -1,135 +0,0 @@
/* Copy paste from FS mod_voicemail */
#include <switch.h>
#include "config.h"
const char *global_cf = "protovm.conf";
void populate_profile_menu_event(vmivr_profile_t *profile, vmivr_menu_profile_t *menu) {
switch_xml_t cfg, xml, x_profiles, x_profile, x_keys, x_phrases, x_menus, x_menu;
free_profile_menu_event(menu);
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
goto end;
}
if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
goto end;
}
if ((x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile->name))) {
if ((x_menus = switch_xml_child(x_profile, "menus"))) {
if ((x_menu = switch_xml_find_child(x_menus, "menu", "name", menu->name))) {
if ((x_keys = switch_xml_child(x_menu, "keys"))) {
switch_event_import_xml(switch_xml_child(x_keys, "key"), "dtmf", "action", &menu->event_keys_dtmf);
switch_event_import_xml(switch_xml_child(x_keys, "key"), "action", "dtmf", &menu->event_keys_action);
switch_event_import_xml(switch_xml_child(x_keys, "key"), "action", "variable", &menu->event_keys_varname);
}
if ((x_phrases = switch_xml_child(x_menu, "phrases"))) {
switch_event_import_xml(switch_xml_child(x_phrases, "phrase"), "name", "value", &menu->event_phrases);
}
}
}
}
end:
if (xml)
switch_xml_free(xml);
return;
}
void free_profile_menu_event(vmivr_menu_profile_t *menu) {
if (menu->event_keys_dtmf) {
switch_event_destroy(&menu->event_keys_dtmf);
}
if (menu->event_keys_action) {
switch_event_destroy(&menu->event_keys_action);
}
if (menu->event_keys_varname) {
switch_event_destroy(&menu->event_keys_varname);
}
if (menu->event_phrases) {
switch_event_destroy(&menu->event_phrases);
}
}
vmivr_profile_t *get_profile(switch_core_session_t *session, const char *profile_name)
{
vmivr_profile_t *profile = NULL;
switch_xml_t cfg, xml, x_profiles, x_profile, x_apis, param;
if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
return profile;
}
if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
goto end;
}
if ((x_profile = switch_xml_find_child(x_profiles, "profile", "name", profile_name))) {
if (!(profile = switch_core_session_alloc(session, sizeof(vmivr_profile_t)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n");
goto end;
}
profile->name = profile_name;
profile->current_msg = 0;
profile->current_msg_uuid = NULL;
/* TODO Make the following configurable */
profile->api_profile = profile->name;
profile->menu_check_auth = "std_authenticate";
profile->menu_check_main = "std_navigator";
profile->menu_check_terminate = "std_purge";
if ((x_apis = switch_xml_child(x_profile, "apis"))) {
int total_options = 0;
int total_invalid_options = 0;
for (param = switch_xml_child(x_apis, "api"); param; param = param->next) {
char *var, *val;
if ((var = (char *) switch_xml_attr_soft(param, "name")) && (val = (char *) switch_xml_attr_soft(param, "value"))) {
if (!strcasecmp(var, "msg_undelete") && !profile->api_msg_undelete)
profile->api_msg_undelete = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_delete") && !profile->api_msg_delete)
profile->api_msg_delete = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_list") && !profile->api_msg_list)
profile->api_msg_list = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_count") && !profile->api_msg_count)
profile->api_msg_count = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_save") && !profile->api_msg_save)
profile->api_msg_save = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_purge") && !profile->api_msg_purge)
profile->api_msg_purge = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_get") && !profile->api_msg_get)
profile->api_msg_get = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "msg_forward") && !profile->api_msg_forward)
profile->api_msg_forward = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "pref_greeting_set") && !profile->api_pref_greeting_set)
profile->api_pref_greeting_set = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "pref_recname_set") && !profile->api_pref_recname_set)
profile->api_pref_recname_set = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "pref_password_set") && !profile->api_pref_password_set)
profile->api_pref_password_set = switch_core_session_strdup(session, val);
else if (!strcasecmp(var, "auth_login") && !profile->api_auth_login)
profile->api_auth_login = switch_core_session_strdup(session, val);
else
total_invalid_options++;
total_options++;
}
}
if (total_options - total_invalid_options != 12) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing api definition for profile '%s'\n", profile_name);
profile = NULL;
}
}
}
end:
switch_xml_free(xml);
return profile;
}

View File

@ -1,53 +0,0 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
extern const char *global_cf;
struct vmivr_profile {
const char *name;
const char *domain;
const char *id;
int current_msg;
const char *current_msg_uuid;
const char *menu_check_auth;
const char *menu_check_main;
const char *menu_check_terminate;
switch_bool_t authorized;
const char *api_profile;
const char *api_auth_login;
const char *api_msg_delete;
const char *api_msg_undelete;
const char *api_msg_list;
const char *api_msg_count;
const char *api_msg_save;
const char *api_msg_purge;
const char *api_msg_get;
const char *api_msg_forward;
const char *api_pref_greeting_set;
const char *api_pref_recname_set;
const char *api_pref_password_set;
};
typedef struct vmivr_profile vmivr_profile_t;
struct vmivr_menu_profile {
const char *name;
switch_event_t *event_keys_action;
switch_event_t *event_keys_dtmf;
switch_event_t *event_keys_varname;
switch_event_t *event_phrases;
};
typedef struct vmivr_menu_profile vmivr_menu_profile_t;
vmivr_profile_t *get_profile(switch_core_session_t *session, const char *profile_name);
void free_profile_menu_event(vmivr_menu_profile_t *menu);
void populate_profile_menu_event(vmivr_profile_t *profile, vmivr_menu_profile_t *menu);
#endif /* _CONFIG_H_ */

View File

@ -1,250 +0,0 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Marc Olivier Chouinard <mochouinard@moctel.com>
*
*
* ivr.c -- MT IVR System Interface
*
*/
#include <switch.h>
#include "ivr.h"
int match_dtmf(switch_core_session_t *session, dtmf_ss_t *loc) {
switch_bool_t is_invalid[128] = { SWITCH_FALSE };
int i;
loc->potentialMatch = NULL;
loc->completeMatch = NULL;
loc->potentialMatchCount = 0;
for (i = 0; i < loc->dtmf_received; i++) {
int j;
loc->potentialMatchCount = 0;
for (j = 0; !zstr(loc->dtmf_accepted[j]) && j < 128; j++) {
switch_bool_t cMatch = SWITCH_FALSE;
char test[2] = { 0 };
if (is_invalid[j])
continue;
test[0] = loc->dtmf_stored[i];
if (loc->dtmf_accepted[j][i] == 'N' && atoi(test) >= 2 && atoi(test) <= 9)
cMatch = SWITCH_TRUE;
if (loc->dtmf_accepted[j][i] == 'X' && atoi(test) >= 0 && atoi(test) <= 9) {
cMatch = SWITCH_TRUE;
}
if (i >= strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.')
cMatch = SWITCH_TRUE;
if (loc->dtmf_accepted[j][i] == loc->dtmf_stored[i])
cMatch = SWITCH_TRUE;
if (cMatch == SWITCH_FALSE) {
is_invalid[j] = SWITCH_TRUE;
continue;
}
if (i == strlen(loc->dtmf_accepted[j]) - 1 && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] == '.') {
loc->completeMatch = loc->dtmf_accepted[j];
}
if (i == loc->dtmf_received - 1 && loc->dtmf_received == strlen(loc->dtmf_accepted[j]) && loc->dtmf_accepted[j][strlen(loc->dtmf_accepted[j])-1] != '.') {
loc->completeMatch = loc->dtmf_accepted[j];
continue;
}
loc->potentialMatchCount++;
}
}
return 1;
}
static switch_status_t cb_on_dtmf_ignore(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
{
switch (itype) {
case SWITCH_INPUT_TYPE_DTMF:
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
switch_channel_queue_dtmf(channel, dtmf);
return SWITCH_STATUS_BREAK;
}
default:
break;
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t cb_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
{
dtmf_ss_t *loc = (dtmf_ss_t*) buf;
switch (itype) {
case SWITCH_INPUT_TYPE_DTMF:
{
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
switch_bool_t audio_was_stopped = loc->audio_stopped;
loc->audio_stopped = SWITCH_TRUE;
if (loc->dtmf_received >= sizeof(loc->dtmf_stored)) {
loc->result = RES_BUFFER_OVERFLOW;
break;
}
if (!loc->terminate_key || dtmf->digit != loc->terminate_key)
loc->dtmf_stored[loc->dtmf_received++] = dtmf->digit;
match_dtmf(session, loc);
if (loc->terminate_key && dtmf->digit == loc->terminate_key && loc->result == RES_WAITFORMORE) {
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
loc->result = RES_FOUND;
} else {
loc->result = RES_INVALID;
}
return SWITCH_STATUS_BREAK;
} else {
if (loc->potentialMatchCount == 0 && loc->completeMatch != NULL) {
loc->result = RES_FOUND;
return SWITCH_STATUS_BREAK;
} else if (loc->potentialMatchCount > 0) {
loc->result = RES_WAITFORMORE;
if (!audio_was_stopped)
return SWITCH_STATUS_BREAK;
} else {
loc->result = RES_INVALID;
return SWITCH_STATUS_BREAK;
}
}
}
break;
default:
break;
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t captureMenuInitialize(dtmf_ss_t *loc, char **dtmf_accepted) {
int i;
memset(loc, 0, sizeof(*loc));
for (i = 0; dtmf_accepted[i] && i < 16; i++) {
strncpy(loc->dtmf_accepted[i], dtmf_accepted[i], 128);
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t playbackBufferDTMF(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_channel_ready(channel)) {
switch_input_args_t args = { 0 };
args.input_callback = cb_on_dtmf_ignore;
if (macro_name) {
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
}
} else {
status = SWITCH_STATUS_BREAK;
}
return status;
}
switch_status_t captureMenu(switch_core_session_t *session, dtmf_ss_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_channel_ready(channel)) {
switch_input_args_t args = { 0 };
args.input_callback = cb_on_dtmf;
args.buf = loc;
if (macro_name && loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
status = switch_ivr_phrase_macro_event(session, macro_name, data, event, lang, &args);
}
if (switch_channel_ready(channel) && (status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK) && timeout && loc->result == RES_WAITFORMORE) {
loc->audio_stopped = SWITCH_TRUE;
switch_ivr_collect_digits_callback(session, &args, timeout, 0);
if (loc->result == RES_WAITFORMORE) {
if (loc->potentialMatchCount == 1 && loc->completeMatch != NULL) {
loc->result = RES_FOUND;
} else {
loc->result = RES_TIMEOUT;
}
}
}
} else {
status = SWITCH_STATUS_BREAK;
}
return status;
}
switch_status_t captureMenuRecord(switch_core_session_t *session, dtmf_ss_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_channel_ready(channel)) {
switch_input_args_t args = { 0 };
args.input_callback = cb_on_dtmf;
args.buf = loc;
if (loc->audio_stopped == SWITCH_FALSE && loc->result == RES_WAITFORMORE) {
loc->recorded_audio = SWITCH_TRUE;
switch_ivr_gentones(session, "%(1000, 0, 640)", 0, NULL); /* TODO Make this optional and configurable */
status = switch_ivr_record_file(session, fh, file_path, &args, max_record_len);
}
if (loc->result == RES_WAITFORMORE) {
loc->result = RES_TIMEOUT;
}
} else {
status = SWITCH_STATUS_BREAK;
}
return status;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/

View File

@ -1,30 +0,0 @@
struct dtmf_ss {
char dtmf_stored[128];
int dtmf_received;
char dtmf_accepted[16][128];
int result;
switch_bool_t audio_stopped;
switch_bool_t recorded_audio;
const char *potentialMatch;
int potentialMatchCount;
const char *completeMatch;
char terminate_key;
};
typedef struct dtmf_ss dtmf_ss_t;
#define RES_WAITFORMORE 0
#define RES_FOUND 1
#define RES_INVALID 3
#define RES_TIMEOUT 4
#define RES_BREAK 5
#define RES_RECORD 6
#define RES_BUFFER_OVERFLOW 99
#define MAX_DTMF_SIZE_OPTION 32
switch_status_t captureMenu(switch_core_session_t *session, dtmf_ss_t *loc, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout);
switch_status_t captureMenuRecord(switch_core_session_t *session, dtmf_ss_t *loc, switch_event_t *event, const char *file_path, switch_file_handle_t *fh, int max_record_len);
switch_status_t captureMenuInitialize(dtmf_ss_t *loc, char **dtmf_accepted);
switch_status_t playbackBufferDTMF(switch_core_session_t *session, const char *macro_name, const char *data, switch_event_t *event, const char *lang, int timeout);

View File

@ -1,743 +0,0 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Marc Olivier Chouinard <mochouinard@moctel.com>
*
*
* menu.c -- VoiceMail Menu
*
*/
#include <switch.h>
#include "ivr.h"
#include "menu.h"
#include "util.h"
#include "config.h"
/* List of available menu */
vmivr_menu_function_t menu_list[] = {
{"std_authenticate", mtvm_menu_authenticate},
{"std_navigator", mtvm_menu_main},
{"std_record_name", mtvm_menu_record_name},
{"std_set_password", mtvm_menu_set_password},
{"std_select_greeting_slot", mtvm_menu_select_greeting_slot},
{"std_record_greeting_with_slot", mtvm_menu_record_greeting_with_slot},
{"std_preference", mtvm_menu_preference},
{"std_purge", mtvm_menu_purge},
{"std_forward", mtvm_menu_forward},
{ NULL, NULL }
};
#define MAX_ATTEMPT 3 /* TODO Make these fields configurable */
#define DEFAULT_IVR_TIMEOUT 3000
void mtvm_menu_purge(switch_core_session_t *session, vmivr_profile_t *profile) {
if (profile->id && profile->authorized) {
if (1==1 /* TODO make Purge email on exit optional ??? */) {
const char *cmd = switch_core_session_sprintf(session, "%s %s %s", profile->api_profile, profile->domain, profile->id);
mt_api_execute(session, profile->api_msg_purge, cmd);
}
}
}
void mtvm_menu_main(switch_core_session_t *session, vmivr_profile_t *profile) {
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_event_t *msg_list_params = NULL;
size_t msg_count = 0;
size_t current_msg = 1;
size_t next_msg = current_msg;
size_t previous_msg = current_msg;
char *cmd = NULL;
int retry;
/* Different switch to control playback of phrases */
switch_bool_t initial_count_played = SWITCH_FALSE;
switch_bool_t skip_header = SWITCH_FALSE;
switch_bool_t msg_deleted = SWITCH_FALSE;
switch_bool_t msg_undeleted = SWITCH_FALSE;
switch_bool_t msg_saved = SWITCH_FALSE;
vmivr_menu_profile_t menu = { "std_navigator" };
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
if (!menu.event_keys_dtmf || !menu.event_phrases) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases or Keys\n");
return;
}
/* Get VoiceMail List And update msg count */
cmd = switch_core_session_sprintf(session, "json %s %s %s", profile->api_profile, profile->domain, profile->id);
msg_list_params = jsonapi2event(session, NULL, profile->api_msg_list, cmd);
msg_count = atol(switch_event_get_header(msg_list_params,"VM-List-Count"));
/* TODO Add Detection of new message and notify the user */
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
switch_core_session_message_t msg = { 0 };
char cid_buf[1024] = "";
dtmf_ss_t loc;
char *dtmfa[16] = { 0 };
switch_event_t *phrase_params = NULL;
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
append_event_profile(phrase_params, profile, menu);
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
previous_msg = current_msg;
/* Simple Protection to not go out of msg list scope */
/* TODO: Add Prompt to notify they reached the begining or the end */
if (next_msg == 0) {
next_msg = 1;
} else if (next_msg > msg_count) {
next_msg = msg_count;
}
current_msg = next_msg;
captureMenuInitialize(&loc, dtmfa);
/* Prompt related to previous Message here */
append_event_message(session, profile, phrase_params, msg_list_params, previous_msg);
if (msg_deleted) {
msg_deleted = SWITCH_FALSE;
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "ack"), "deleted", phrase_params, NULL, 0);
}
if (msg_undeleted) {
msg_undeleted = SWITCH_FALSE;
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "ack"), "undeleted", phrase_params, NULL, 0);
}
if (msg_saved) {
msg_saved = SWITCH_FALSE;
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "ack"), "saved", phrase_params, NULL, 0);
}
/* Prompt related the current message */
append_event_message(session, profile, phrase_params, msg_list_params, current_msg);
/* Save in profile the current msg info for other menu processing AND restoration of our current position */
switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", switch_str_nil(switch_event_get_header(phrase_params, "VM-Message-Caller-Number")), switch_str_nil(switch_event_get_header(phrase_params, "VM-Message-Caller-Name")));
/* Display MSG CID/Name to caller */
msg.from = __FILE__;
msg.string_arg = cid_buf;
msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
switch_core_session_receive_message(session, &msg);
profile->current_msg = current_msg;
profile->current_msg_uuid = switch_core_session_strdup(session, switch_event_get_header(phrase_params, "VM-Message-UUID"));
/* TODO check if msg is gone (purged by another session, notify user and auto jump to next message or something) */
if (!skip_header) {
if (!initial_count_played) {
cmd = switch_core_session_sprintf(session, "json %s %s %s", profile->api_profile, profile->domain, profile->id);
jsonapi2event(session, phrase_params, profile->api_msg_count, cmd);
initial_count_played = SWITCH_TRUE;
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "msg_count"), NULL, phrase_params, NULL, 0);
}
if (msg_count > 0) {
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "say_msg_number"), NULL, phrase_params, NULL, 0);
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "say_date"), NULL, phrase_params, NULL, 0);
}
}
if (msg_count > 0) {
/* TODO Update the Read date of a message (When msg start, or when it listen compleatly ??? To be determined */
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "play_message"), NULL, phrase_params, NULL, 0);
}
skip_header = SWITCH_FALSE;
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
if (loc.result == RES_TIMEOUT) {
/* TODO Ask for the prompt Again IF retry != 0 */
} else if (loc.result == RES_INVALID) {
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
/* Reset the try count */
retry = MAX_ATTEMPT;
if (action) {
if (!strcasecmp(action, "skip_intro")) { /* Skip Header / Play the recording again */
skip_header = SWITCH_TRUE;
} else if (!strcasecmp(action, "next_msg")) { /* Next Message */
next_msg++;
} else if (!strcasecmp(action, "prev_msg")) { /* Previous Message */
next_msg--;
} else if (!strcasecmp(action, "delete_msg")) { /* Delete / Undelete Message */
const char *msg_flags = switch_event_get_header(phrase_params, "VM-Message-Flags");
if (!msg_flags || strncasecmp(msg_flags, "delete", 6)) {
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(phrase_params, "VM-Message-UUID"));
mt_api_execute(session, profile->api_msg_delete, cmd);
msg_deleted = SWITCH_TRUE;
/* TODO Option for auto going to next message or just return to the menu (So user used to do 76 to delete and next message wont be confused) */
next_msg++;
} else {
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(phrase_params, "VM-Message-UUID"));
mt_api_execute(session, profile->api_msg_undelete, cmd);
msg_undeleted = SWITCH_TRUE;
}
} else if (!strcasecmp(action, "save_msg")) { /* Save Message */
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(phrase_params, "VM-Message-UUID"));
mt_api_execute(session, profile->api_msg_save, cmd);
msg_saved = SWITCH_TRUE;
} else if (!strcasecmp(action, "callback")) { /* CallBack caller */
const char *cid_num = switch_event_get_header(phrase_params, "VM-Message-Caller-Number");
if (cid_num) {
/* TODO add detection for private number */
switch_core_session_execute_exten(session, cid_num, "XML", profile->domain);
} else {
/* TODO Some error msg that the msg doesn't contain a caller number */
}
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
if (fPtr) {
fPtr(session, profile);
}
} else if (!strcasecmp(action, "return")) { /* Return */
retry = -1;
}
}
}
/* IF the API to get the message returned us a COPY of the file locally (temp file create from a DB or from a web server), delete it */
if (switch_true(switch_event_get_header(phrase_params, "VM-Message-Private-Local-Copy"))) {
const char *file_path = switch_event_get_header(phrase_params, "VM-Message-File-Path");
if (file_path && unlink(file_path) != 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete temp file [%s]\n", file_path);
}
}
switch_event_destroy(&phrase_params);
}
switch_event_destroy(&msg_list_params);
free_profile_menu_event(&menu);
return;
}
void mtvm_menu_forward(switch_core_session_t *session, vmivr_profile_t *profile) {
vmivr_menu_profile_t menu = { "std_forward_ask_prepend" };
switch_channel_t *channel = switch_core_session_get_channel(session);
const char *prepend_filepath = NULL;
int retry;
switch_bool_t forward_msg = SWITCH_FALSE;
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
if (!menu.event_keys_dtmf || !menu.event_phrases) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys\n");
return;
}
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
dtmf_ss_t loc;
char *dtmfa[16] = { 0 };
switch_event_t *phrase_params = NULL;
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
append_event_profile(phrase_params, profile, menu);
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
captureMenuInitialize(&loc, dtmfa);
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
if (loc.result == RES_TIMEOUT) {
/* TODO Ask for the prompt Again IF retry != 0 */
} else if (loc.result == RES_INVALID) {
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
/* Reset the try count */
retry = MAX_ATTEMPT;
if (action) {
if (!strcasecmp(action, "return")) { /* Return to the previous menu */
retry = -1;
forward_msg = SWITCH_FALSE;
} else if (!strcasecmp(action, "prepend")) { /* Prepend record msg */
vmivr_menu_profile_t sub_menu = { "std_record_message" };
char *tmp_filepath = generate_random_file_name(session, "protovm", "wav" /* TODO make it configurable */);
switch_status_t status;
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &sub_menu);
status = mtvm_menu_record(session, profile, sub_menu, tmp_filepath);
if (status == SWITCH_STATUS_SUCCESS) {
//char *cmd = switch_core_session_sprintf(session, "%s %s %s %d %s", profile->api_profile, profile->domain, profile->id, gnum, tmp_filepath);
//char *str_num = switch_core_session_sprintf(session, "%d", gnum);
//mt_api_execute(session, profile->api_pref_greeting_set, cmd);
//playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
prepend_filepath = tmp_filepath;
retry = -1;
forward_msg = SWITCH_TRUE;
} else {
/* TODO Error Recording msg */
}
free_profile_menu_event(&sub_menu);
} else if (!strcasecmp(action, "forward")) { /* Forward without prepend msg */
retry = -1;
forward_msg = SWITCH_TRUE;
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
if (fPtr) {
fPtr(session, profile);
}
}
}
}
switch_event_destroy(&phrase_params);
}
/* Ask Extension to Forward */
if (forward_msg) {
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
const char *id = NULL;
vmivr_menu_profile_t sub_menu = { "std_forward_ask_extension" };
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &sub_menu);
id = mtvm_menu_get_input_set(session, profile, sub_menu, "X.");
if (id) {
const char *cmd = switch_core_session_sprintf(session, "%s %s %s %s %s %s %s%s%s", profile->api_profile, profile->domain, profile->id, profile->current_msg_uuid, profile->domain, id, prepend_filepath?" ":"", prepend_filepath?prepend_filepath:"" );
if (mt_api_execute(session, profile->api_msg_forward, cmd) == SWITCH_STATUS_SUCCESS) {
playbackBufferDTMF(session, switch_event_get_header(sub_menu.event_phrases, "ack"), "saved", NULL, NULL, 0);
retry = -1;
} else {
playbackBufferDTMF(session, switch_event_get_header(sub_menu.event_phrases, "invalid_extension"), NULL, NULL, NULL, 0);
}
} else {
/* TODO Prompt about input not valid */
}
free_profile_menu_event(&sub_menu);
/* TODO add Confirmation of the transfered number */
}
/* TODO Ask if we want to transfer the msg to more person */
}
free_profile_menu_event(&menu);
}
void mtvm_menu_record_name(switch_core_session_t *session, vmivr_profile_t *profile) {
switch_status_t status;
vmivr_menu_profile_t menu = { "std_record_name" };
char *tmp_filepath = generate_random_file_name(session, "protovm", "wav" /* TODO make it configurable */);
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
status = mtvm_menu_record(session, profile, menu, tmp_filepath);
if (status == SWITCH_STATUS_SUCCESS) {
char *cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, tmp_filepath);
mt_api_execute(session, profile->api_pref_recname_set, cmd);
}
}
void mtvm_menu_set_password(switch_core_session_t *session, vmivr_profile_t *profile) {
char *password;
vmivr_menu_profile_t menu = { "std_set_password" };
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
password = mtvm_menu_get_input_set(session, profile, menu, "XXX." /* TODO Conf Min 3 Digit */);
/* TODO Add Prompts to tell if password was set and if it was not */
if (password) {
char *cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, profile->id, password);
mt_api_execute(session, profile->api_pref_password_set, cmd);
}
free_profile_menu_event(&menu);
}
void mtvm_menu_authenticate(switch_core_session_t *session, vmivr_profile_t *profile) {
switch_channel_t *channel = switch_core_session_get_channel(session);
vmivr_menu_profile_t menu = { "std_authenticate" };
int retry;
const char *auth_var = NULL;
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
if (profile->id && (auth_var = switch_channel_get_variable(channel, "voicemail_authorized")) && switch_true(auth_var)) {
profile->authorized = SWITCH_TRUE;
}
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0 && profile->authorized == SWITCH_FALSE; retry--) {
const char *id = profile->id, *password = NULL;
char *cmd = NULL;
if (!id) {
vmivr_menu_profile_t sub_menu = { "std_authenticate_ask_user" };
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &sub_menu);
id = mtvm_menu_get_input_set(session, profile, sub_menu, "X." /* TODO Conf Min 3 Digit */);
free_profile_menu_event(&sub_menu);
}
if (!password) {
vmivr_menu_profile_t sub_menu = { "std_authenticate_ask_password" };
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &sub_menu);
password = mtvm_menu_get_input_set(session, profile, sub_menu, "X." /* TODO Conf Min 3 Digit */);
free_profile_menu_event(&sub_menu);
}
cmd = switch_core_session_sprintf(session, "%s %s %s %s", profile->api_profile, profile->domain, id, password);
if (mt_api_execute(session, profile->api_auth_login, cmd) == SWITCH_STATUS_SUCCESS) {
profile->id = id;
profile->authorized = SWITCH_TRUE;
} else {
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "fail_auth"), NULL, NULL, NULL, 0);
}
}
free_profile_menu_event(&menu);
}
void mtvm_menu_select_greeting_slot(switch_core_session_t *session, vmivr_profile_t *profile) {
vmivr_menu_profile_t menu = { "std_select_greeting_slot" };
const char *result;
int gnum = -1;
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
result = mtvm_menu_get_input_set(session, profile, menu, "X");
if (result)
gnum = atoi(result);
if (gnum != -1) {
char * cmd = switch_core_session_sprintf(session, "%s %s %s %d", profile->api_profile, profile->domain, profile->id, gnum);
if (mt_api_execute(session, profile->api_pref_greeting_set, cmd) == SWITCH_STATUS_SUCCESS) {
char *str_num = switch_core_session_sprintf(session, "%d", gnum);
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
} else {
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "invalid_slot"), NULL, NULL, NULL, 0);
}
}
free_profile_menu_event(&menu);
}
void mtvm_menu_record_greeting_with_slot(switch_core_session_t *session, vmivr_profile_t *profile) {
vmivr_menu_profile_t menu = { "std_record_greeting_with_slot" };
const char *result;
int gnum = -1;
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
result = mtvm_menu_get_input_set(session, profile, menu, "X");
if (result)
gnum = atoi(result);
/* If user entered 0, we don't accept it */
if (gnum > 0) {
vmivr_menu_profile_t sub_menu = { "std_record_greeting" };
char *tmp_filepath = generate_random_file_name(session, "protovm", "wav" /* TODO make it configurable */);
switch_status_t status;
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &sub_menu);
status = mtvm_menu_record(session, profile, sub_menu, tmp_filepath);
if (status == SWITCH_STATUS_SUCCESS) {
char *cmd = switch_core_session_sprintf(session, "%s %s %s %d %s", profile->api_profile, profile->domain, profile->id, gnum, tmp_filepath);
char *str_num = switch_core_session_sprintf(session, "%d", gnum);
mt_api_execute(session, profile->api_pref_greeting_set, cmd);
playbackBufferDTMF(session, switch_event_get_header(menu.event_phrases, "selected_slot"), str_num, NULL, NULL, 0);
}
free_profile_menu_event(&sub_menu);
}
free_profile_menu_event(&menu);
}
void mtvm_menu_preference(switch_core_session_t *session, vmivr_profile_t *profile) {
switch_channel_t *channel = switch_core_session_get_channel(session);
int retry;
vmivr_menu_profile_t menu = { "std_preference" };
/* Initialize Menu Configs */
populate_profile_menu_event(profile, &menu);
if (!menu.event_keys_dtmf || !menu.event_phrases) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys\n");
return;
}
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
dtmf_ss_t loc;
char *dtmfa[16] = { 0 };
switch_event_t *phrase_params = NULL;
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
append_event_profile(phrase_params, profile, menu);
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
captureMenuInitialize(&loc, dtmfa);
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
if (loc.result == RES_TIMEOUT) {
/* TODO Ask for the prompt Again IF retry != 0 */
} else if (loc.result == RES_INVALID) {
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
/* Reset the try count */
retry = MAX_ATTEMPT;
if (action) {
if (!strcasecmp(action, "return")) { /* Return to the previous menu */
retry = -1;
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
if (fPtr) {
fPtr(session, profile);
}
}
}
}
switch_event_destroy(&phrase_params);
}
free_profile_menu_event(&menu);
}
char *mtvm_menu_get_input_set(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *input_mask) {
char *result = NULL;
int retry;
const char *terminate_key = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (!menu.event_keys_dtmf || !menu.event_phrases) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys : %s\n", menu.name);
return result;
}
terminate_key = switch_event_get_header(menu.event_keys_action, "ivrengine:terminate_entry");
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
dtmf_ss_t loc;
char *dtmfa[16] = { 0 };
int i;
switch_event_t *phrase_params = NULL;
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
append_event_profile(phrase_params, profile, menu);
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
/* Find the last entry and append this one to it */
for (i=0; dtmfa[i] && i < 16; i++){
}
dtmfa[i] = (char *) input_mask;
captureMenuInitialize(&loc, dtmfa);
if (terminate_key) {
loc.terminate_key = terminate_key[0];
}
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "instructions"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
if (loc.result == RES_TIMEOUT) {
/* TODO Ask for the prompt Again IF retry != 0 */
} else if (loc.result == RES_INVALID) {
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
/* Reset the try count */
retry = MAX_ATTEMPT;
if (!strncasecmp(loc.completeMatch, input_mask, 1)) {
result = switch_core_session_strdup(session, loc.dtmf_stored);
retry = -1;
}
}
switch_event_destroy(&phrase_params);
}
return result;
}
switch_status_t mtvm_menu_record(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *file_name) {
switch_status_t status = SWITCH_STATUS_FALSE;
switch_channel_t *channel = switch_core_session_get_channel(session);
int retry;
switch_bool_t record_prompt = SWITCH_TRUE;
switch_bool_t listen_recording = SWITCH_FALSE;
switch_bool_t play_instruction = SWITCH_TRUE;
if (!menu.event_keys_dtmf || !menu.event_phrases) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Menu Phrases and Keys\n");
return status;
}
for (retry = MAX_ATTEMPT; switch_channel_ready(channel) && retry > 0; retry--) {
dtmf_ss_t loc;
char *dtmfa[16] = { 0 };
switch_event_t *phrase_params = NULL;
switch_file_handle_t fh = { 0 };
/* TODO Make the following configurable */
fh.thresh = 200;
fh.silence_hits = 4;
//fh.samplerate = 8000;
switch_event_create(&phrase_params, SWITCH_EVENT_REQUEST_PARAMS);
append_event_profile(phrase_params, profile, menu);
populate_dtmfa_from_event(phrase_params, profile, menu, dtmfa);
captureMenuInitialize(&loc, dtmfa);
if (record_prompt) {
if (play_instruction) {
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "instructions"), NULL, phrase_params, NULL, 0);
}
play_instruction = SWITCH_TRUE;
captureMenuRecord(session, &loc, phrase_params, file_name, &fh, 30 /* TODO Make max recording configurable */);
} else {
if (listen_recording) {
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Record-File-Path", "%s", file_name);
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "play_recording"), NULL, phrase_params, NULL, 0);
listen_recording = SWITCH_FALSE;
}
captureMenu(session, &loc, switch_event_get_header(menu.event_phrases, "menu_options"), NULL, phrase_params, NULL, DEFAULT_IVR_TIMEOUT);
}
if (loc.recorded_audio) {
/* Reset the try count */
retry = MAX_ATTEMPT;
/* TODO Check if message is too short */
record_prompt = SWITCH_FALSE;
} else if (loc.result == RES_TIMEOUT) {
/* TODO Ask for the prompt Again IF retry != 0 */
} else if (loc.result == RES_INVALID) {
/* TODO Say invalid option, and ask for the prompt again IF retry != 0 */
} else if (loc.result == RES_FOUND) { /* Matching DTMF Key Pressed */
const char *action = switch_event_get_header(menu.event_keys_dtmf, loc.dtmf_stored);
/* Reset the try count */
retry = MAX_ATTEMPT;
if (action) {
if (!strcasecmp(action, "listen")) { /* Listen */
listen_recording = SWITCH_TRUE;
} else if (!strcasecmp(action, "save")) {
retry = -1;
/* TODO ALLOW SAVE ONLY IF FILE IS RECORDED AND HIGHER THAN MIN SIZE */
status = SWITCH_STATUS_SUCCESS;
} else if (!strcasecmp(action, "rerecord")) {
record_prompt = SWITCH_TRUE;
} else if (!strcasecmp(action, "skip_instruction")) { /* Skip Recording Greeting */
play_instruction = SWITCH_FALSE;
} else if (!strncasecmp(action, "menu:", 5)) { /* Sub Menu */
void (*fPtr)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(action+5);
if (fPtr) {
fPtr(session, profile);
}
} else if (!strcasecmp(action, "return")) { /* Return */
retry = -1;
}
}
}
switch_event_destroy(&phrase_params);
}
return status;
}
void (*mtvm_get_menu_function(const char *menu_name))(switch_core_session_t *session, vmivr_profile_t *profile) {
int i = 0;
if (menu_name) {
for (i=0; menu_list[i].name ; i++) {
if (!strcasecmp(menu_list[i].name, menu_name)) {
return menu_list[i].pt2Func;
}
}
}
return NULL;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/

View File

@ -1,32 +0,0 @@
#ifndef _MENU_H_
#define _MENU_H_
#include "config.h"
void mtvm_menu_purge(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_authenticate(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_main(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_record_name(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_set_password(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_select_greeting_slot(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_record_greeting_with_slot(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_preference(switch_core_session_t *session, vmivr_profile_t *profile);
void mtvm_menu_forward(switch_core_session_t *session, vmivr_profile_t *profile);
switch_status_t mtvm_menu_record(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *file_name);
char *mtvm_menu_get_input_set(switch_core_session_t *session, vmivr_profile_t *profile, vmivr_menu_profile_t menu, const char *input_mask);
struct vmivr_menu_function {
const char *name;
void (*pt2Func)(switch_core_session_t *session, vmivr_profile_t *profile);
};
typedef struct vmivr_menu_function vmivr_menu_function_t;
extern vmivr_menu_function_t menu_list[];
void (*mtvm_get_menu_function(const char *menu_name))(switch_core_session_t *session, vmivr_profile_t *profile);
#endif /* _MENU_H_ */

View File

@ -1,139 +0,0 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Marc Olivier Chouinard <mochouinard@moctel.com>
*
*
* mod_protovm.c -- MT VoiceMail System
*
*/
#include <switch.h>
#include "config.h"
#include "menu.h"
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_protovm_shutdown);
SWITCH_MODULE_RUNTIME_FUNCTION(mod_protovm_runtime);
SWITCH_MODULE_LOAD_FUNCTION(mod_protovm_load);
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
*/
SWITCH_MODULE_DEFINITION(mod_protovm, mod_protovm_load, mod_protovm_shutdown, NULL);
#define MTVM_DESC "protovm"
#define MTVM_USAGE "<check> profile domain [id]"
SWITCH_STANDARD_APP(protovm_function)
{
const char *id = NULL;
const char *domain = NULL;
const char *profile_name = NULL;
vmivr_profile_t *profile = NULL;
int argc = 0;
char *argv[6] = { 0 };
char *mydata = NULL;
if (!zstr(data)) {
mydata = switch_core_session_strdup(session, data);
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (argv[1])
profile_name = argv[1];
if (argv[2])
domain = argv[2];
if (!strcasecmp(argv[0], "check")) {
if (argv[3])
id = argv[3];
if (domain && profile_name) {
profile = get_profile(session, profile_name);
if (profile) {
void (*fPtrAuth)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(profile->menu_check_auth);
void (*fPtrMain)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(profile->menu_check_main);
void (*fPtrTerminate)(switch_core_session_t *session, vmivr_profile_t *profile) = mtvm_get_menu_function(profile->menu_check_terminate);
profile->domain = domain;
profile->id = id;
if (fPtrAuth && !profile->authorized) {
fPtrAuth(session, profile);
}
if (fPtrMain && profile->authorized) {
fPtrMain(session, profile);
}
if (fPtrTerminate) {
fPtrTerminate(session, profile);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile '%s' not found\n", profile_name);
}
}
}
return;
}
/* Macro expands to: switch_status_t mod_protovm_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_protovm_load)
{
switch_application_interface_t *app_interface;
switch_status_t status = SWITCH_STATUS_SUCCESS;
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_APP(app_interface, "protovm", "protovm", MTVM_DESC, protovm_function, MTVM_USAGE, SAF_NONE);
/* indicate that the module should continue to be loaded */
return status;
}
/*
Called when the system shuts down
Macro expands to: switch_status_t mod_protovm_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_protovm_shutdown)
{
return SWITCH_STATUS_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/

View File

@ -1,176 +0,0 @@
<configuration name="protovm.conf" description="ProtoVoicemailIVR">
<profiles>
<profile name="default">
<apis>
<api name="auth_login" value="vm_fsdb_auth_login" />
<api name="msg_list" value="vm_fsdb_msg_list" />
<api name="msg_count" value="vm_fsdb_msg_count" />
<api name="msg_delete" value="vm_fsdb_msg_delete" />
<api name="msg_undelete" value="vm_fsdb_msg_undelete" />
<api name="msg_save" value="vm_fsdb_msg_save" />
<api name="msg_purge" value="vm_fsdb_msg_purge" />
<api name="msg_get" value="vm_fsdb_msg_get" />
<api name="msg_forward" value="vm_fsdb_msg_forward" />
<api name="pref_greeting_set" value="vm_fsdb_pref_greeting_set" />
<api name="pref_recname_set" value="vm_fsdb_pref_recname_set" />
<api name="pref_password_set" value="vm_fsdb_pref_password_set" />
</apis>
<menus>
<menu name="std_authenticate">
<phrases>
<phrase name="fail_auth" value="fail_auth@protovm" />
</phrases>
<keys>
</keys>
</menu>
<menu name="std_authenticate_ask_user">
<phrases>
<phrase name="instructions" value="enter_id@protovm" />
</phrases>
<keys>
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
</keys>
</menu>
<menu name="std_authenticate_ask_password">
<phrases>
<phrase name="instructions" value="enter_pass@protovm" />
</phrases>
<keys>
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
</keys>
</menu>
<menu name="std_navigator">
<phrases>
<phrase name="msg_count" value="message_count@protovm" />
<phrase name="say_date" value="say_date_event@protovm" />
<phrase name="say_msg_number" value="say_message_number@protovm" />
<phrase name="menu_options" value="listen_file_check@protovm" />
<phrase name="ack" value="ack@protovm" />
<phrase name="play_message" value="play_message@protovm" />
</phrases>
<keys>
<key dtmf="1" action="skip_intro" variable="VM-Key-Main-Listen-File" />
<key dtmf="6" action="next_msg" variable="VM-Key-Main-Next-Msg" />
<key dtmf="4" action="prev_msg" />
<key dtmf="7" action="delete_msg" variable="VM-Key-Main-Delete-File" /> <!-- Same key for undelete if it already deleted -->
<key dtmf="8" action="menu:std_forward" variable="VM-Key-Main-Forward" />
<key dtmf="3" action="save_msg" variable="VM-Key-Main-Save-File" />
<key dtmf="2" action="callback" variable="VM-Key-Main-Callback" />
<key dtmf="5" action="menu:std_preference" />
<key dtmf="#" action="return" /> <!-- TODO Might Conflict with future fast-forward -->
</keys>
</menu>
<menu name="std_preference">
<phrases>
<phrase name="menu_options" value="config_menu@protovm" />
</phrases>
<keys>
<key dtmf="1" action="menu:std_record_greeting_with_slot" variable="VM-Key-Record-Greeting" />
<key dtmf="2" action="menu:std_select_greeting_slot" variable="VM-Key-Choose-Greeting" />
<key dtmf="3" action="menu:std_record_name" variable="VM-Key-Record-Name" />
<key dtmf="6" action="menu:std_set_password" variable="VM-Key-Change-Password" />
<key dtmf="#" action="return" variable="VM-Key-Main-Menu" />
</keys>
</menu>
<menu name="std_record_greeting">
<phrases>
<phrase name="instructions" value="record_greeting@protovm" />
<phrase name="play_recording" value="play_recording@protovm" />
<phrase name="menu_options" value="record_file_check@protovm" />
</phrases>
<keys>
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
<key dtmf="3" action="save" variable="VM-Key-Save-File" />
<key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
<key dtmf="#" action="skip_instruction" />
</keys>
</menu>
<menu name="std_record_name">
<phrases>
<phrase name="instructions" value="record_name@protovm" />
<phrase name="play_recording" value="play_recording@protovm" />
<phrase name="menu_options" value="record_file_check@protovm" />
</phrases>
<keys>
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
<key dtmf="3" action="save" variable="VM-Key-Save-File" />
<key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
<key dtmf="#" action="skip_instruction" />
</keys>
</menu>
<menu name="std_record_message">
<phrases>
<phrase name="instructions" value="record_message@protovm" />
<phrase name="play_recording" value="play_recording@protovm" />
<phrase name="menu_options" value="record_file_check@protovm" />
</phrases>
<keys>
<key dtmf="1" action="listen" variable="VM-Key-Listen-File" />
<key dtmf="3" action="save" variable="VM-Key-Save-File" />
<key dtmf="4" action="rerecord" variable="VM-Key-ReRecord-File" />
<key dtmf="#" action="skip_instruction" />
</keys>
</menu>
<menu name="std_forward_ask_prepend">
<phrases>
<phrase name="menu_options" value="forward_ask_prepend@protovm" />
</phrases>
<keys>
<key dtmf="1" action="prepend" variable="VM-Key-Prepend" />
<key dtmf="8" action="forward" variable="VM-Key-Forward" />
<key dtmf="#" action="return" variable="VM-Key-Return" />
</keys>
</menu>
<menu name="std_forward_ask_extension">
<phrases>
<phrase name="instructions" value="forward_ask_extension@protovm" />
<phrase name="ack" value="ack@protovm" />
<phrase name="invalid_extension" value="invalid_extension@protovm" />
</phrases>
<keys>
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
</keys>
</menu>
<menu name="std_select_greeting_slot">
<phrases>
<phrase name="instructions" value="choose_greeting@protovm" />
<phrase name="invalid_slot" value="choose_greeting_fail@protovm" />
<phrase name="selected_slot" value="greeting_selected@protovm" />
</phrases>
<keys>
</keys>
</menu>
<menu name="std_record_greeting_with_slot">
<phrases>
<phrase name="instructions" value="choose_greeting@protovm" />
</phrases>
<keys>
</keys>
</menu>
<menu name="std_set_password">
<phrases>
<phrase name="instructions" value="enter_pass@protovm" />
</phrases>
<keys>
<key dtmf="#" action="ivrengine:terminate_entry" variable="VM-Key-Terminator" />
</keys>
</menu>
</menus>
</profile>
</profiles>
</configuration>

View File

@ -1,397 +0,0 @@
<include><!--This line will be ignored it's here to validate the xml and is optional -->
<macros name="protovm" sound-prefix="$${sounds_dir}/en/us/callie">
<macro name="press_key">
<input pattern="^(.*):(.*)$">
<match>
<action function="play-file" data="$2"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="plurial_msg">
<input pattern="^[01]:(.*):(.*)$" break_on_match="true">
<match>
<action function="play-file" data="$1"/>
</match>
</input>
<input pattern="^.*:(.*):(.*)$" break_on_match="true">
<match>
<action function="play-file" data="$2"/>
</match>
</input>
</macro>
<macro name="enter_id">
<input pattern="(.+)">
<match>
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
<nomatch>
<action function="play-file" data="voicemail/vm-enter_id.wav"/>
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
</nomatch>
</input>
</macro>
<macro name="enter_pass">
<input pattern="(.+)">
<match>
<action function="play-file" data="voicemail/vm-enter_pass.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
<nomatch>
<action function="play-file" data="voicemail/vm-enter_pass.wav"/>
<action function="say" data="${VM-Key-Terminator}" method="pronounced" type="name_spelled"/>
</nomatch>
</input>
</macro>
<macro name="fail_auth">
<input>
<match>
<action function="play-file" data="voicemail/vm-fail_auth.wav"/>
</match>
</input>
</macro>
<macro name="hello">
<input>
<match>
<!--<action function="play-file" data="voicemail/vm-hello.wav"/> -->
</match>
</input>
</macro>
<macro name="goodbye">
<input>
<match>
<action function="play-file" data="voicemail/vm-goodbye.wav"/>
</match>
</input>
</macro>
<macro name="abort">
<input>
<match>
<action function="play-file" data="voicemail/vm-abort.wav"/>
</match>
</input>
</macro>
<macro name="message_count">
<input field="${VM-Total-New-Urgent-Messages}" pattern="^(0)$">
<nomatch>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="${VM-Total-New-Urgent-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-urgent-new.wav"/>
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-New-Urgent-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</nomatch>
</input>
<input field="${VM-Total-New-Messages}" pattern="^(\d+)$">
<match>
<action function="play-file" data="voicemail/vm-you_have.wav"/>
<action function="say" data="${VM-Total-New-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-new.wav"/>
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-New-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</match>
</input>
<input field="${VM-Total-Saved-Messages}" pattern="^(0)$">
<nomatch>
<action function="play-file" data="currency/and.wav"/>
<action function="say" data="${VM-Total-Saved-Messages}" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-saved.wav"/>
<action function="phrase" phrase="plurial_msg@protovm" data="${VM-Total-Saved-Messages}:voicemail/vm-message.wav:voicemail/vm-messages.wav"/>
</nomatch>
</input>
</macro>
<macro name="menu">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Play-New-Messages}:voicemail/vm-listen_new.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Play-Saved-Messages}:voicemail/vm-listen_saved.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Config-Menu}:voicemail/vm-advanced.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Terminator}:voicemail/vm-to_exit.wav"/>
</match>
</input>
</macro>
<macro name="config_menu">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-Greeting}:voicemail/vm-to_record_greeting.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Choose-Greeting}:voicemail/vm-choose_greeting.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-Name}:voicemail/vm-record_name2.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Change-Password}:voicemail/vm-change_password.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Menu}:voicemail/vm-main_menu.wav"/>
</match>
</input>
</macro>
<macro name="record_name">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_name1.wav"/>
</match>
</input>
</macro>
<macro name="forward_ask_prepend">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
</match>
</input>
</macro>
<macro name="forward_ask_extension">
<input>
<match>
<action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
<!-- <action function="phrase" phrase="play-file" data="voicemail/vm-followed_by.wav"/>
<action function="say" data="${VM-Key-Terminate}" method="pronounced" type="name_spelled"/>-->
</match>
</input>
</macro>
<macro name="record_file_check">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Save-File}:voicemail/vm-save_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Record-File}:voicemail/vm-rerecord.wav"/>
</match>
</input>
</macro>
<macro name="record_urgent_check">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Urgent}:voicemail/vm-mark-urgent.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Terminator}:voicemail/vm-continue.wav"/>
</match>
</input>
</macro>
<macro name="forward_prepend">
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Prepend}:voicemail/vm-forward_add_intro.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Forward}:voicemail/vm-send_message_now.wav"/>
</match>
</input>
</macro>
<macro name="forward_message_enter_extension">
<input pattern="^([0-9#*])$">
<match>
<action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
<action function="play-file" data="voicemail/vm-followed_by.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="invalid_extension">
<input>
<match>
<action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
</match>
</input>
</macro>
<macro name="listen_file_check">
<input>
<match>
<!--<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Next-Msg}:voicemail/vm-for_next_msg.wav"/>--> <!-- Not existant in callie recordings -->
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Listen-File}:voicemail/vm-listen_to_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Save-File}:voicemail/vm-save_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Delete-File}:voicemail/vm-delete_recording.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
</match>
</input>
<input field="${VM-Message-Email}" pattern="^$">
<nomatch>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Email}:voicemail/vm-forward_to_email.wav"/>
</nomatch>
</input>
<input>
<match>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Callback}:voicemail/vm-return_call.wav"/>
<action function="phrase" phrase="press_key@protovm" data="${VM-Key-Main-Forward}:voicemail/vm-to_forward.wav"/>
</match>
</input>
</macro>
<macro name="choose_greeting">
<input>
<match>
<action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
</match>
</input>
</macro>
<macro name="choose_greeting_fail">
<input>
<match>
<action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
</match>
</input>
</macro>
<macro name="record_greeting">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_greeting.wav"/>
</match>
</input>
</macro>
<macro name="record_message">
<input>
<match>
<action function="play-file" data="voicemail/vm-record_message.wav"/>
</match>
</input>
</macro>
<macro name="greeting_selected">
<input pattern="^(\d+)$">
<match>
<action function="play-file" data="voicemail/vm-greeting.wav"/>
<action function="say" data="$1" method="pronounced" type="items"/>
<action function="play-file" data="voicemail/vm-selected.wav"/>
</match>
</input>
</macro>
<macro name="play_greeting">
<input pattern="^(.*)$">
<match>
<action function="play-file" data="voicemail/vm-person.wav"/>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
<action function="play-file" data="voicemail/vm-not_available.wav"/>
</match>
</input>
</macro>
<macro name="say_number">
<input pattern="^(\d+)$">
<match>
<action function="say" data="$1" method="pronounced" type="items"/>
</match>
</input>
</macro>
<macro name="say_message_number">
<input>
<match>
<action function="play-file" data="voicemail/vm-${VM-Message-Type}.wav"/>
<action function="play-file" data="voicemail/vm-message_number.wav"/>
<action function="say" data="${VM-Message-Number}" method="pronounced" type="items"/>
</match>
</input>
</macro>
<macro name="say_phone_number">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<macro name="say_name">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
</match>
</input>
</macro>
<!-- Note: Update this to marked-urgent,emailed and saved once new sound files are recorded -->
<macro name="ack">
<input pattern="^(too-small)$">
<match>
<action function="play-file" data="voicemail/vm-too-small.wav"/>
</match>
</input>
<input pattern="^(undeleted)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(deleted)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(saved)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(emailed)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
<input pattern="^(marked-urgent)$">
<match>
<action function="play-file" data="voicemail/vm-message.wav"/>
<action function="play-file" data="voicemail/vm-$1.wav"/>
</match>
</input>
</macro>
<macro name="say_date">
<input pattern="^(.*)$">
<match>
<action function="say" data="$1" method="pronounced" type="short_date_time"/>
</match>
</input>
</macro>
<macro name="say_date_event">
<input>
<match>
<action function="say" data="${VM-Message-Received-Epoch}" method="pronounced" type="short_date_time"/>
</match>
</input>
</macro>
<macro name="play_message">
<input>
<match>
<action function="play-file" data="${VM-Message-File-Path}"/>
</match>
</input>
</macro>
<macro name="play_recording">
<input>
<match>
<action function="play-file" data="${VM-Record-File-Path}"/>
</match>
</input>
</macro>
<macro name="disk_quota_exceeded">
<input>
<match>
<action function="play-file" data="voicemail/vm-mailbox_full.wav"/>
</match>
</input>
</macro>
</macros>
</include><!--This line will be ignored it's here to validate the xml and is optional -->

View File

@ -1,175 +0,0 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Marc Olivier Chouinard <mochouinard@moctel.com>
*
*
* utils.c -- MT VoiceMail / Different utility that might need to go into the core (after cleanup)
*
*/
#include <switch.h>
#include "util.h"
switch_status_t mt_merge_media_files(const char** inputs, const char *output) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_file_handle_t fh_output = { 0 };
int channels = 1;
int rate = 8000; /* TODO Make this configurable */
int j = 0;
if (switch_core_file_open(&fh_output, output, channels, rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s\n", output);
goto end;
}
for (j = 0; inputs[j] != NULL && j < 128 && status == SWITCH_STATUS_SUCCESS; j++) {
switch_file_handle_t fh_input = { 0 };
char buf[2048];
switch_size_t len = sizeof(buf) / 2;
if (switch_core_file_open(&fh_input, inputs[j], channels, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s\n", inputs[j]);
status = SWITCH_STATUS_GENERR;
break;
}
while (switch_core_file_read(&fh_input, buf, &len) == SWITCH_STATUS_SUCCESS) {
if (switch_core_file_write(&fh_output, buf, &len) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Write error\n");
status = SWITCH_STATUS_GENERR;
break;
}
}
if (fh_input.file_interface) {
switch_core_file_close(&fh_input);
}
}
if (fh_output.file_interface) {
switch_core_file_close(&fh_output);
}
end:
return status;
}
switch_event_t *jsonapi2event(switch_core_session_t *session, switch_event_t *apply_event, const char *api, const char *data) {
switch_event_t *phrases_event = NULL;
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
switch_api_execute(api, data, session, &stream);
switch_event_create_json(&phrases_event, (char *) stream.data);
switch_safe_free(stream.data);
if (apply_event) {
switch_event_header_t *hp;
for (hp = phrases_event->headers; hp; hp = hp->next) {
if (!strncasecmp(hp->name, "VM-", 3)) {
switch_event_add_header(apply_event, SWITCH_STACK_BOTTOM, hp->name, "%s", hp->value);
}
}
switch_event_destroy(&phrases_event);
phrases_event = apply_event;
}
return phrases_event;
}
char *generate_random_file_name(switch_core_session_t *session, const char *mod_name, char *file_extension) {
char rand_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = "";
switch_uuid_t srand_uuid;
switch_uuid_get(&srand_uuid);
switch_uuid_format(rand_uuid, &srand_uuid);
return switch_core_session_sprintf(session, "%s%s%s_%s.%s", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, mod_name, rand_uuid, file_extension);
}
switch_status_t mt_api_execute(switch_core_session_t *session, const char *apiname, const char *arguments) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
switch_api_execute(apiname, arguments, session, &stream);
if (!strncasecmp(stream.data, "-ERR", 4)) {
status = SWITCH_STATUS_GENERR;
}
switch_safe_free(stream.data);
return status;
}
void append_event_profile(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu) {
/* Used for some appending function */
if (profile->name && profile->id && profile->domain) {
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Profile", "%s", profile->name);
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Account-ID", "%s", profile->id);
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Account-Domain", "%s", profile->domain);
}
}
void populate_dtmfa_from_event(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu, char **dtmfa) {
int i = 0;
if (menu.event_keys_dtmf) {
switch_event_header_t *hp;
for (hp = menu.event_keys_dtmf->headers; hp; hp = hp->next) {
if (strlen(hp->name) < 3 && hp->value) { /* TODO This is a hack to discard default FS Events ! */
const char *varphrasename = switch_event_get_header(menu.event_keys_varname, hp->value);
dtmfa[i++] = hp->name;
if (varphrasename && !zstr(varphrasename)) {
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, varphrasename, "%s", hp->name);
}
}
}
}
}
void append_event_message(switch_core_session_t *session, vmivr_profile_t *profile, switch_event_t *phrase_params, switch_event_t *msg_list_event, size_t current_msg) {
char *varname;
char *apicmd;
varname = switch_mprintf("VM-List-Message-%" SWITCH_SIZE_T_FMT "-UUID", current_msg);
apicmd = switch_mprintf("json %s %s %s %s", profile->api_profile, profile->domain, profile->id, switch_event_get_header(msg_list_event, varname));
switch_safe_free(varname);
jsonapi2event(session, phrase_params, profile->api_msg_get, apicmd);
/* TODO Set these 2 header correctly */
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Type", "%s", "new");
switch_event_add_header(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Number", "%"SWITCH_SIZE_T_FMT, current_msg);
switch_event_add_header_string(phrase_params, SWITCH_STACK_BOTTOM, "VM-Message-Private-Local-Copy", "False");
switch_safe_free(apicmd);
}

View File

@ -1,16 +0,0 @@
#ifndef _UTIL_H_
#define _UTIL_H_
#include "config.h"
switch_status_t mt_merge_files(const char** inputs, const char *output);
void append_event_message(switch_core_session_t *session, vmivr_profile_t *profile, switch_event_t *phrase_params, switch_event_t *msg_list_event, size_t current_msg);
void append_event_profile(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu);
char *generate_random_file_name(switch_core_session_t *session, const char *mod_name, char *file_extension);
switch_event_t *jsonapi2event(switch_core_session_t *session, switch_event_t *apply_event, const char *api, const char *data);
switch_status_t mt_merge_media_files(const char** inputs, const char *output);
switch_status_t mt_api_execute(switch_core_session_t *session, const char *apiname, const char *arguments);
void populate_dtmfa_from_event(switch_event_t *phrase_params, vmivr_profile_t *profile, vmivr_menu_profile_t menu, char **dtmfa);
#endif /* _UTIL_H_ */

View File

@ -276,17 +276,19 @@ SWITCH_STANDARD_APP(valet_parking_function)
if (token->timeout) {
const char *var = switch_channel_get_variable(channel, "valet_ticket");
if (!strcmp(var, token->uuid)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Valet ticket %s accepted.\n", var);
switch_channel_set_variable(channel, "valet_ticket", NULL);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid token %s\n", token->uuid);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return;
if (!zstr(var)) {
if (!strcmp(var, token->uuid)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Valet ticket %s accepted.\n", var);
switch_channel_set_variable(channel, "valet_ticket", NULL);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid token %s\n", token->uuid);
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return;
}
}
}
if (token && (b_session = switch_core_session_locate(token->uuid))) {
if (!zstr(token->uuid) && (b_session = switch_core_session_locate(token->uuid))) {
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VALET_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext);

View File

@ -45,6 +45,7 @@ SWITCH_MODULE_DEFINITION(mod_voicemail, mod_voicemail_load, mod_voicemail_shutdo
#define VM_EVENT_MAINT "vm::maintenance"
#define VM_MAX_GREETINGS 9
#define VM_EVENT_QUEUE_SIZE 50000
static switch_status_t voicemail_inject(const char *data, switch_core_session_t *session);
@ -53,6 +54,9 @@ static struct {
switch_hash_t *profile_hash;
int debug;
int message_query_exact_match;
int32_t threads;
int32_t running;
switch_queue_t *event_queue;
switch_mutex_t *mutex;
switch_memory_pool_t *pool;
} globals;
@ -1160,6 +1164,8 @@ static switch_status_t create_file(switch_core_session_t *session, vm_profile_t
args.buf = input;
args.buflen = sizeof(input);
unlink(file_path);
switch_ivr_record_file(session, &fh, file_path, &args, profile->max_record_len);
if (switch_file_exists(file_path, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
@ -1819,7 +1825,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
uint32_t timeout, attempts = 0, retries = 0;
int failed = 0;
msg_type_t play_msg_type = MSG_NONE;
char *dir_path = NULL, *file_path = NULL;
char *dir_path = NULL, *file_path = NULL, *tmp_file_path = NULL;
int total_new_messages = 0;
int total_saved_messages = 0;
int total_new_urgent_messages = 0;
@ -2099,13 +2105,19 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
} else {
switch_event_t *params;
file_path = switch_mprintf("%s%sgreeting_%d.%s", dir_path, SWITCH_PATH_SEPARATOR, num, profile->file_ext);
tmp_file_path = switch_mprintf("%s%sgreeting_%d_TMP.%s", dir_path, SWITCH_PATH_SEPARATOR, num, profile->file_ext);
unlink(tmp_file_path);
TRY_CODE(create_file(session, profile, VM_RECORD_GREETING_MACRO, file_path, &message_len, SWITCH_TRUE, NULL, NULL));
switch_file_rename(tmp_file_path, file_path, switch_core_session_get_pool(session));
sql =
switch_mprintf("update voicemail_prefs set greeting_path='%s' where username='%s' and domain='%s'", file_path, myid,
domain_name);
vm_execute_sql(profile, sql, profile->mutex);
switch_safe_free(sql);
switch_safe_free(file_path);
switch_safe_free(tmp_file_path);
switch_event_create_subclass(&params, SWITCH_EVENT_CUSTOM, VM_EVENT_MAINT);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "VM-Action", "record-greeting");
@ -2146,10 +2158,14 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
} else if (!strcmp(input, profile->record_name_key)) {
switch_event_t *params;
file_path = switch_mprintf("%s%srecorded_name.%s", dir_path, SWITCH_PATH_SEPARATOR, profile->file_ext);
tmp_file_path = switch_mprintf("%s%srecorded_name_TMP.%s", dir_path, SWITCH_PATH_SEPARATOR, profile->file_ext);
unlink(tmp_file_path);
TRY_CODE(create_file(session, profile, VM_RECORD_NAME_MACRO, file_path, &message_len, SWITCH_FALSE, NULL, NULL));
switch_file_rename(tmp_file_path, file_path, switch_core_session_get_pool(session));
sql = switch_mprintf("update voicemail_prefs set name_path='%s' where username='%s' and domain='%s'", file_path, myid, domain_name);
vm_execute_sql(profile, sql, profile->mutex);
switch_safe_free(file_path);
switch_safe_free(tmp_file_path);
switch_safe_free(sql);
switch_event_create_subclass(&params, SWITCH_EVENT_CUSTOM, VM_EVENT_MAINT);
@ -2431,6 +2447,14 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
end:
switch_safe_free(file_path);
if (tmp_file_path) {
unlink(tmp_file_path);
free(tmp_file_path);
tmp_file_path = NULL;
}
if (switch_channel_ready(channel)) {
if (failed) {
status = switch_ivr_phrase_macro(session, VM_ABORT_MACRO, NULL, NULL, NULL);
@ -3629,16 +3653,14 @@ SWITCH_STANDARD_API(prefs_api_function)
switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, "MWI-Message-Account", account); \
switch_event_add_header(new_event, SWITCH_STACK_BOTTOM, "MWI-Voice-Message", "%d/%d (%d/%d)", \
+total_new_messages, total_saved_messages, total_new_urgent_messages, total_saved_urgent_messages); \
created++; \
} \
} \
}
static void message_query_handler(switch_event_t *event)
static void actual_message_query_handler(switch_event_t *event)
{
char *account = switch_event_get_header(event, "message-account");
int created = 0;
switch_event_t *new_event = NULL;
char *dup = NULL;
int total_new_messages = 0;
@ -3677,6 +3699,10 @@ static void message_query_handler(switch_event_t *event)
switch_hash_this(hi, NULL, NULL, &val);
profile = (vm_profile_t *) val;
parse_profile();
if (new_event) {
break;
}
}
}
}
@ -3685,7 +3711,7 @@ static void message_query_handler(switch_event_t *event)
}
if (!created) {
if (!new_event) {
if (switch_event_create(&new_event, SWITCH_EVENT_MESSAGE_WAITING) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, "MWI-Messages-Waiting", "no");
switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, "MWI-Message-Account", account);
@ -3707,6 +3733,101 @@ static void message_query_handler(switch_event_t *event)
}
static int EVENT_THREAD_RUNNING = 0;
static int EVENT_THREAD_STARTED = 0;
void *SWITCH_THREAD_FUNC vm_event_thread_run(switch_thread_t *thread, void *obj)
{
void *pop;
int done = 0;
switch_mutex_lock(globals.mutex);
if (!EVENT_THREAD_RUNNING) {
EVENT_THREAD_RUNNING++;
globals.threads++;
} else {
done = 1;
}
switch_mutex_unlock(globals.mutex);
if (done) {
return NULL;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Started\n");
while (globals.running == 1) {
int count = 0;
if (switch_queue_trypop(globals.event_queue, &pop) == SWITCH_STATUS_SUCCESS) {
switch_event_t *event = (switch_event_t *) pop;
if (!pop) {
break;
}
actual_message_query_handler(event);
switch_event_destroy(&event);
count++;
}
if (!count) {
switch_yield(100000);
}
}
while (switch_queue_trypop(globals.event_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
switch_event_t *event = (switch_event_t *) pop;
switch_event_destroy(&event);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Ended\n");
switch_mutex_lock(globals.mutex);
globals.threads--;
EVENT_THREAD_RUNNING = EVENT_THREAD_STARTED = 0;
switch_mutex_unlock(globals.mutex);
return NULL;
}
void vm_event_thread_start(void)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
int done = 0;
switch_mutex_lock(globals.mutex);
if (!EVENT_THREAD_STARTED) {
EVENT_THREAD_STARTED++;
} else {
done = 1;
}
switch_mutex_unlock(globals.mutex);
if (done) {
return;
}
switch_threadattr_create(&thd_attr, globals.pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_threadattr_priority_increase(thd_attr);
switch_thread_create(&thread, thd_attr, vm_event_thread_run, NULL, globals.pool);
}
void vm_event_handler(switch_event_t *event)
{
switch_event_t *cloned_event;
switch_event_dup(&cloned_event, event);
switch_assert(cloned_event);
switch_queue_push(globals.event_queue, cloned_event);
if (!EVENT_THREAD_STARTED) {
vm_event_thread_start();
}
}
struct holder {
vm_profile_t *profile;
@ -5482,14 +5603,20 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load)
switch_core_hash_init(&globals.profile_hash, globals.pool);
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_mutex_lock(globals.mutex);
globals.running = 1;
switch_mutex_unlock(globals.mutex);
switch_queue_create(&globals.event_queue, VM_EVENT_QUEUE_SIZE, globals.pool);
if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
globals.running = 0;
return status;
}
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
if (switch_event_bind(modname, SWITCH_EVENT_MESSAGE_QUERY, SWITCH_EVENT_SUBCLASS_ANY, message_query_handler, NULL)
if (switch_event_bind(modname, SWITCH_EVENT_MESSAGE_QUERY, SWITCH_EVENT_SUBCLASS_ANY, vm_event_handler, NULL)
!= SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
return SWITCH_STATUS_GENERR;
@ -5534,9 +5661,23 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_voicemail_shutdown)
void *val = NULL;
const void *key;
switch_ssize_t keylen;
int sanity = 0;
switch_mutex_lock(globals.mutex);
if (globals.running == 1) {
globals.running = 0;
}
switch_mutex_unlock(globals.mutex);
switch_event_free_subclass(VM_EVENT_MAINT);
switch_event_unbind_callback(message_query_handler);
switch_event_unbind_callback(vm_event_handler);
while (globals.threads) {
switch_cond_next();
if (++sanity >= 60000) {
break;
}
}
switch_mutex_lock(globals.mutex);
while ((hi = switch_hash_first(NULL, globals.profile_hash))) {

View File

@ -301,7 +301,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_makeCall)
amf_object_to_event(argv[3], &event);
}
if (rtmp_session_create_call(rsession, &newsession, 0, RTMP_DEFAULT_STREAM_AUDIO, number, user, domain, event) != SWITCH_CAUSE_NONE) {
if (rtmp_session_create_call(rsession, &newsession, 0, RTMP_DEFAULT_STREAM_AUDIO, number, user, domain, event) != SWITCH_CAUSE_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_ERROR, "Couldn't create call.\n");
}

View File

@ -283,6 +283,7 @@ static ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t
* The ioctl() implementation
*/
#ifndef HAVE_UNLOCKED_IOCTL
static int skypopen_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@ -302,13 +303,38 @@ static int skypopen_ioctl(struct inode *inode, struct file *filp,
}
}
#else// HAVE_UNLOCKED_IOCTL
static long skypopen_unlocked_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, p);
case SNDCTL_DSP_GETBLKSIZE:
return put_user(SKYPOPEN_BLK, p);
case SNDCTL_DSP_GETFMTS:
return put_user(28731, p);
default:
return 0;
}
}
#endif// HAVE_UNLOCKED_IOCTL
struct file_operations skypopen_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = skypopen_read,
.write = skypopen_write,
#ifndef HAVE_UNLOCKED_IOCTL
.ioctl = skypopen_ioctl,
#else// HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = skypopen_unlocked_ioctl,
#endif// HAVE_UNLOCKED_IOCTL
.open = skypopen_c_open,
.release = skypopen_c_release,
};

View File

@ -792,6 +792,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1),
TAG_IF(is_proxy, SOATAG_RTP_SELECT(1)),
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());

View File

@ -354,6 +354,7 @@ struct mod_sofia_globals {
int debug_presence;
int debug_sla;
int auto_restart;
int reg_deny_binding_fetch_and_no_lookup; /* backwards compatibility */
int auto_nat;
int tracelevel;
char *capture_server;
@ -1116,6 +1117,7 @@ switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *sess
char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type);
void sofia_glue_tech_simplify(private_object_t *tech_pvt);
switch_console_callback_match_t *sofia_reg_find_reg_url_multi(sofia_profile_t *profile, const char *user, const char *host);
switch_console_callback_match_t *sofia_reg_find_reg_url_with_positive_expires_multi(sofia_profile_t *profile, const char *user, const char *host);
switch_bool_t sofia_glue_profile_exists(const char *key);
void sofia_glue_global_siptrace(switch_bool_t on);
void sofia_glue_global_capture(switch_bool_t on);

View File

@ -48,7 +48,9 @@ extern su_log_t nth_server_log[];
extern su_log_t nua_log[];
extern su_log_t soa_log[];
extern su_log_t sresolv_log[];
#ifdef HAVE_SOFIA_STUN
extern su_log_t stun_log[];
#endif
extern su_log_t su_log_default[];
static void config_sofia_profile_urls(sofia_profile_t * profile);
@ -1255,8 +1257,9 @@ void sofia_event_callback(nua_event_t event,
if (!zstr(sofia_private->uuid)) {
if ((session = switch_core_session_locate(sofia_private->uuid))) {
if (switch_core_session_running(session)) {
switch_channel_t *channel = switch_core_session_get_channel(session);
if (switch_core_session_running(session) && !switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_core_session_queue_signal_data(session, de);
} else {
switch_core_session_message_t msg = { 0 };
@ -2077,8 +2080,10 @@ static su_log_t *sofia_get_logger(const char *name)
return soa_log;
} else if (!strcasecmp(name, "sresolv")) {
return sresolv_log;
#ifdef HAVE_SOFIA_STUN
} else if (!strcasecmp(name, "stun")) {
return stun_log;
#endif
} else if (!strcasecmp(name, "default")) {
return su_log_default;
} else {
@ -2105,7 +2110,9 @@ switch_status_t sofia_set_loglevel(const char *name, int level)
su_log_set_level(nua_log, level);
su_log_set_level(soa_log, level);
su_log_set_level(sresolv_log, level);
#ifdef HAVE_SOFIA_STUN
su_log_set_level(stun_log, level);
#endif
return SWITCH_STATUS_SUCCESS;
}
@ -2702,6 +2709,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
mod_sofia_globals.debug_sla = atoi(val);
} else if (!strcasecmp(var, "auto-restart")) {
mod_sofia_globals.auto_restart = switch_true(val);
} else if (!strcasecmp(var, "reg-deny-binding-fetch-and-no-lookup")) { /* backwards compatibility */
mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup = switch_true(val); /* remove when noone complains about the extra lookup */
if (switch_true(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Enabling reg-deny-binding-fetch-and-no-lookup - this functionality is "
"deprecated and will be removed - let FS devs know if you think it should stay\n");
}
} else if (!strcasecmp(var, "rewrite-multicasted-fs-path")) {
if( (!strcasecmp(val, "to_host")) || (!strcasecmp(val, "1")) ) {
/* old behaviour */
@ -3356,7 +3369,9 @@ switch_status_t config_sofia(int reload, char *profile_name)
su_log_redirect(nua_log, logger, NULL);
su_log_redirect(soa_log, logger, NULL);
su_log_redirect(sresolv_log, logger, NULL);
#ifdef HAVE_SOFIA_STUN
su_log_redirect(stun_log, logger, NULL);
#endif
}
if (!zstr(profile_name) && (profile = sofia_glue_find_profile(profile_name))) {
@ -3377,6 +3392,7 @@ switch_status_t config_sofia(int reload, char *profile_name)
}
mod_sofia_globals.auto_restart = SWITCH_TRUE;
mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup = SWITCH_FALSE; /* handle backwards compatilibity - by default use new behavior */
mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
if ((settings = switch_xml_child(cfg, "global_settings"))) {
@ -3393,6 +3409,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
mod_sofia_globals.debug_sla = atoi(val);
} else if (!strcasecmp(var, "auto-restart")) {
mod_sofia_globals.auto_restart = switch_true(val);
} else if (!strcasecmp(var, "reg-deny-binding-fetch-and-no-lookup")) { /* backwards compatibility */
mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup = switch_true(val); /* remove when noone complains about the extra lookup */
if (switch_true(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Enabling reg-deny-binding-fetch-and-no-lookup - this functionality is "
"deprecated and will be removed - let FS devs know if you think it should stay\n");
}
} else if (!strcasecmp(var, "rewrite-multicasted-fs-path")) {
if( (!strcasecmp(val, "to_host")) || (!strcasecmp(val, "1")) ) {
/* old behaviour */
@ -6737,35 +6759,37 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t
goto end;
}
if (dtmf.digit && (tech_pvt->dtmf_type == DTMF_INFO ||
sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF))) {
/* queue it up */
switch_channel_queue_dtmf(channel, &dtmf);
if (dtmf.digit) {
if (tech_pvt->dtmf_type == DTMF_INFO ||
sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) {
/* queue it up */
switch_channel_queue_dtmf(channel, &dtmf);
/* print debug info */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "INFO DTMF(%c)\n", dtmf.digit);
/* print debug info */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "INFO DTMF(%c)\n", dtmf.digit);
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
const char *uuid;
switch_core_session_t *session_b;
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
const char *uuid;
switch_core_session_t *session_b;
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (session_b = switch_core_session_locate(uuid))) {
while (switch_channel_has_dtmf(channel)) {
switch_dtmf_t idtmf = { 0, 0 };
if (switch_channel_dequeue_dtmf(channel, &idtmf) == SWITCH_STATUS_SUCCESS) {
switch_core_session_send_dtmf(session_b, &idtmf);
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (session_b = switch_core_session_locate(uuid))) {
while (switch_channel_has_dtmf(channel)) {
switch_dtmf_t idtmf = { 0, 0 };
if (switch_channel_dequeue_dtmf(channel, &idtmf) == SWITCH_STATUS_SUCCESS) {
switch_core_session_send_dtmf(session_b, &idtmf);
}
}
switch_core_session_rwunlock(session_b);
}
switch_core_session_rwunlock(session_b);
}
}
/* Send 200 OK response */
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"IGNORE INFO DTMF(%c) (This channel was not configured to use INFO DTMF!)\n", dtmf.digit);
/* Send 200 OK response */
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"IGNORE INFO DTMF(%c) (This channel was not configured to use INFO DTMF!)\n", dtmf.digit);
}
}
goto end;
}

View File

@ -3989,7 +3989,6 @@ static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_
{
switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
sdp_attribute_t *attr;
const char *var;
if (!t38_options) {
t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t));
@ -4069,20 +4068,8 @@ static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_
switch_channel_set_private(tech_pvt->channel, "t38_options", t38_options);
switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_execute_on_image"))) {
char *app, *arg = NULL;
app = switch_core_session_strdup(tech_pvt->session, var);
if (strstr(app, "::")) {
switch_core_session_execute_application_async(tech_pvt->session, app, arg);
} else {
if ((arg = strchr(app, ' '))) {
*arg++ = '\0';
}
switch_core_session_execute_application(tech_pvt->session, app, arg);
}
}
switch_channel_execute_on(tech_pvt->channel, "sip_execute_on_image");
switch_channel_api_on(tech_pvt->channel, "sip_api_on_image");
return t38_options;
}

View File

@ -30,9 +30,10 @@
* Marcel Barbulescu <marcelbarbulescu@gmail.com>
* David Knell <>
* Eliot Gable <egable AT.AT broadvox.com>
* Leon de Rooij <leon@scarlet-internet.nl>
*
*
* sofia_ref.c -- SOFIA SIP Endpoint (registration code)
* sofia_reg.c -- SOFIA SIP Endpoint (registration code)
*
*/
#include "mod_sofia.h"
@ -466,6 +467,39 @@ int sofia_reg_find_callback(void *pArg, int argc, char **argv, char **columnName
return cbt->matches == 1 ? 0 : 1;
}
int sofia_reg_find_reg_with_positive_expires_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct callback_t *cbt = (struct callback_t *) pArg;
sofia_destination_t *dst = NULL;
long int expires;
char *contact = NULL;
expires = atol(argv[1]) - 60 - (long) switch_epoch_time_now(NULL);
if (expires > 0) {
dst = sofia_glue_get_destination(argv[0]);
contact = switch_mprintf("<%s>;expires=%ld", dst->contact, expires);
if (!cbt->len) {
switch_console_push_match(&cbt->list, contact);
switch_safe_free(contact);
sofia_glue_free_destination(dst);
cbt->matches++;
return 0;
}
switch_copy_string(cbt->val, contact, cbt->len);
switch_safe_free(contact);
sofia_glue_free_destination(dst);
cbt->matches++;
return cbt->matches == 1 ? 0 : 1;
}
return 0;
}
int sofia_reg_nat_callback(void *pArg, int argc, char **argv, char **columnNames)
{
sofia_profile_t *profile = (sofia_profile_t *) pArg;
@ -875,6 +909,29 @@ switch_console_callback_match_t *sofia_reg_find_reg_url_multi(sofia_profile_t *p
}
switch_console_callback_match_t *sofia_reg_find_reg_url_with_positive_expires_multi(sofia_profile_t *profile, const char *user, const char *host)
{
struct callback_t cbt = { 0 };
char sql[512] = "";
if (!user) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n");
return NULL;
}
if (host) {
switch_snprintf(sql, sizeof(sql), "select contact,expires from sip_registrations where sip_user='%s' and (sip_host='%s' or presence_hosts like '%%%s%%')",
user, host, host);
} else {
switch_snprintf(sql, sizeof(sql), "select contact,expires from sip_registrations where sip_user='%s'", user);
}
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_reg_find_reg_with_positive_expires_callback, &cbt);
return cbt.list;
}
void sofia_reg_auth_challenge(sofia_profile_t *profile, nua_handle_t *nh, sofia_dispatch_event_t *de,
sofia_regtype_t regtype, const char *realm, int stale)
{
@ -983,8 +1040,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
}
}
/* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
switch_assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
/* all callers must confirm that sip and sip->sip_request are not NULL */
switch_assert(sip != NULL && sip->sip_request != NULL);
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
@ -1032,7 +1089,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
sub_host = to_host;
}
if (contact->m_url) {
if (contact && contact->m_url) {
const char *port = contact->m_url->url_port;
char new_port[25] = "";
const char *contact_host = contact->m_url->url_host;
@ -1130,7 +1187,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
if (expires) {
exptime = expires->ex_delta;
} else if (contact->m_expires) {
} else if (contact && contact->m_expires) {
exptime = atol(contact->m_expires);
}
@ -1163,11 +1220,13 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", reg_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
if (contact)
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", reg_desc);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
if (contact)
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-user", from_user);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-host", from_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "network-ip", network_ip);
@ -1178,7 +1237,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_event_fire(&s_event);
}
if (exptime && v_event && *v_event) {
if (contact && exptime && v_event && *v_event) {
char *exp_var;
char *allow_multireg = NULL;
int auto_connectile = 0;
@ -1310,11 +1369,13 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", reg_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
if (contact)
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", reg_desc);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
if (contact)
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-user", from_user);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-host", from_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "network-ip", network_ip);
@ -1343,6 +1404,10 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_goto_int(r, 1, end);
}
if (!contact)
goto respond_200_ok;
reg:
@ -1589,69 +1654,107 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
}
}
respond_200_ok:
if (regtype == REG_REGISTER) {
char exp_param[128] = "";
char date[80] = "";
switch_event_t *s_mwi_event = NULL;
switch_console_callback_match_t *contact_list = NULL;
tagi_t *contact_tags;
switch_console_callback_match_node_t *m;
int i;
s_event = NULL;
if (exptime) {
switch_snprintf(exp_param, sizeof(exp_param), "expires=%ld", exptime);
sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param);
if (contact) {
if (exptime) {
switch_snprintf(exp_param, sizeof(exp_param), "expires=%ld", exptime);
sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param);
if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER) ||
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER))) {
if (switch_event_create(&s_mwi_event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(s_mwi_event, SWITCH_STACK_BOTTOM, "Message-Account", "sip:%s@%s", mwi_user, mwi_host);
switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Call-ID", call_id);
}
}
if (sofia_test_pflag(profile, PFLAG_PRESENCE_ON_REGISTER) ||
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER))
|| send_pres == 1 || (reg_count == 1 && send_pres == 2)) {
if (sofia_test_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER)) {
if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, sub_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_fire(&s_event);
if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER) ||
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER))) {
if (switch_event_create(&s_mwi_event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(s_mwi_event, SWITCH_STACK_BOTTOM, "Message-Account", "sip:%s@%s", mwi_user, mwi_host);
switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Call-ID", call_id);
}
} else {
if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", "Registered");
switch_event_fire(&s_event);
}
}
}
} else {
switch_core_del_registration(to_user, reg_host, call_id);
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", reg_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
if (sofia_test_pflag(profile, PFLAG_PRESENCE_ON_REGISTER) ||
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER))
|| send_pres == 1 || (reg_count == 1 && send_pres == 2)) {
if (sofia_test_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER)) {
if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, sub_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_fire(&s_event);
}
} else {
if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", "Registered");
switch_event_fire(&s_event);
}
}
}
} else {
switch_core_del_registration(to_user, reg_host, call_id);
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-host", reg_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "contact", contact_str);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", call_id);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
}
}
}
switch_rfc822_date(date, switch_micro_time_now());
nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact),
TAG_IF(path_val, SIPTAG_PATH_STR(path_val)), NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_DATE_STR(date), TAG_END());
/* generate and respond a 200 OK */
if (mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup) {
/* handle backwards compatibility - contacts will not be looked up but only copied from the request into the response
remove this condition later if nobody complains about the extra select of the below new behavior
also remove the parts in mod_sofia.h, sofia.c and sofia_reg.c that refer to reg_deny_binding_fetch_and_no_lookup */
nua_respond(nh, SIP_200_OK, TAG_IF(contact, SIPTAG_CONTACT(sip->sip_contact)), TAG_IF(path_val, SIPTAG_PATH_STR(path_val)),
NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_DATE_STR(date), TAG_END());
} else if ((contact_list = sofia_reg_find_reg_url_with_positive_expires_multi(profile, from_user, reg_host))) {
/* all + 1 tag_i elements initialized as NULL - last one implies TAG_END() */
switch_zmalloc(contact_tags, sizeof(*contact_tags) * (contact_list->count + 1));
i = 0;
for (m = contact_list->head; m; m = m->next) {
contact_tags[i].t_tag = siptag_contact_str;
contact_tags[i].t_value = (tag_value_t) m->val;
++i;
}
nua_respond(nh, SIP_200_OK, TAG_IF(path_val, SIPTAG_PATH_STR(path_val)),
NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_DATE_STR(date), TAG_NEXT(contact_tags));
switch_safe_free(contact_tags);
switch_console_free_matches(&contact_list);
} else {
/* respond without any contacts */
nua_respond(nh, SIP_200_OK, TAG_IF(path_val, SIPTAG_PATH_STR(path_val)),
NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_DATE_STR(date), TAG_END());
}
if (s_event) {
switch_event_fire(&s_event);
@ -1661,7 +1764,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_event_fire(&s_mwi_event);
}
if (*contact_str && sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO)) {
if (contact && *contact_str && sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO)) {
sofia_sla_handle_register(nua, profile, sip, de, exptime, contact_str);
}
@ -1707,7 +1810,8 @@ void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_h
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
if (!(sip->sip_contact && sip->sip_contact->m_url)) {
/* backwards compatibility */
if (mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup && !(sip->sip_contact && sip->sip_contact->m_url)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT! ip: %s, port: %i\n", network_ip, network_port);
nua_respond(nh, 400, "Missing Contact Header", TAG_END());
goto end;

View File

@ -362,7 +362,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan
{
switch_status_t status;
void *pop;
switch_dtmf_t new_dtmf;
switch_dtmf_t new_dtmf = { 0 };
switch_assert(dtmf);
@ -376,14 +376,17 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan
if (is_dtmf(new_dtmf.digit)) {
switch_dtmf_t *dt;
int x = 0;
char str[2] = "";
str[0] = new_dtmf.digit;
if (new_dtmf.duration > switch_core_max_dtmf_duration(0)) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "%s EXCESSIVE DTMF DIGIT [%c] LEN [%d]\n",
switch_channel_get_name(channel), new_dtmf.digit, new_dtmf.duration);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "%s EXCESSIVE DTMF DIGIT [%s] LEN [%d]\n",
switch_channel_get_name(channel), str, new_dtmf.duration);
new_dtmf.duration = switch_core_max_dtmf_duration(0);
} else if (new_dtmf.duration < switch_core_min_dtmf_duration(0)) {
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "%s SHORT DTMF DIGIT [%c] LEN [%d]\n",
switch_channel_get_name(channel), new_dtmf.digit, new_dtmf.duration);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "%s SHORT DTMF DIGIT [%s] LEN [%d]\n",
switch_channel_get_name(channel), str, new_dtmf.duration);
new_dtmf.duration = switch_core_min_dtmf_duration(0);
} else if (!new_dtmf.duration) {
new_dtmf.duration = switch_core_default_dtmf_duration(0);
@ -1014,8 +1017,10 @@ SWITCH_DECLARE(void) switch_channel_process_export(switch_channel_t *channel, sw
const char *vval;
if ((vval = switch_channel_get_variable(channel, argv[x]))) {
char *vvar = argv[x];
if (!strncasecmp(vvar, "nolocal:", 8)) {
if (!strncasecmp(vvar, "nolocal:", 8)) { /* remove this later ? */
vvar += 8;
} else if (!strncasecmp(vvar, "_nolocal_", 9)) {
vvar += 9;
}
if (var_event) {
switch_event_del_header(var_event, vvar);
@ -1055,9 +1060,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_
var = switch_core_session_strdup(channel->session, varname);
if (var) {
if (!strncasecmp(var, "nolocal:", 8)) {
if (!strncasecmp(var, "nolocal:", 8)) { /* remove this later ? */
var_name = var + 8;
local = 0;
} else if (!strncasecmp(var, "_nolocal_", 9)) {
var_name = var + 9;
local = 0;
} else {
var_name = var;
}
@ -2822,6 +2830,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(swi
}
switch_channel_execute_on(channel, SWITCH_CHANNEL_EXECUTE_ON_RING_VARIABLE);
switch_channel_api_on(channel, SWITCH_CHANNEL_API_ON_RING_VARIABLE);
return SWITCH_STATUS_SUCCESS;
}
@ -2869,7 +2878,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_
switch_channel_execute_on(channel, SWITCH_CHANNEL_EXECUTE_ON_PRE_ANSWER_VARIABLE);
switch_channel_execute_on(channel, SWITCH_CHANNEL_EXECUTE_ON_MEDIA_VARIABLE);
switch_channel_api_on(channel, SWITCH_CHANNEL_API_ON_PRE_ANSWER_VARIABLE);
switch_channel_api_on(channel, SWITCH_CHANNEL_API_ON_MEDIA_VARIABLE);
if ((var = switch_channel_get_variable(channel, SWITCH_PASSTHRU_PTIME_MISMATCH_VARIABLE))) {
switch_channel_set_flag(channel, CF_PASSTHRU_PTIME_MISMATCH);
@ -2961,43 +2971,108 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_ring_ready_value(switch_c
return status;
}
static void do_api_on(switch_channel_t *channel, const char *variable)
{
char *app;
char *arg = NULL;
switch_stream_handle_t stream = { 0 };
app = switch_core_session_strdup(channel->session, variable);
if ((arg = strchr(app, ' '))) {
*arg++ = '\0';
}
SWITCH_STANDARD_STREAM(stream);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "%s process %s: %s(%s)\n%s\n",
channel->name, variable, app, switch_str_nil(arg), (char *) stream.data);
switch_api_execute(app, arg, NULL, &stream);
free(stream.data);
}
SWITCH_DECLARE(switch_status_t) switch_channel_api_on(switch_channel_t *channel, const char *variable_prefix)
{
switch_event_header_t *hp;
switch_event_t *event;
int x = 0;
switch_channel_get_variables(channel, &event);
for (hp = event->headers; hp; hp = hp->next) {
char *var = hp->name;
char *val = hp->value;
if (!strncasecmp(var, variable_prefix, strlen(variable_prefix))) {
if (hp->idx) {
int i;
for (i = 0; i < hp->idx; i++) {
x++;
do_api_on(channel, hp->array[i]);
}
} else {
x++;
do_api_on(channel, val);
}
}
}
switch_event_destroy(&event);
return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
static void do_execute_on(switch_channel_t *channel, const char *variable)
{
char *arg = NULL;
char *p;
int bg = 0;
char *app;
app = switch_core_session_strdup(channel->session, variable);
for(p = app; p && *p; p++) {
if (*p == ' ') {
*p++ = '\0';
arg = p;
break;
} else if (*p == ':' && (*(p+1) == ':')) {
bg++;
break;
}
}
if (bg) {
switch_core_session_execute_application_async(channel->session, app, arg);
} else {
switch_core_session_execute_application(channel->session, app, arg);
}
}
SWITCH_DECLARE(switch_status_t) switch_channel_execute_on(switch_channel_t *channel, const char *variable_prefix)
{
switch_event_header_t *hi;
switch_event_header_t *hp;
switch_event_t *event;
int x = 0;
switch_channel_get_variables(channel, &event);
for (hi = event->headers; hi; hi = hi->next) {
char *var = hi->name;
char *val = hi->value;
char *app;
for (hp = event->headers; hp; hp = hp->next) {
char *var = hp->name;
char *val = hp->value;
if (!strncasecmp(var, variable_prefix, strlen(variable_prefix))) {
char *arg = NULL;
char *p;
int bg = 0;
x++;
app = switch_core_session_strdup(channel->session, val);
for(p = app; p && *p; p++) {
if (*p == ' ') {
*p++ = '\0';
arg = p;
break;
} else if (*p == ':' && (*(p+1) == ':')) {
bg++;
break;
if (hp->idx) {
int i;
for (i = 0; i < hp->idx; i++) {
x++;
do_execute_on(channel, hp->array[i]);
}
}
if (bg) {
switch_core_session_execute_application_async(channel->session, app, arg);
} else {
switch_core_session_execute_application(channel->session, app, arg);
x++;
do_execute_on(channel, val);
}
}
}
@ -3013,7 +3088,6 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_chan
const char *uuid;
switch_core_session_t *other_session;
const char *var;
char *app;
switch_assert(channel != NULL);
@ -3079,24 +3153,10 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_chan
if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA)) {
switch_channel_execute_on(channel, SWITCH_CHANNEL_EXECUTE_ON_MEDIA_VARIABLE);
switch_channel_api_on(channel, SWITCH_CHANNEL_API_ON_MEDIA_VARIABLE);
}
if ((var = switch_channel_get_variable(channel, SWITCH_CHANNEL_API_ON_ANSWER_VARIABLE)) && !zstr(var)) {
switch_stream_handle_t stream = { 0 };
char *arg = NULL;
app = switch_core_session_strdup(channel->session, var);
if ((arg = strchr(app, ' '))) {
*arg++ = '\0';
}
SWITCH_STANDARD_STREAM(stream);
switch_api_execute(app, arg, NULL, &stream);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "%s api on answer: %s(%s)\n%s\n",
channel->name, app, switch_str_nil(arg), (char *) stream.data);
free(stream.data);
}
switch_channel_api_on(channel, SWITCH_CHANNEL_API_ON_ANSWER_VARIABLE);
switch_channel_presence(channel, "unknown", "answered", NULL);

View File

@ -135,10 +135,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file,
switch_uuid_format(uuid_str, &uuid);
fh->spool_path = switch_core_sprintf(fh->memory_pool, "%s%s%s.%s", spool_path, SWITCH_PATH_SEPARATOR, uuid_str, ext);
} else {
fh->spool_path = NULL;
}
if (rhs) {
fh->handler = switch_core_strdup(fh->memory_pool, rhs);
} else {
fh->handler = NULL;
}
if (channels) {

View File

@ -996,7 +996,7 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread,
trans = 1;
}
if (len + newlen > sql_len) {
if (len + newlen + 1 > sql_len) {
int new_mlen = len + newlen + 10240;
if (new_mlen < runtime.max_sql_buffer_len) {
@ -1935,7 +1935,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
case SCDB_TYPE_ODBC:
{
char *err;
switch_cache_db_test_reactive(dbh, "select call_uuid, read_bit_rate from channels", "DROP TABLE channels", create_channels_sql);
switch_cache_db_test_reactive(dbh, "select call_uuid, read_bit_rate, sent_callee_name from channels", "DROP TABLE channels", create_channels_sql);
switch_cache_db_test_reactive(dbh, "select * from detailed_calls where sent_callee_name=''", "DROP VIEW detailed_calls", detailed_calls_sql);
switch_cache_db_test_reactive(dbh, "select * from basic_calls where sent_callee_name=''", "DROP VIEW basic_calls", basic_calls_sql);
if (runtime.odbc_dbtype == DBTYPE_DEFAULT) {

View File

@ -333,17 +333,11 @@ static void *SWITCH_THREAD_FUNC switch_event_thread(switch_thread_t *thread, voi
if (++loops > 2) {
uint32_t last_sps = 0, sess_count = switch_core_session_count();
if (auto_pause) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Event system *still* overloading.\n");
} else {
switch_core_session_ctl(SCSC_LAST_SPS, &last_sps);
last_sps = (uint32_t) (float) (last_sps * 0.75f);
sess_count = (uint32_t) (float) (sess_count * 0.75f);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
"Event system overloading. Taking a 10 second break, Reducing max_sessions to %d %dsps\n", sess_count, last_sps);
switch_core_session_limit(sess_count);
switch_core_session_ctl(SCSC_SPS, &last_sps);
"Event system overloading. Taking a 10 second break\n");
auto_pause = 10;
switch_core_session_ctl(SCSC_PAUSE_INBOUND, &auto_pause);
}

View File

@ -2458,6 +2458,8 @@ static switch_status_t tone_on_dtmf(switch_core_session_t *session, const switch
cont->list[i].callback(cont->session, cont->list[i].app, cont->list[i].data);
} else {
switch_channel_execute_on(switch_core_session_get_channel(cont->session), SWITCH_CHANNEL_EXECUTE_ON_TONE_DETECT_VARIABLE);
switch_channel_api_on(switch_core_session_get_channel(cont->session), SWITCH_CHANNEL_API_ON_TONE_DETECT_VARIABLE);
if (cont->list[i].app) {
switch_core_session_execute_application_async(cont->session, cont->list[i].app, cont->list[i].data);
}

View File

@ -2561,7 +2561,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
switch_channel_set_variable(originate_status[i].peer_channel, "originating_leg_uuid", switch_core_session_get_uuid(session));
}
switch_channel_execute_on(originate_status[i].peer_channel, "execute_on_originate");
switch_channel_execute_on(originate_status[i].peer_channel, SWITCH_CHANNEL_EXECUTE_ON_ORIGINATE_VARIABLE);
switch_channel_api_on(originate_status[i].peer_channel, SWITCH_CHANNEL_API_ON_ORIGINATE_VARIABLE);
}
if (table) {

View File

@ -377,7 +377,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
int divisor = 0;
int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT;
int restart_limit_on_dtmf = 0;
const char *prefix;
const char *prefix, *var;
prefix = switch_channel_get_variable(channel, "sound_prefix");
@ -756,6 +756,29 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
switch_core_file_close(fh);
if ((var = switch_channel_get_variable(channel, "record_post_process_exec_api"))) {
char *cmd = switch_core_session_strdup(session, var);
char *data, *expanded = NULL;
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
if ((data = strchr(cmd, ':'))) {
*data++ = '\0';
expanded = switch_channel_expand_variables(channel, data);
}
switch_api_execute(cmd, expanded, session, &stream);
if (expanded && expanded != data) {
free(expanded);
}
switch_safe_free(stream.data);
}
if (read_impl.samples_per_second) {
switch_channel_set_variable_printf(channel, "record_seconds", "%d", fh->samples_out / read_impl.samples_per_second);
switch_channel_set_variable_printf(channel, "record_ms", "%d", fh->samples_out / (read_impl.samples_per_second / 1000));

View File

@ -994,8 +994,8 @@ static switch_status_t switch_loadable_module_load_module_ex(char *dir, char *fn
switch_snprintf(path, len, "%s%s%s%s", dir, SWITCH_PATH_SEPARATOR, file, ext);
}
switch_mutex_lock(loadable_modules.mutex);
if (switch_core_hash_find(loadable_modules.module_hash, file)) {
if (switch_core_hash_find_locked(loadable_modules.module_hash, file, loadable_modules.mutex)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Module %s Already Loaded!\n", file);
*err = "Module already loaded";
status = SWITCH_STATUS_FALSE;
@ -1010,7 +1010,7 @@ static switch_status_t switch_loadable_module_load_module_ex(char *dir, char *fn
} else {
*err = "module load file routine returned an error";
}
switch_mutex_unlock(loadable_modules.mutex);
return status;