[Freeswitch-svn] [commit] r5846 - in freeswitch/trunk: . build conf src src/include src/mod/applications/mod_dptools src/mod/applications/mod_voicemail
Freeswitch SVN
anthm at freeswitch.org
Thu Oct 11 23:28:59 EDT 2007
Author: anthm
Date: Thu Oct 11 23:28:59 2007
New Revision: 5846
Added:
freeswitch/trunk/conf/voicemail.conf.xml
freeswitch/trunk/conf/voicemail_en_tts.xml
freeswitch/trunk/src/mod/applications/mod_voicemail/
freeswitch/trunk/src/mod/applications/mod_voicemail/Makefile
freeswitch/trunk/src/mod/applications/mod_voicemail/mod_voicemail.c
freeswitch/trunk/src/mod/applications/mod_voicemail/mod_voicemail.vcproj
Modified:
freeswitch/trunk/Makefile.am
freeswitch/trunk/build/modules.conf.in
freeswitch/trunk/conf/default_context.xml
freeswitch/trunk/conf/directory.xml
freeswitch/trunk/conf/freeswitch.xml
freeswitch/trunk/conf/modules.conf.xml
freeswitch/trunk/src/include/switch_apr.h
freeswitch/trunk/src/include/switch_types.h
freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c
freeswitch/trunk/src/switch_apr.c
freeswitch/trunk/src/switch_core.c
freeswitch/trunk/src/switch_core_file.c
freeswitch/trunk/src/switch_xml.c
Log:
EXECUTE ORDER 66
Modified: freeswitch/trunk/Makefile.am
==============================================================================
--- freeswitch/trunk/Makefile.am (original)
+++ freeswitch/trunk/Makefile.am Thu Oct 11 23:28:59 2007
@@ -135,6 +135,7 @@
endif
if ADD_ODBC
+CORE_CFLAGS += -DSWITCH_HAVE_ODBC
libfreeswitch_la_SOURCES += src/switch_odbc.c
libfreeswitch_la_LDFLAGS += -lodbc
endif
Modified: freeswitch/trunk/build/modules.conf.in
==============================================================================
--- freeswitch/trunk/build/modules.conf.in (original)
+++ freeswitch/trunk/build/modules.conf.in Thu Oct 11 23:28:59 2007
@@ -5,6 +5,7 @@
applications/mod_dptools
applications/mod_enum
applications/mod_fifo
+#applications/mod_voicemail
#applications/mod_ivrtest
#applications/mod_soundtouch
#applications/mod_rss
Modified: freeswitch/trunk/conf/default_context.xml
==============================================================================
--- freeswitch/trunk/conf/default_context.xml (original)
+++ freeswitch/trunk/conf/default_context.xml Thu Oct 11 23:28:59 2007
@@ -19,6 +19,21 @@
</condition>
</extension>
+ <extension name="7771">
+ <condition field="destination_number" expression="^7771$">
+ <action application="answer"/>
+ <action application="set" data="voicemail_authorized=${sip_authorized}"/>
+ <action application="voicemail" data="check demo $${domain} ${sip_from_user}"/>
+ </condition>
+ </extension>
+
+ <extension name="7772">
+ <condition field="destination_number" expression="^7772$">
+ <action application="answer"/>
+ <action application="voicemail" data="demo $${domain} ${sip_from_user}"/>
+ </condition>
+ </extension>
+
<extension name="9193">
<condition field="destination_number" expression="^9193$">
<action application="set" data="bridge_pre_execute_bleg_app=soundtouch"/>
Modified: freeswitch/trunk/conf/directory.xml
==============================================================================
--- freeswitch/trunk/conf/directory.xml (original)
+++ freeswitch/trunk/conf/directory.xml Thu Oct 11 23:28:59 2007
@@ -1,7 +1,7 @@
<!--the domain or ip (the right hand side of the @ in the addr-->
<domain name="$${domain}">
<!--the user id (the left hand side of the @ in the addr-->
- <user id="stpeter">
+ <user id="stpeter" mailbox="1000"> <!--if id is numeric mailbox param is not necessary-->
<!-- Outbound Registrations Related to this user -->
<gateways>
<!--<gateway name="asterlink.com">-->
@@ -34,6 +34,8 @@
<params>
<!-- omit password for authless registration -->
<param name="password" value="mypass"/>
+ <param name="vm-password" value="1234"/><!--if vm-password is omitted password param is used-->
+ <!--<param name="vm-mailto" value="me at mydomain.com"/>-->
<!-- optionally use this instead if you want to store the hash of user:domain:pass-->
<!--<param name="a1-hash" value="c6440e5de50b403206989679159de89a"/>-->
</params>
Modified: freeswitch/trunk/conf/freeswitch.xml
==============================================================================
--- freeswitch/trunk/conf/freeswitch.xml (original)
+++ freeswitch/trunk/conf/freeswitch.xml Thu Oct 11 23:28:59 2007
@@ -102,6 +102,7 @@
<!--#include "conference.conf.xml"-->
<!-- ivr.conf is used by mod_dptools -->
<!--#include "ivr.conf.xml"-->
+ <!--#include "voicemail.conf.xml"-->
<!-- Dialplan Interfaces -->
<!--#include "dialplan_directory.conf.xml"-->
@@ -145,6 +146,8 @@
<macros>
<language name="en" sound_path="/snds" tts_engine="cepstral" tts_voice="david">
<!--#include "lang_en.xml"-->
+ <!--voicemail_en_tts is purely implemented with tts, we need a files based implementation too -->
+ <!--#include "voicemail_en_tts.xml"-->
</language>
<language name="fr" sound_path="/var/sounds/lang/fr/jean" tts_engine="cepstral" tts_voice="jean-pierre">
<!--#include "lang_fr.xml"-->
Modified: freeswitch/trunk/conf/modules.conf.xml
==============================================================================
--- freeswitch/trunk/conf/modules.conf.xml (original)
+++ freeswitch/trunk/conf/modules.conf.xml Thu Oct 11 23:28:59 2007
@@ -37,6 +37,7 @@
<load module="mod_conference"/>
<load module="mod_dptools"/>
<load module="mod_fifo"/>
+ <!--<load module="mod_voicemail"/>-->
<!-- Dialplan Interfaces -->
<!-- <load module="mod_dialplan_directory"/> -->
Added: freeswitch/trunk/conf/voicemail.conf.xml
==============================================================================
--- (empty file)
+++ freeswitch/trunk/conf/voicemail.conf.xml Thu Oct 11 23:28:59 2007
@@ -0,0 +1,30 @@
+<configuration name="voicemail.conf" description="Voicemail">
+ <settings>
+ </settings>
+ <profiles>
+ <profile name="demo">
+ <param name="terminator-key" value="#"/>
+ <param name="max-login-attempts" value="3"/>
+ <param name="digit-timeout" value="10000"/>
+ <param name="max-record-len" value="300"/>
+ <param name="tone-spec" value="%(1000, 0, 640)"/>
+ <param name="terminator-key" value="#"/>
+ <param name="play-new-messages-key" value="1"/>
+ <param name="play-saved-messages-key" value="2"/>
+ <param name="save-message-key" value="8"/>
+ <param name="delete-message-key" value="7"/>
+ <param name="replay-message-key" value="1"/>
+ <param name="main-menu-key" value="0"/>
+ <param name="config-menu-key" value="5"/>
+ <param name="record-greeting-key" value="1"/>
+ <param name="choose-greeting-key" value="2"/>
+ <param name="record-name-key" value="3"/>
+ <param name="record-file-key" value="3"/>
+ <param name="listen-file-key" value="1"/>
+ <param name="save-file-key" value="2"/>
+ <param name="delete-file-key" value="7"/>
+ <param name="undelete-file-key" value="8"/>
+ <!--<param name="odbc-dsn" value="dsn:user:pass"/>-->
+ </profile>
+ </profiles>
+</configuration>
Added: freeswitch/trunk/conf/voicemail_en_tts.xml
==============================================================================
--- (empty file)
+++ freeswitch/trunk/conf/voicemail_en_tts.xml Thu Oct 11 23:28:59 2007
@@ -0,0 +1,209 @@
+<include><!--This line will be ignored it's here to validate the xml and is optional -->
+ <macro name="voicemail_enter_id">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="please enter your i d, followed by $1"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_enter_pass">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="please enter your password, followed by $1"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_fail_auth">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="login incorrect"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_hello">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="welcome to your voicemail"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_goodbye">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="goodbye"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_abort">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="too many failed attempts"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_new_message_count">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="you have $1 new messages in folder ${voicemail_current_folder}"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_saved_message_count">
+ <input pattern="(.*)">
+ <match>
+ <action function="speak-text" data="you have $1 saved messages in folder ${voicemail_current_folder}"/>
+ </match>
+ </input>
+ </macro>
+
+
+ <macro name="voicemail_menu">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="speak-text" data="press $1 to listen to new messages. press $2 to listen to saved messages. press $3 for advanced options"/>
+ </match>
+ </input>
+ </macro>
+
+
+ <macro name="voicemail_config_menu">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="speak-text"
+ data="press $1 to record a greeting, press $2 to choose a greeting, press $3 to record your name, press $4 for the main menu"/>
+ </match>
+ </input>
+ </macro>
+
+
+ <macro name="voicemail_record_name">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="at the tone, record your name, press any key or stop talking to end the recording."/>
+
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_record_file_check">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="speak-text"
+ data="press $1 to listen to the recording, press $2 to save the recording, press $3 to re record"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_listen_file_check">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="speak-text"
+ data="press $1 to listen to the recording again, press $2 to save the recording, press $3 to delete the recording"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_choose_greeting">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="choose a greeting between 1 and 3"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_choose_greeting_fail">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="invalid value"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_record_greeting">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="record your greeting at the tone, press any key or stop talking to end the recording"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_record_message">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="record your message at the tone, press any key or stop talking to end the recording"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_greeting_selected">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="greeting $1 selected"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_play_greeting">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="$1 is not available"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_say_number">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="$1"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_say_message_number">
+ <input pattern="^([a-z]+):(.*)$">
+ <match>
+ <action function="speak-text" data="$1 message number $2"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_say_phone_number">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="$1"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_say_name">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="$1"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_ack">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="message $1"/>
+ </match>
+ </input>
+ </macro>
+
+ <macro name="voicemail_say_date">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="speak-text" data="$strftime($1|%A, %B %d %Y, %I %m %p)"/>
+ </match>
+ </input>
+ </macro>
+
+</include><!--This line will be ignored it's here to validate the xml and is optional -->
Modified: freeswitch/trunk/src/include/switch_apr.h
==============================================================================
--- freeswitch/trunk/src/include/switch_apr.h (original)
+++ freeswitch/trunk/src/include/switch_apr.h Thu Oct 11 23:28:59 2007
@@ -748,6 +748,11 @@
SWITCH_DECLARE(switch_status_t) switch_file_exists(const char *filename, switch_memory_pool_t *pool);
+SWITCH_DECLARE(switch_status_t) switch_dir_make(const char *path, switch_fileperms_t perm,
+ switch_memory_pool_t *pool);
+SWITCH_DECLARE(switch_status_t) switch_dir_make_recursive(const char *path, switch_fileperms_t perm,
+ switch_memory_pool_t *pool);
+
typedef struct switch_dir switch_dir_t;
struct switch_array_header_t {
Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h (original)
+++ freeswitch/trunk/src/include/switch_types.h Thu Oct 11 23:28:59 2007
@@ -253,6 +253,7 @@
char *temp_dir;
char *htdocs_dir;
char *grammar_dir;
+ char *storage_dir;
};
typedef struct switch_directories switch_directories;
Modified: freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c (original)
+++ freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c Thu Oct 11 23:28:59 2007
@@ -675,9 +675,16 @@
switch_size_t retsize;
switch_time_exp_t tm;
char date[80] = "";
-
- switch_time_exp_lt(&tm, switch_time_now());
- switch_strftime(date, &retsize, sizeof(date), cmd ? cmd : "%Y-%m-%d %T", &tm);
+ switch_time_t thetime;
+ char *p;
+ if (!switch_strlen_zero(cmd) && (p = strchr(cmd, '|'))) {
+ thetime = switch_time_make(atoi(cmd),0);
+ cmd = p+1;
+ } else {
+ thetime = switch_time_now();
+ }
+ switch_time_exp_lt(&tm, thetime);
+ switch_strftime(date, &retsize, sizeof(date), switch_strlen_zero(cmd) ? "%Y-%m-%d %T" : cmd, &tm);
stream->write_function(stream, "%s", date);
return SWITCH_STATUS_SUCCESS;
Added: freeswitch/trunk/src/mod/applications/mod_voicemail/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_voicemail/Makefile Thu Oct 11 23:28:59 2007
@@ -0,0 +1,2 @@
+BASE=../../../..
+include /usr/src/freeswitch.trunk/build/modmake.rules
Added: freeswitch/trunk/src/mod/applications/mod_voicemail/mod_voicemail.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_voicemail/mod_voicemail.c Thu Oct 11 23:28:59 2007
@@ -0,0 +1,1633 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * 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 <anthmct at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct at yahoo.com>
+ *
+ *
+ * mod_voicemail.c -- Voicemail Module
+ *
+ */
+#include <switch.h>
+
+#ifdef SWITCH_HAVE_ODBC
+#include <switch_odbc.h>
+#endif
+
+
+#define TRY_CODE(code) do {status = code; if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { goto end; } break;} while(status)
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load);
+SWITCH_MODULE_DEFINITION(mod_voicemail, mod_voicemail_load, NULL, NULL);
+
+static struct {
+ switch_hash_t *profile_hash;
+ int debug;
+ switch_memory_pool_t *pool;
+} globals;
+
+struct vm_profile {
+ char *name;
+ char *dbname;
+ char *odbc_dsn;
+ char *odbc_user;
+ char *odbc_pass;
+ char terminator_key[2];
+ char play_new_messages_key[2];
+ char play_saved_messages_key[2];
+ char save_message_key[2];
+ char delete_message_key[2];
+ char replay_message_key[2];
+
+ char main_menu_key[2];
+ char config_menu_key[2];
+ char record_greeting_key[2];
+ char choose_greeting_key[2];
+ char record_name_key[2];
+
+ char record_file_key[2];
+ char listen_file_key[2];
+ char save_file_key[2];
+ char delete_file_key[2];
+ char undelete_file_key[2];
+ char *tone_spec;
+ uint32_t digit_timeout;
+ uint32_t max_login_attempts;
+ uint32_t max_record_len;
+ switch_mutex_t *mutex;
+#ifdef SWITCH_HAVE_ODBC
+ switch_odbc_handle_t *master_odbc;
+#else
+ void *filler1;
+#endif
+};
+typedef struct vm_profile vm_profile_t;
+
+
+#define B64BUFFLEN 1024
+static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int write_buf(int fd, char *buf)
+{
+
+ int len = (int) strlen(buf);
+ if (fd && write(fd, buf, len) != len) {
+ close(fd);
+ return 0;
+ }
+
+ return 1;
+}
+static switch_bool_t vm_email(char *to, char *from, char *headers, char *body, char *file)
+{
+ char *bound = "XXXX_boundary_XXXX";
+ char filename[80], buf[B64BUFFLEN];
+ int fd = 0, ifd = 0;
+ int x = 0, y = 0, bytes = 0, ilen = 0;
+ unsigned int b = 0, l = 0;
+ unsigned char in[B64BUFFLEN];
+ unsigned char out[B64BUFFLEN + 512];
+ char *path = NULL;
+
+ snprintf(filename, 80, "%smail.%ld%04x", SWITCH_GLOBAL_dirs.temp_dir, time(NULL), rand() & 0xffff);
+
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644))) {
+ if (file) {
+ path = file;
+ if ((ifd = open(path, O_RDONLY)) < 1) {
+ return SWITCH_FALSE;
+ }
+
+ snprintf(buf, B64BUFFLEN, "MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n", bound);
+ if (!write_buf(fd, buf)) {
+ return SWITCH_FALSE;
+ }
+ }
+
+ if (headers && !write_buf(fd, headers))
+ return SWITCH_FALSE;
+
+ if (!write_buf(fd, "\n\n"))
+ return SWITCH_FALSE;
+
+ if (file) {
+ snprintf(buf, B64BUFFLEN, "--%s\nContent-Type: text/plain\n\n", bound);
+ if (!write_buf(fd, buf))
+ return SWITCH_FALSE;
+ }
+
+ if (body) {
+ if (!write_buf(fd, body)) {
+ return SWITCH_FALSE;
+ }
+ }
+
+ if (file) {
+ snprintf(buf, B64BUFFLEN, "\n\n--%s\nContent-Type: application/octet-stream\n"
+ "Content-Transfer-Encoding: base64\n"
+ "Content-Description: Sound attachment.\n" "Content-Disposition: attachment; filename=\"%s\"\n\n", bound, switch_cut_path(file));
+ if (!write_buf(fd, buf))
+ return SWITCH_FALSE;
+
+ while ((ilen = read(ifd, in, B64BUFFLEN))) {
+ for (x = 0; x < ilen; x++) {
+ b = (b << 8) + in[x];
+ l += 8;
+ while (l >= 6) {
+ out[bytes++] = c64[(b >> (l -= 6)) % 64];
+ if (++y != 72)
+ continue;
+ out[bytes++] = '\n';
+ y = 0;
+ }
+ }
+ if (write(fd, &out, bytes) != bytes) {
+ return -1;
+ } else
+ bytes = 0;
+
+ }
+
+ if (l > 0) {
+ out[bytes++] = c64[((b % 16) << (6 - l)) % 64];
+ }
+ if (l != 0)
+ while (l < 6) {
+ out[bytes++] = '=', l += 2;
+ }
+ if (write(fd, &out, bytes) != bytes) {
+ return -1;
+ }
+
+ }
+
+
+
+ if (file) {
+ snprintf(buf, B64BUFFLEN, "\n\n--%s--\n.\n", bound);
+ if (!write_buf(fd, buf))
+ return SWITCH_FALSE;
+ }
+ }
+
+ if (fd) {
+ close(fd);
+ }
+ if (ifd) {
+ close(ifd);
+ }
+ snprintf(buf, B64BUFFLEN, "/bin/cat %s | /usr/sbin/sendmail -tvf \"%s\" %s", filename, from, to);
+ if(system(buf)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to execute command: %s\n", buf);
+ }
+
+ unlink(filename);
+
+
+ if (file) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Emailed file [%s] to [%s]\n", filename, to);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Emailed data to [%s]\n", to);
+ }
+
+ return SWITCH_TRUE;
+}
+
+static switch_status_t vm_execute_sql(vm_profile_t *profile, char *sql, switch_mutex_t *mutex)
+{
+ switch_core_db_t *db;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ if (mutex) {
+ switch_mutex_lock(mutex);
+ }
+
+#ifdef SWITCH_HAVE_ODBC
+ if (profile->odbc_dsn) {
+ SQLHSTMT stmt;
+ if (switch_odbc_handle_exec(profile->master_odbc, sql, &stmt) != SWITCH_ODBC_SUCCESS) {
+ char *err_str;
+ err_str = switch_odbc_handle_get_error(profile->master_odbc, stmt);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
+ switch_safe_free(err_str);
+ status = SWITCH_STATUS_FALSE;
+ }
+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+ } else {
+#endif
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ status = SWITCH_STATUS_FALSE;
+ goto end;
+ }
+
+ status = switch_core_db_persistant_execute(db, sql, 25);
+ switch_core_db_close(db);
+
+#ifdef SWITCH_HAVE_ODBC
+ }
+#endif
+
+
+ end:
+ if (mutex) {
+ switch_mutex_unlock(mutex);
+ }
+
+ return status;
+}
+
+
+static switch_bool_t vm_execute_sql_callback(vm_profile_t *profile,
+ switch_mutex_t *mutex,
+ char *sql,
+ switch_core_db_callback_func_t callback,
+ void *pdata)
+{
+ switch_bool_t ret = SWITCH_FALSE;
+ switch_core_db_t *db;
+ char *errmsg = NULL;
+
+ if (mutex) {
+ switch_mutex_lock(mutex);
+ }
+
+
+#ifdef SWITCH_HAVE_ODBC
+ if (profile->odbc_dsn) {
+ switch_odbc_handle_callback_exec(profile->master_odbc, sql, callback, pdata);
+ } else {
+#endif
+
+
+
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ goto end;
+ }
+
+
+ switch_core_db_exec(db, sql, callback, pdata, &errmsg);
+
+ if (errmsg) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
+ free(errmsg);
+ }
+
+ if (db) {
+ switch_core_db_close(db);
+ }
+
+#ifdef SWITCH_HAVE_ODBC
+ }
+#endif
+
+
+ end:
+
+ if (mutex) {
+ switch_mutex_unlock(mutex);
+ }
+
+
+
+ return ret;
+
+}
+
+
+static char vm_sql[] =
+ "CREATE TABLE voicemail_data (\n"
+ " created_epoch INTEGER(8),\n"
+ " read_epoch INTEGER(8),\n"
+ " user VARCHAR(255),\n"
+ " domain VARCHAR(255),\n"
+ " uuid VARCHAR(255),\n"
+ " cid_name VARCHAR(255),\n"
+ " cid_number VARCHAR(255),\n"
+ " in_folder VARCHAR(255),\n"
+ " file_path VARCHAR(255),\n"
+ " flags VARCHAR(255)\n"
+ ");\n";
+
+
+static char vm_pref_sql[] =
+ "CREATE TABLE voicemail_prefs (\n"
+ " user VARCHAR(255),\n"
+ " domain VARCHAR(255),\n"
+ " name_path VARCHAR(255),\n"
+ " greeting_path VARCHAR(255)\n"
+ ");\n";
+
+
+
+
+static switch_status_t load_config(void)
+{
+ char *cf = "voicemail.conf";
+ vm_profile_t *profile = NULL;
+ switch_xml_t cfg, xml, settings, param, x_profile, x_profiles;
+
+ memset(&globals, 0, sizeof(globals));
+ switch_core_new_memory_pool(&globals.pool);
+ switch_core_hash_init(&globals.profile_hash, globals.pool);
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ return SWITCH_STATUS_TERM;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "debug")) {
+ globals.debug = atoi(val);
+ }
+ }
+ }
+
+ if (!(x_profiles = switch_xml_child(cfg, "profiles"))) {
+ goto end;
+ }
+
+ for (x_profile = switch_xml_child(x_profiles, "profile"); x_profile; x_profile = x_profile->next) {
+ char *name = (char *) switch_xml_attr_soft(x_profile, "name");
+ char *odbc_dsn = NULL, *odbc_dsn_tmp = NULL, *odbc_user = NULL, *odbc_pass = NULL, *dbname = NULL;
+ char *terminator_key = "#";
+ char *play_new_messages_key = "1";
+ char *play_saved_messages_key = "2";
+ char *save_message_key = "8";
+ char *delete_message_key = "7";
+ char *replay_message_key = "1";
+
+ char *main_menu_key = "0";
+ char *config_menu_key = "5";
+ char *record_greeting_key = "1";
+ char *choose_greeting_key = "2";
+ char *record_name_key = "3";
+
+ char *record_file_key = "3";
+ char *listen_file_key = "1";
+ char *save_file_key = "2";
+ char *delete_file_key = "7";
+ char *undelete_file_key = "8";
+ char *tone_spec = "%(1000, 0, 640)";
+
+ switch_core_db_t *db;
+ uint32_t timeout = 10000, max_login_attempts = 3, max_record_len = 300;
+
+ db = NULL;
+ for (param = switch_xml_child(x_profile, "param"); param; param = param->next) {
+ char *var, *val;
+
+ var = (char *) switch_xml_attr_soft(param, "name");
+ val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "terminator-key") && !switch_strlen_zero(val)) {
+ terminator_key = val;
+ } else if (!strcasecmp(var, "play-new-messages-key") && !switch_strlen_zero(val)) {
+ play_new_messages_key = val;
+ } else if (!strcasecmp(var, "play-saved-messages-key") && !switch_strlen_zero(val)) {
+ play_saved_messages_key = val;
+ } else if (!strcasecmp(var, "save-message-key") && !switch_strlen_zero(val)) {
+ save_message_key = val;
+ } else if (!strcasecmp(var, "delete-message-key") && !switch_strlen_zero(val)) {
+ delete_message_key = val;
+ } else if (!strcasecmp(var, "replay-message-key") && !switch_strlen_zero(val)) {
+ replay_message_key = val;
+ } else if (!strcasecmp(var, "main-menu-key") && !switch_strlen_zero(val)) {
+ main_menu_key = val;
+ } else if (!strcasecmp(var, "config-menu-key") && !switch_strlen_zero(val)) {
+ config_menu_key = val;
+ } else if (!strcasecmp(var, "record-greeting-key") && !switch_strlen_zero(val)) {
+ record_greeting_key = val;
+ } else if (!strcasecmp(var, "choose-greeting-key") && !switch_strlen_zero(val)) {
+ choose_greeting_key = val;
+ } else if (!strcasecmp(var, "record-name-key") && !switch_strlen_zero(val)) {
+ record_name_key = val;
+ } else if (!strcasecmp(var, "listen-file-key") && !switch_strlen_zero(val)) {
+ listen_file_key = val;
+ } else if (!strcasecmp(var, "save-file-key") && !switch_strlen_zero(val)) {
+ save_file_key = val;
+ } else if (!strcasecmp(var, "delete-file-key") && !switch_strlen_zero(val)) {
+ delete_file_key = val;
+ } else if (!strcasecmp(var, "undelete-file-key") && !switch_strlen_zero(val)) {
+ undelete_file_key = val;
+ } else if (!strcasecmp(var, "tone-spec")) {
+ tone_spec = val;
+ } else if (!strcasecmp(var, "digit-timeout")) {
+ int tmp = 0;
+ if (!switch_strlen_zero(val)) {
+ tmp = atoi(val);
+ }
+ if (tmp >= 1000 && tmp <= 30000) {
+ timeout = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid timeout value [%s] must be between 1000 and 30000 ms\n", val);
+ }
+ } else if (!strcasecmp(var, "max-login-attempts")) {
+ int tmp = 0;
+ if (!switch_strlen_zero(val)) {
+ tmp = atoi(val);
+ }
+ if (tmp > 0 && tmp < 11) {
+ max_login_attempts = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid attempts [%s] must be between 1 and 10 ms\n", val);
+ }
+ } else if (!strcasecmp(var, "max-record-len")) {
+ int tmp = 0;
+ if (!switch_strlen_zero(val)) {
+ tmp = atoi(val);
+ }
+ if (tmp > 0 && tmp < 10000) {
+ max_record_len = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid attempts [%s] must be between 1 and 10000s\n", val);
+ }
+ } else if (!strcasecmp(var, "odbc-dsn")) {
+#ifdef SWITCH_HAVE_ODBC
+ odbc_dsn_tmp = val;
+ odbc_dsn = strdup(val);
+
+ if ((odbc_user = strchr(odbc_dsn, ':'))) {
+ *odbc_user++ = '\0';
+ }
+
+ if ((odbc_pass = strchr(odbc_user, ':'))) {
+ *odbc_pass++ = '\0';
+ }
+#else
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
+#endif
+ }
+ }
+
+ if (switch_strlen_zero(name)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No name specified.\n");
+ } else {
+ profile = switch_core_alloc(globals.pool, sizeof(*profile));
+ profile->name = switch_core_strdup(globals.pool, name);
+
+ if (!switch_strlen_zero(odbc_dsn) && !switch_strlen_zero(odbc_user) && !switch_strlen_zero(odbc_pass)) {
+ profile->odbc_dsn = switch_core_strdup(globals.pool, odbc_dsn_tmp);
+ profile->odbc_user = switch_core_strdup(globals.pool, odbc_user);
+ profile->odbc_pass = switch_core_strdup(globals.pool, odbc_pass);
+ } else {
+ profile->dbname = switch_core_sprintf(globals.pool, "voicemail_%s", name);
+ }
+#ifdef SWITCH_HAVE_ODBC
+ if (profile->odbc_dsn) {
+ if (!(profile->master_odbc = switch_odbc_handle_new(profile->odbc_dsn, profile->odbc_user, profile->odbc_pass))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
+ continue;
+
+ }
+ if (switch_odbc_handle_connect(profile->master_odbc) != SWITCH_ODBC_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
+ continue;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected ODBC DSN: %s\n", profile->odbc_dsn);
+ switch_odbc_handle_exec(profile->master_odbc, vm_sql, NULL);
+ switch_odbc_handle_exec(profile->master_odbc, vm_pref_sql, NULL);
+ } else {
+#endif
+ if ((db = switch_core_db_open_file(profile->dbname))) {
+ switch_core_db_test_reactive(db, "select * from voicemail_data", vm_sql);
+ switch_core_db_test_reactive(db, "select * from voicemail_prefs", vm_pref_sql);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n");
+ continue;
+ }
+ switch_core_db_close(db);
+#ifdef SWITCH_HAVE_ODBC
+ }
+#endif
+ profile->digit_timeout = timeout;
+ profile->max_login_attempts = max_login_attempts;
+ profile->max_record_len = max_record_len;
+ *profile->terminator_key = *terminator_key;
+ *profile->play_new_messages_key = *play_new_messages_key;
+ *profile->play_saved_messages_key = *play_saved_messages_key;
+ *profile->save_message_key = *save_message_key;
+ *profile->delete_message_key = *delete_message_key;
+ *profile->replay_message_key = *replay_message_key;
+ *profile->main_menu_key = *main_menu_key;
+ *profile->config_menu_key = *config_menu_key;
+ *profile->record_greeting_key = *record_greeting_key;
+ *profile->choose_greeting_key = *choose_greeting_key;
+ *profile->record_name_key = *record_name_key;
+ *profile->record_file_key = *record_file_key;
+ *profile->listen_file_key = *listen_file_key;
+ *profile->save_file_key = *save_file_key;
+ *profile->delete_file_key = *delete_file_key;
+ *profile->undelete_file_key = *undelete_file_key;
+ profile->tone_spec = switch_core_strdup(globals.pool, tone_spec);
+
+ switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, globals.pool);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added Profile %s\n", profile->name);
+ switch_core_hash_insert(globals.profile_hash, profile->name, profile);
+
+ }
+
+
+
+ switch_safe_free(odbc_dsn);
+ switch_safe_free(dbname);
+
+ }
+
+ end:
+
+ switch_xml_free(xml);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t cancel_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
+{
+
+
+ switch (itype) {
+ case SWITCH_INPUT_TYPE_DTMF:
+ {
+ char *dtmf = (char *) input;
+ if (buf && buflen) {
+ switch_copy_string(buf, dtmf, buflen);
+ }
+ return SWITCH_STATUS_BREAK;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t control_playback(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
+{
+
+
+ switch (itype) {
+ case SWITCH_INPUT_TYPE_DTMF:
+ {
+ char *dtmf = (char *) input;
+ switch_file_handle_t *fh = (switch_file_handle_t *) buf;
+ uint32_t pos = 0;
+
+ switch(*dtmf) {
+ case '0':
+ {
+ if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
+ switch_clear_flag(fh, SWITCH_FILE_PAUSE);
+ } else {
+ switch_set_flag(fh, SWITCH_FILE_PAUSE);
+ }
+ return SWITCH_STATUS_SUCCESS;
+ }
+ break;
+ case '1':
+ {
+ unsigned int pos = 0;
+ fh->speed = 0;
+ switch_core_file_seek(fh, &pos, 0, SEEK_SET);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ break;
+ case '6':
+ {
+ int samps = 24000;
+ switch_core_file_seek(fh, &pos, samps, SEEK_CUR);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ break;
+ case '4':
+ {
+ int samps = 24000;
+ switch_core_file_seek(fh, &pos, fh->pos - samps, SEEK_SET);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ break;
+ case '#':
+ return SWITCH_STATUS_BREAK;
+
+ default:
+ return SWITCH_STATUS_SUCCESS;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+struct prefs_callback {
+ char name_path[255];
+ char greeting_path[255];
+};
+typedef struct prefs_callback prefs_callback_t;
+
+static int prefs_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ prefs_callback_t *cbt = (prefs_callback_t *) pArg;
+
+ switch_copy_string(cbt->name_path, argv[2], sizeof(cbt->name_path));
+ switch_copy_string(cbt->greeting_path, argv[3], sizeof(cbt->greeting_path));
+
+ return 0;
+}
+
+
+typedef enum {
+ VM_CHECK_START,
+ VM_CHECK_AUTH,
+ VM_CHECK_MENU,
+ VM_CHECK_CONFIG,
+ VM_CHECK_PLAY_MESSAGES,
+ VM_CHECK_FOLDER_SUMMARY,
+ VM_CHECK_LISTEN
+} vm_check_state_t;
+
+
+#define VM_ACK_MACRO "voicemail_ack"
+#define VM_SAY_DATE_MACRO "voicemail_say_date"
+#define VM_PLAY_GREETING_MACRO "voicemail_play_greeting"
+#define VM_SAY_MESSAGE_NUMBER_MACRO "voicemail_say_message_number"
+#define VM_SAY_NUMBER_MACRO "voicemail_say_number"
+#define VM_SAY_PHONE_NUMBER_MACRO "voicemail_say_phone_number"
+#define VM_SAY_NAME_MACRO "voicemail_say_name"
+
+#define VM_RECORD_MESSAGE_MACRO "voicemail_record_message"
+#define VM_CHOOSE_GREETING_MACRO "voicemail_choose_greeting"
+#define VM_CHOOSE_GREETING_FAIL_MACRO "voicemail_choose_greeting_fail"
+#define VM_CHOOSE_GREETING_SELECTED_MACRO "voicemail_greeting_selected"
+#define VM_RECORD_GREETING_MACRO "voicemail_record_greeting"
+#define VM_RECORD_NAME_MACRO "voicemail_record_name"
+#define VM_LISTEN_FILE_CHECK_MACRO "voicemail_listen_file_check"
+#define VM_RECORD_FILE_CHECK_MACRO "voicemail_record_file_check"
+#define VM_MENU_MACRO "voicemail_menu"
+#define VM_CONFIG_MENU_MACRO "voicemail_config_menu"
+#define VM_ENTER_ID_MACRO "voicemail_enter_id"
+#define VM_ENTER_PASS_MACRO "voicemail_enter_pass"
+#define VM_FAIL_AUTH_MACRO "voicemail_fail_auth"
+#define VM_ABORT_MACRO "voicemail_abort"
+#define VM_HELLO_MACRO "voicemail_hello"
+#define VM_GOODBYE_MACRO "voicemail_goodbye"
+#define VM_NEW_MESSAGE_COUNT_MACRO "voicemail_new_message_count"
+#define VM_SAVED_MESSAGE_COUNT_MACRO "voicemail_saved_message_count"
+
+
+static switch_status_t vm_macro_get(switch_core_session_t *session,
+ char *macro,
+ char *macro_arg,
+ char *buf,
+ switch_size_t buflen,
+ switch_size_t maxlen,
+ char *term_chars,
+ char *terminator_key,
+ uint32_t timeout)
+{
+ switch_input_args_t args = { 0 }, *ap = NULL;
+ switch_channel_t *channel;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_size_t bslen;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ if (buf && buflen) {
+ *buf = '\0';
+ args.input_callback = cancel_on_dtmf;
+ args.buf = buf;
+ args.buflen = sizeof(buf);
+ ap = &args;
+ }
+
+ status = switch_ivr_phrase_macro(session, macro, macro_arg, NULL, ap);
+
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ if (buf) {
+ memset(buf, 0, buflen);
+ }
+ return status;
+ }
+
+ if (!buf) {
+ return status;
+ }
+
+ bslen = strlen(buf);
+
+ if (maxlen == 0 || maxlen > buflen - 1) {
+ maxlen = buflen -1;
+ }
+ if (bslen < maxlen) {
+ status = switch_ivr_collect_digits_count(session, buf + bslen, buflen, maxlen - bslen, term_chars, terminator_key, timeout);
+ }
+
+ return status;
+}
+
+struct callback {
+ char *buf;
+ size_t len;
+ int matches;
+};
+typedef struct callback callback_t;
+
+static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ callback_t *cbt = (callback_t *) pArg;
+
+ switch_copy_string(cbt->buf, argv[0], cbt->len);
+ cbt->matches++;
+ return 0;
+}
+
+
+static int unlink_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ if (argv[0]) {
+ unlink(argv[0]);
+ }
+ return 0;
+}
+
+
+typedef enum {
+ MSG_NONE,
+ MSG_NEW,
+ MSG_SAVED
+} msg_type_t;
+
+static uint32_t DEFAULT_DIR_PERMS = SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE | SWITCH_FPROT_UEXECUTE | SWITCH_FPROT_GREAD | SWITCH_FPROT_GEXECUTE;
+
+
+static switch_status_t create_file(switch_core_session_t *session, vm_profile_t *profile, char *macro_name, char *file_path)
+{
+ switch_channel_t *channel;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_file_handle_t fh = { 0 };
+ switch_input_args_t args = { 0 };
+ char term;
+ char input[10] = "" , key_buf[80] = "";
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+
+ while(switch_channel_ready(channel)) {
+
+
+ switch_channel_set_variable(channel, "RECORD_COMMENT", macro_name);
+
+
+
+
+
+ snprintf(key_buf, sizeof(key_buf), "%s:%s:%s",
+ profile->listen_file_key,
+ profile->save_file_key,
+ profile->record_file_key);
+
+
+ record_file:
+ args.input_callback = cancel_on_dtmf;
+ TRY_CODE(switch_ivr_phrase_macro(session, macro_name, NULL, NULL, NULL));
+ TRY_CODE(switch_ivr_gentones(session, profile->tone_spec, 0, NULL));
+
+ memset(&fh, 0, sizeof(fh));
+ fh.thresh = 200;
+ fh.silence_hits = 2;
+
+
+ switch_ivr_record_file(session, &fh, file_path, &args, profile->max_record_len);
+ status = SWITCH_STATUS_SUCCESS;
+
+ play_file:
+ memset(&fh, 0, sizeof(fh));
+ args.input_callback = control_playback;
+ args.buf = &fh;
+ switch_ivr_play_file(session, &fh, file_path, &args);
+
+
+ while(switch_channel_ready(channel)) {
+ status = vm_macro_get(session, VM_RECORD_FILE_CHECK_MACRO,
+ key_buf, input, sizeof(input), 1, profile->terminator_key, &term, profile->digit_timeout);
+
+ if (!strcmp(input, profile->listen_file_key)) {
+ goto play_file;
+ } else if (!strcmp(input, profile->record_file_key)) {
+ goto record_file;
+ } else {
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_ACK_MACRO, "saved", NULL, NULL));
+ goto end;
+ }
+ }
+ }
+
+ end:
+
+ return status;
+}
+
+
+struct listen_callback {
+ char created_epoch[255];
+ char read_epoch[255];
+ char user[255];
+ char domain[255];
+ char uuid[255];
+ char cid_name[255];
+ char cid_number[255];
+ char in_folder[255];
+ char file_path[255];
+ char flags[255];
+ int index;
+ int want;
+ msg_type_t type;
+};
+typedef struct listen_callback listen_callback_t;
+
+static int listen_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ listen_callback_t *cbt = (listen_callback_t *) pArg;
+
+ if (cbt->index++ != cbt->want) {
+ return 0;
+ }
+
+ switch_copy_string(cbt->created_epoch, argv[0], 255);
+ switch_copy_string(cbt->read_epoch, argv[1], 255);
+ switch_copy_string(cbt->user, argv[2], 255);
+ switch_copy_string(cbt->domain, argv[3], 255);
+ switch_copy_string(cbt->uuid, argv[4], 255);
+ switch_copy_string(cbt->cid_name, argv[5], 255);
+ switch_copy_string(cbt->cid_number, argv[6], 255);
+ switch_copy_string(cbt->in_folder, argv[7], 255);
+ switch_copy_string(cbt->file_path, argv[8], 255);
+ switch_copy_string(cbt->flags, argv[9], 255);
+
+
+ return -1;
+}
+
+
+static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t *profile, listen_callback_t *cbt)
+{
+ switch_channel_t *channel;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_input_args_t args = { 0 };
+ char term;
+ char input[10] = "" , key_buf[80] = "";
+ switch_file_handle_t fh = { 0 };
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+
+ if(switch_channel_ready(channel)) {
+
+ args.input_callback = cancel_on_dtmf;
+
+
+ snprintf(key_buf, sizeof(key_buf), "%s:%s:%s:%s",
+ profile->listen_file_key,
+ profile->save_file_key,
+ profile->delete_file_key,
+ profile->undelete_file_key);
+
+
+ snprintf(input, sizeof(input), "%s:%d", cbt->type == MSG_NEW ? "new" : "saved", cbt->index);
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_SAY_MESSAGE_NUMBER_MACRO, input, NULL, NULL));
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_SAY_DATE_MACRO, cbt->created_epoch, NULL, NULL));
+ play_file:
+
+ memset(&fh, 0, sizeof(fh));
+ args.input_callback = control_playback;
+ args.buf = &fh;
+ TRY_CODE(switch_ivr_play_file(session, NULL, cbt->file_path, &args));
+
+ if (switch_channel_ready(channel)) {
+ status = vm_macro_get(session, VM_LISTEN_FILE_CHECK_MACRO,
+ key_buf, input, sizeof(input), 1, profile->terminator_key, &term, profile->digit_timeout);
+
+ if (!strcmp(input, profile->listen_file_key)) {
+ goto play_file;
+ } else if (!strcmp(input, profile->delete_file_key)) {
+ char *sql = switch_mprintf("update voicemail_data set flags='delete' where uuid='%s'", cbt->uuid);
+ vm_execute_sql(profile, sql, profile->mutex);
+ switch_safe_free(sql);
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_ACK_MACRO, "deleted", NULL, NULL));
+ } else {
+ char *sql = switch_mprintf("update voicemail_data set flags='save' where uuid='%s'", cbt->uuid);
+ vm_execute_sql(profile, sql, profile->mutex);
+ switch_safe_free(sql);
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_ACK_MACRO, "saved", NULL, NULL));
+ }
+ }
+ }
+
+ end:
+
+ return status;
+}
+
+static void message_count(vm_profile_t *profile, char *myid, char *domain_name, char *myfolder, int *total_new_messages, int *total_saved_messages)
+{
+ char msg_count[80] = "";
+ callback_t cbt = { 0 };
+ char sql[128];
+
+ cbt.buf = msg_count;
+ cbt.len = sizeof(msg_count);
+
+
+ snprintf(sql, sizeof(sql),
+ "select count(*) from voicemail_data where user='%s' and domain='%s' and in_folder='%s' and read_epoch=0",
+ myid,
+ domain_name,
+ myfolder);
+ vm_execute_sql_callback(profile, profile->mutex, sql, sql2str_callback, &cbt);
+ *total_new_messages = atoi(msg_count);
+
+ snprintf(sql, sizeof(sql),
+ "select count(*) from voicemail_data where user='%s' and domain='%s' and in_folder='%s' and read_epoch!=0",
+ myid,
+ domain_name,
+ myfolder);
+ vm_execute_sql_callback(profile, profile->mutex, sql, sql2str_callback, &cbt);
+ *total_saved_messages = atoi(msg_count);
+}
+
+
+static void voicemail_check_main(switch_core_session_t *session, char *profile_name, char *domain_name, char *id, int auth)
+{
+ vm_check_state_t vm_check_state = VM_CHECK_START;
+ switch_channel_t *channel;
+ vm_profile_t *profile;
+ switch_xml_t x_domain, x_domain_root, x_user, x_params, x_param;
+ switch_status_t status;
+ char pass_buf[80] = "", *mypass = NULL, id_buf[80] = "", *myid = id, *myfolder = NULL;
+ const char *thepass = NULL;
+ char term = 0;
+ uint32_t timeout, attempts = 0;
+ int failed = 0;
+ msg_type_t play_msg_type = MSG_NONE;
+ char *dir_path = NULL, *file_path = NULL;
+ int total_new_messages = 0;
+ int total_saved_messages = 0;
+ int heard_auto_saved = 0, heard_auto_new = 0;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+
+ if (!(profile = switch_core_hash_find(globals.profile_hash, profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error invalid profile %s", profile_name);
+ return;
+ }
+
+ x_user = x_domain = x_domain_root = NULL;
+
+ timeout = profile->digit_timeout;
+ attempts = profile->max_login_attempts;
+
+ status = switch_ivr_phrase_macro(session, VM_HELLO_MACRO, NULL, NULL, NULL);
+
+ while(switch_channel_ready(channel)) {
+
+ switch_ivr_sleep(session, 100);
+
+ switch(vm_check_state) {
+ case VM_CHECK_START:
+ {
+ total_new_messages = 0;
+ total_saved_messages = 0;
+ heard_auto_saved = 0;
+ heard_auto_new = 0;
+ play_msg_type = MSG_NONE;
+ attempts = profile->max_login_attempts;
+ myid = id;
+ mypass = NULL;
+ myfolder = "inbox";
+ vm_check_state = VM_CHECK_AUTH;
+ if (x_domain_root) {
+ switch_xml_free(x_domain_root);
+ }
+ x_user = x_domain = x_domain_root = NULL;
+ }
+ break;
+ case VM_CHECK_FOLDER_SUMMARY:
+ {
+ char msg_count[80] = "";
+ switch_channel_set_variable(channel, "voicemail_current_folder", myfolder);
+ message_count(profile, myid, domain_name, myfolder, &total_new_messages, &total_saved_messages);
+ snprintf(msg_count, sizeof(msg_count), "%d", total_new_messages);
+ if ((status = switch_ivr_phrase_macro(session, VM_NEW_MESSAGE_COUNT_MACRO, msg_count, NULL, NULL)) != SWITCH_STATUS_SUCCESS) {
+ goto end;
+ }
+
+ if (!heard_auto_new && total_new_messages > 0) {
+ heard_auto_new = 1;
+ play_msg_type = MSG_NEW;
+ vm_check_state = VM_CHECK_PLAY_MESSAGES;
+ continue;
+ }
+
+ snprintf(msg_count, sizeof(msg_count), "%d", total_saved_messages);
+ if ((status = switch_ivr_phrase_macro(session, VM_SAVED_MESSAGE_COUNT_MACRO, msg_count, NULL, NULL)) != SWITCH_STATUS_SUCCESS) {
+ goto end;
+ }
+
+ if (!heard_auto_saved && total_saved_messages > 0) {
+ heard_auto_saved = 1;
+ play_msg_type = MSG_SAVED;
+ vm_check_state = VM_CHECK_PLAY_MESSAGES;
+ continue;
+ }
+
+ vm_check_state = VM_CHECK_MENU;
+ }
+ break;
+ case VM_CHECK_PLAY_MESSAGES:
+ {
+ listen_callback_t cbt;
+ char sql[128];
+ int cur_message, total_messages;
+ message_count(profile, myid, domain_name, myfolder, &total_new_messages, &total_saved_messages);
+ memset(&cbt, 0, sizeof(cbt));
+ switch(play_msg_type) {
+ case MSG_NEW:
+ {
+ snprintf(sql, sizeof(sql),
+ "select * from voicemail_data where user='%s' and domain='%s' and read_epoch=0", myid, domain_name);
+ total_messages = total_new_messages;
+ heard_auto_new = heard_auto_saved = 1;
+ }
+ break;
+ case MSG_SAVED:
+ default:
+ {
+ snprintf(sql, sizeof(sql),
+ "select * from voicemail_data where user='%s' and domain='%s' and read_epoch!=0", myid, domain_name);
+ total_messages = total_saved_messages;
+ heard_auto_new = heard_auto_saved = 1;
+ }
+ break;
+ }
+ for (cur_message = 0; cur_message < total_messages; cur_message++) {
+ cbt.index = 0;
+ cbt.want = cur_message;
+ cbt.type = play_msg_type;
+ vm_execute_sql_callback(profile, profile->mutex, sql, listen_callback, &cbt);
+ status = listen_file(session, profile, &cbt);
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ break;
+ }
+ }
+ snprintf(sql, sizeof(sql), "update voicemail_data set read_epoch=%ld where user='%s' and domain='%s' and flags='save'",
+ (long)time(NULL), myid, domain_name);
+ vm_execute_sql(profile, sql, profile->mutex);
+ snprintf(sql, sizeof(sql), "select file_path from voicemail_data where user='%s' and domain='%s' and flags='delete'", myid, domain_name);
+ vm_execute_sql_callback(profile, profile->mutex, sql, unlink_callback, NULL);
+ snprintf(sql, sizeof(sql), "delete from voicemail_data where user='%s' and domain='%s' and flags='delete'", myid, domain_name);
+ vm_execute_sql(profile, sql, profile->mutex);
+ vm_check_state = VM_CHECK_FOLDER_SUMMARY;
+ }
+ break;
+ case VM_CHECK_CONFIG:
+ {
+ char *sql = NULL;
+ char input[10] = "";
+ char key_buf[80] = "";
+ callback_t cbt = { 0 };
+ char msg_count[80] = "";
+ cbt.buf = msg_count;
+ cbt.len = sizeof(msg_count);
+ sql = switch_mprintf("select count(*) from voicemail_prefs where user='%q' and domain = '%q'", myid, domain_name);
+ vm_execute_sql_callback(profile, profile->mutex, sql, sql2str_callback, &cbt);
+ switch_safe_free(sql);
+ if (switch_strlen_zero(msg_count) || !atoi(msg_count)) {
+ sql = switch_mprintf("insert into voicemail_prefs values('%q','%q','','')", myid, domain_name);
+ vm_execute_sql(profile, sql, profile->mutex);
+ switch_safe_free(sql);
+ }
+
+ snprintf(key_buf, sizeof(key_buf), "%s:%s:%s:%s",
+ profile->record_greeting_key,
+ profile->choose_greeting_key,
+ profile->record_name_key,
+ profile->main_menu_key);
+
+
+ TRY_CODE(vm_macro_get(session, VM_CONFIG_MENU_MACRO, key_buf, input, sizeof(input), 1,
+ profile->terminator_key, &term, timeout));
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ goto end;
+ }
+
+ if (!strcmp(input, profile->main_menu_key)) {
+ vm_check_state = VM_CHECK_MENU;
+ } else if (!strcmp(input, profile->choose_greeting_key)) {
+ int num;
+ switch_input_args_t args = { 0 };
+ args.input_callback = cancel_on_dtmf;
+
+ TRY_CODE(vm_macro_get(session, VM_CHOOSE_GREETING_MACRO, key_buf, input, sizeof(input), 1,
+ profile->terminator_key, &term, timeout));
+
+ num = atoi(input);
+ file_path = switch_mprintf("%s%sgreeting_%d.wav", dir_path, SWITCH_PATH_SEPARATOR, num);
+ if (num < 1 || num > 3) {
+ status = SWITCH_STATUS_FALSE;
+ } else {
+ switch_file_handle_t fh = { 0 };
+ memset(&fh, 0, sizeof(fh));
+ args.input_callback = control_playback;
+ args.buf = &fh;
+ status = switch_ivr_play_file(session, NULL, file_path, &args);
+ }
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_CHOOSE_GREETING_FAIL_MACRO, NULL, NULL, NULL));
+ } else {
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_CHOOSE_GREETING_SELECTED_MACRO, input, NULL, NULL));
+ sql = switch_mprintf("update voicemail_prefs set greeting_path='%s' where user='%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);
+ } else if (!strcmp(input, profile->record_greeting_key)) {
+ int num;
+ TRY_CODE(vm_macro_get(session, VM_CHOOSE_GREETING_MACRO, key_buf, input, sizeof(input), 1,
+ profile->terminator_key, &term, timeout));
+
+ num = atoi(input);
+ if (num < 1 || num > 3) {
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_CHOOSE_GREETING_FAIL_MACRO, NULL, NULL, NULL));
+ } else {
+ file_path = switch_mprintf("%s%sgreeting_%d.wav", dir_path, SWITCH_PATH_SEPARATOR, num);
+ TRY_CODE(create_file(session, profile, VM_RECORD_GREETING_MACRO, file_path));
+ sql = switch_mprintf("update voicemail_prefs set greeting_path='%s' where user='%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);
+ }
+
+ } else if (!strcmp(input, profile->record_name_key)) {
+ file_path = switch_mprintf("%s%srecorded_name.wav", dir_path, SWITCH_PATH_SEPARATOR);
+ TRY_CODE(create_file(session, profile, VM_RECORD_NAME_MACRO, file_path));
+ sql = switch_mprintf("update voicemail_prefs set name_path='%s' where user='%s' and domain='%s'", file_path, myid, domain_name);
+ vm_execute_sql(profile, sql, profile->mutex);
+ switch_safe_free(file_path);
+ switch_safe_free(sql);
+ }
+
+ continue;
+ }
+ break;
+ case VM_CHECK_MENU:
+ {
+ char input[10] = "";
+ char key_buf[80] = "";
+ play_msg_type = MSG_NONE;
+
+ snprintf(key_buf, sizeof(key_buf), "%s:%s:%s",
+ profile->play_new_messages_key,
+ profile->play_saved_messages_key,
+ profile->config_menu_key);
+
+ status = vm_macro_get(session, VM_MENU_MACRO, key_buf, input, sizeof(input), 1,
+ profile->terminator_key, &term, timeout);
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ goto end;
+ }
+
+ if (!strcmp(input, profile->play_new_messages_key)) {
+ play_msg_type = MSG_NEW;
+ } else if (!strcmp(input, profile->play_saved_messages_key)) {
+ play_msg_type = MSG_SAVED;
+ } else if (!strcmp(input, profile->config_menu_key)) {
+ vm_check_state = VM_CHECK_CONFIG;
+ }
+
+ if (play_msg_type) {
+ vm_check_state = VM_CHECK_PLAY_MESSAGES;
+ }
+
+
+ continue;
+ }
+ break;
+ case VM_CHECK_AUTH:
+ {
+ if (!attempts) {
+ failed = 1;
+ goto end;
+ }
+
+ attempts--;
+
+ if (!myid) {
+ status = vm_macro_get(session, VM_ENTER_ID_MACRO, profile->terminator_key, id_buf, sizeof(id_buf), 0,
+ profile->terminator_key, &term, timeout);
+ if (status != SWITCH_STATUS_SUCCESS) {
+ goto end;
+ }
+
+ if (switch_strlen_zero(id_buf)) {
+ continue;
+ } else {
+ myid = id_buf;
+ }
+ }
+
+ if (!x_user) {
+ int ok = 1;
+ char *xtra = switch_mprintf("mailbox=%s", myid);
+
+ assert(xtra);
+
+ if (switch_xml_locate_user(myid, domain_name, switch_channel_get_variable(channel, "network_addr"),
+ &x_domain_root, &x_domain, &x_user, xtra) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", myid, domain_name);
+ ok = 0;
+ }
+
+ switch_safe_free(xtra);
+
+ if (!ok) {
+ goto failed;
+ }
+ }
+
+ if (!mypass) {
+ if (auth) {
+ mypass = "OK";
+ } else {
+ status = vm_macro_get(session, VM_ENTER_PASS_MACRO, profile->terminator_key,
+ pass_buf, sizeof(pass_buf), 0, profile->terminator_key, &term, timeout);
+ if (status != SWITCH_STATUS_SUCCESS) {
+ goto end;
+ }
+ if (switch_strlen_zero(pass_buf)) {
+ continue;
+ } else {
+ mypass = pass_buf;
+ }
+ }
+ }
+
+ if (!(x_params = switch_xml_child(x_user, "params"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find params for user [%s@%s]\n", myid, domain_name);
+ goto failed;
+ }
+
+ thepass = NULL;
+ for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
+ const char *var = switch_xml_attr_soft(x_param, "name");
+ const char *val = switch_xml_attr_soft(x_param, "value");
+
+ if (!strcasecmp(var, "password")) {
+ thepass = val;
+ } else if (!strcasecmp(var, "vm-password")) {
+ thepass = val;
+ }
+ }
+ switch_xml_free(x_domain_root);
+ x_domain_root = NULL;
+
+ if (auth || !thepass || (thepass && mypass && !strcmp(thepass, mypass))) {
+ if (!dir_path) {
+ dir_path = switch_core_session_sprintf(session, "%s%svoicemail%s%s%s%s%s%s", SWITCH_GLOBAL_dirs.storage_dir,
+ SWITCH_PATH_SEPARATOR,
+ SWITCH_PATH_SEPARATOR,
+ profile->name,
+ SWITCH_PATH_SEPARATOR,
+ domain_name,
+ SWITCH_PATH_SEPARATOR,
+ myid);
+
+
+ if (switch_dir_make_recursive(dir_path, DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s", dir_path);
+ return;
+ }
+ }
+
+
+ vm_check_state = VM_CHECK_FOLDER_SUMMARY;
+ //vm_check_state = VM_CHECK_MENU;
+ } else {
+ goto failed;
+ }
+
+ continue;
+ failed:
+ status = switch_ivr_phrase_macro(session, VM_FAIL_AUTH_MACRO, NULL, NULL, NULL);
+ myid = id;
+ mypass = NULL;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ end:
+
+ if (switch_channel_ready(channel)) {
+ if (failed) {
+ status = switch_ivr_phrase_macro(session, VM_ABORT_MACRO, NULL, NULL, NULL);
+ }
+ status = switch_ivr_phrase_macro(session, VM_GOODBYE_MACRO, NULL, NULL, NULL);
+ }
+
+ if (x_domain_root) {
+ switch_xml_free(x_domain_root);
+ }
+
+}
+
+
+static switch_status_t voicemail_leave_main(switch_core_session_t *session, char *profile_name, char *domain_name, char *id)
+{
+ switch_channel_t *channel;
+ char *myfolder = "inbox";
+ char sql[128];
+ prefs_callback_t cbt;
+ vm_profile_t *profile;
+ char *uuid = switch_core_session_get_uuid(session);
+ char *file_path = NULL;
+ char *dir_path = NULL;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_caller_profile_t *caller_profile;
+ switch_file_handle_t fh = { 0 };
+ switch_input_args_t args = { 0 };
+ char *email_vm = NULL;
+
+ memset(&cbt, 0, sizeof(cbt));
+ if (!(profile = switch_core_hash_find(globals.profile_hash, profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error invalid profile %s", profile_name);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ caller_profile = switch_channel_get_caller_profile(channel);
+ dir_path = switch_core_session_sprintf(session, "%s%svoicemail%s%s%s%s%s%s", SWITCH_GLOBAL_dirs.storage_dir,
+ SWITCH_PATH_SEPARATOR,
+ SWITCH_PATH_SEPARATOR,
+ profile->name,
+ SWITCH_PATH_SEPARATOR,
+ domain_name,
+ SWITCH_PATH_SEPARATOR,
+ id);
+ if (switch_dir_make_recursive(dir_path, DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s", dir_path);
+ goto end;
+ }
+
+
+ if (id) {
+ int ok = 1;
+ char *xtra = switch_mprintf("mailbox=%s", id);
+ switch_xml_t x_domain, x_domain_root, x_user, x_params, x_param;
+
+ assert(xtra);
+ x_user = x_domain = x_domain_root = NULL;
+ if (switch_xml_locate_user(id, domain_name, switch_channel_get_variable(channel, "network_addr"),
+ &x_domain_root, &x_domain, &x_user, xtra) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", id, domain_name);
+ ok = 0;
+ }
+
+ if ((x_params = switch_xml_child(x_user, "params"))) {
+ for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
+ const char *var = switch_xml_attr_soft(x_param, "name");
+ const char *val = switch_xml_attr_soft(x_param, "value");
+
+ if (!strcasecmp(var, "vm-mailto")) {
+ email_vm = switch_core_session_strdup(session, val);
+ }
+ }
+ }
+
+ switch_safe_free(xtra);
+ switch_xml_free(x_domain_root);
+ if (!ok) {
+ goto end;
+ }
+ }
+
+ snprintf(sql, sizeof(sql),
+ "select * from voicemail_prefs where user='%s' and domain='%s'",
+ id,
+ domain_name);
+ vm_execute_sql_callback(profile, profile->mutex, sql, prefs_callback, &cbt);
+
+ file_path = switch_mprintf("%s%smsg_%s.wav", dir_path, SWITCH_PATH_SEPARATOR, uuid);
+
+ memset(&fh, 0, sizeof(fh));
+ args.input_callback = control_playback;
+ args.buf = &fh;
+
+ if (!switch_strlen_zero(cbt.greeting_path)) {
+ TRY_CODE(switch_ivr_play_file(session, NULL, cbt.greeting_path, NULL));
+ } else {
+ if (!switch_strlen_zero(cbt.name_path)) {
+ TRY_CODE(switch_ivr_play_file(session, NULL, cbt.name_path, NULL));
+ }
+ TRY_CODE(switch_ivr_phrase_macro(session, VM_PLAY_GREETING_MACRO, id, NULL, NULL));
+ }
+
+ if(switch_channel_ready(channel)) {
+ char *usql;
+ status = create_file(session, profile, VM_RECORD_MESSAGE_MACRO, file_path);
+ if (status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK) {
+ usql = switch_mprintf("insert into voicemail_data values(%ld,0,'%q','%q','%q','%q','%q','%q','%q','')", (long)time(NULL),
+ id, domain_name, uuid, caller_profile->caller_id_name, caller_profile->caller_id_number, myfolder, file_path);
+ vm_execute_sql(profile, usql, profile->mutex);
+ switch_safe_free(usql);
+ } else {
+ unlink(file_path);
+ goto end;
+ }
+
+ }
+
+ end:
+
+ if (!switch_strlen_zero(email_vm)) {
+
+ switch_event_t *event;
+ char *from = switch_core_session_sprintf(session, "FreeSWITCH mod_voicemail <%s@%s>", id, domain_name);
+ char *headers = switch_core_session_sprintf(session, "Subject: Voicemail from %s %s",
+ caller_profile->caller_id_name, caller_profile->caller_id_number);
+ char *body;
+
+
+ if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+ switch_channel_event_set_data(channel, event);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Message-Type", "voicemail");
+ switch_event_serialize(event, &body);
+ switch_event_fire(&event);
+ } else {
+ body = switch_mprintf("Voicemail from %s %s",
+ caller_profile->caller_id_name, caller_profile->caller_id_number);
+ }
+
+ //TBD add better formatting to the body
+ vm_email(email_vm, from, headers, body, file_path);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending message to %s", email_vm);
+ switch_safe_free(body);
+ }
+
+ switch_safe_free(file_path);
+
+ if (switch_channel_ready(channel)) {
+ status = switch_ivr_phrase_macro(session, VM_GOODBYE_MACRO, NULL, NULL, NULL);
+ }
+
+ return status;
+
+
+}
+
+
+#define VM_DESC "voicemail"
+#define VM_USAGE "[check|auth] <profile_name> <domain_name> [<id>]"
+
+SWITCH_STANDARD_APP(voicemail_function)
+{
+ int argc = 0;
+ char *argv[4] = { 0 };
+ char *mydata = NULL;
+ char *profile_name = NULL;
+ char *domain_name = NULL;
+ char *id = NULL;
+ char *auth_var = NULL;
+ int x = 0, check = 0, auth = 0;
+ switch_channel_t *channel;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ if (switch_dir_make_recursive(SWITCH_GLOBAL_dirs.storage_dir, DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s", SWITCH_GLOBAL_dirs.storage_dir);
+ return;
+ }
+
+ if (!switch_strlen_zero(data)) {
+ mydata = switch_core_session_strdup(session, data);
+ argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argv[x] && !strcasecmp(argv[x], "check")) {
+ check++;
+ x++;
+ }
+
+ if (argv[x] && !strcasecmp(argv[x], "auth")) {
+ auth++;
+ x++;
+ }
+
+ if (argv[x]) {
+ profile_name = argv[x++];
+ }
+
+ if (argv[x]) {
+ domain_name = argv[x++];
+ }
+
+ if (argv[x]) {
+ id = argv[x++];
+ }
+
+
+ if ((auth_var = switch_channel_get_variable(channel, "voicemail_authorized")) && switch_true(auth_var)) {
+ auth = 1;
+ }
+
+ if (switch_strlen_zero(profile_name)) {
+ profile_name = switch_channel_get_variable(channel, "voicemail_profile_name");
+ }
+
+ if (switch_strlen_zero(domain_name)) {
+ domain_name = switch_channel_get_variable(channel, "voicemail_domain_name");
+ }
+
+ if (switch_strlen_zero(id)) {
+ id = switch_channel_get_variable(channel, "voicemail_id");
+ }
+
+ if (switch_strlen_zero(profile_name) || switch_strlen_zero(domain_name)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Usage: %s\n", VM_USAGE);
+ return;
+ }
+
+ if (check) {
+ voicemail_check_main(session, profile_name, domain_name, id, auth);
+ } else {
+ voicemail_leave_main(session, profile_name, domain_name, id);
+ }
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load)
+{
+ switch_application_interface_t *app_interface;
+ switch_status_t status;
+
+ if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
+ /* 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, "voicemail", "Voicemail", VM_DESC, voicemail_function, VM_USAGE, SAF_NONE);
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_NOUNLOAD;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:nil
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */
Added: freeswitch/trunk/src/mod/applications/mod_voicemail/mod_voicemail.vcproj
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_voicemail/mod_voicemail.vcproj Thu Oct 11 23:28:59 2007
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mod_voicemail"
+ ProjectGUID="{C24FB505-05D7-4319-8485-7540B44C8603}"
+ RootNamespace="mod_voicemail"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""$(InputDir)..\..\..\include";"$(InputDir)include";"$(InputDir)..\..\..\..\libs\include""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\..\w32\vsnet\$(OutDir)"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/mod_voicemail.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""$(InputDir)..\..\..\include";"$(InputDir)include";"$(InputDir)..\..\..\..\libs\include""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\..\..\..\w32\vsnet\$(OutDir)"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)/mod_voicemail.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\mod_voicemail.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Modified: freeswitch/trunk/src/switch_apr.c
==============================================================================
--- freeswitch/trunk/src/switch_apr.c (original)
+++ freeswitch/trunk/src/switch_apr.c Thu Oct 11 23:28:59 2007
@@ -394,6 +394,51 @@
return status;
}
+/* #define SWITCH_FPROT_USETID 0x8000 /\**< Set user id *\/ */
+/* #define SWITCH_FPROT_UREAD 0x0400 /\**< Read by user *\/ */
+/* #define SWITCH_FPROT_UWRITE 0x0200 /\**< Write by user *\/ */
+/* #define SWITCH_FPROT_UEXECUTE 0x0100 /\**< Execute by user *\/ */
+
+/* #define SWITCH_FPROT_GSETID 0x4000 /\**< Set group id *\/ */
+/* #define SWITCH_FPROT_GREAD 0x0040 /\**< Read by group *\/ */
+/* #define SWITCH_FPROT_GWRITE 0x0020 /\**< Write by group *\/ */
+/* #define SWITCH_FPROT_GEXECUTE 0x0010 /\**< Execute by group *\/ */
+
+/* #define SWITCH_FPROT_WSTICKY 0x2000 /\**< Sticky bit *\/ */
+/* #define SWITCH_FPROT_WREAD 0x0004 /\**< Read by others *\/ */
+/* #define SWITCH_FPROT_WWRITE 0x0002 /\**< Write by others *\/ */
+/* #define SWITCH_FPROT_WEXECUTE 0x0001 /\**< Execute by others *\/ */
+
+/* #define SWITCH_FPROT_OS_DEFAULT 0x0FFF /\**< use OS's default permissions *\/ */
+
+
+/**
+ * Create a new directory on the file system.
+ * @param path the path for the directory to be created. (use / on all systems)
+ * @param perm Permissions for the new direcoty.
+ * @param pool the pool to use.
+ */
+SWITCH_DECLARE(switch_status_t) switch_dir_make(const char *path, switch_fileperms_t perm,
+ switch_memory_pool_t *pool)
+{
+ return apr_dir_make(path, perm, pool);
+}
+
+/** Creates a new directory on the file system, but behaves like
+ * 'mkdir -p'. Creates intermediate directories as required. No error
+ * will be reported if PATH already exists.
+ * @param path the path for the directory to be created. (use / on all systems)
+ * @param perm Permissions for the new direcoty.
+ * @param pool the pool to use.
+ */
+SWITCH_DECLARE(switch_status_t) switch_dir_make_recursive(const char *path,
+ switch_fileperms_t perm,
+ switch_memory_pool_t *pool)
+{
+ return apr_dir_make_recursive(path, perm, pool);
+}
+
+
struct switch_dir {
apr_dir_t *dir_handle;
apr_finfo_t finfo;
Modified: freeswitch/trunk/src/switch_core.c
==============================================================================
--- freeswitch/trunk/src/switch_core.c (original)
+++ freeswitch/trunk/src/switch_core.c Thu Oct 11 23:28:59 2007
@@ -295,6 +295,14 @@
#endif
}
+ if (!SWITCH_GLOBAL_dirs.storage_dir && (SWITCH_GLOBAL_dirs.storage_dir = (char *) malloc(BUFSIZE))) {
+#ifdef SWITCH_STORAGE_DIR
+ switch_snprintf(SWITCH_GLOBAL_dirs.storage_dir, BUFSIZE, "%s", SWITCH_STORAGE_DIR);
+#else
+ switch_snprintf(SWITCH_GLOBAL_dirs.storage_dir, BUFSIZE, "%s%sstorage", base_dir, SWITCH_PATH_SEPARATOR);
+#endif
+ }
+
if (!SWITCH_GLOBAL_dirs.db_dir && (SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_DB_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.db_dir, BUFSIZE, "%s", SWITCH_DB_DIR);
Modified: freeswitch/trunk/src/switch_core_file.c
==============================================================================
--- freeswitch/trunk/src/switch_core_file.c (original)
+++ freeswitch/trunk/src/switch_core_file.c Thu Oct 11 23:28:59 2007
@@ -55,7 +55,7 @@
}
if ((fh->file_interface = switch_loadable_module_get_file_interface(ext)) == 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid file format [%s]!\n", ext);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid file format [%s] for [%s]!\n", ext, file_path);
return SWITCH_STATUS_GENERR;
}
Modified: freeswitch/trunk/src/switch_xml.c
==============================================================================
--- freeswitch/trunk/src/switch_xml.c (original)
+++ freeswitch/trunk/src/switch_xml.c Thu Oct 11 23:28:59 2007
@@ -1241,7 +1241,8 @@
}
-SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(char *user_name, char *domain_name,
+SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(char *user_name,
+ char *domain_name,
char *ip,
switch_xml_t *root,
switch_xml_t *domain,
@@ -1272,7 +1273,8 @@
}
if (user_name) {
- if (!(*user = switch_xml_find_child(*domain, "user", "id", user_name))) {
+ if (!(*user = switch_xml_find_child(*domain, "user", "id", user_name)) && strstr(xtra_params, "mailbox") &&
+ !(*user = switch_xml_find_child(*domain, "user", "mailbox", user_name))) {
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
More information about the Freeswitch-svn
mailing list