* Added MySQL audio and template storage option for voicemail

application.
* Simplified conference application by removing caching of audio
  from MySQL to file system.


git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@343 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Juha Heinanen 19 years ago
parent 5695a3a1f1
commit 3123aba1bf

@ -43,8 +43,8 @@
#define DEFAULT_AUDIO_TABLE "default_audio"
#define DOMAIN_AUDIO_TABLE "domain_audio"
#define LONELY_USER_MSG "first_participant_msg"
#define JOIN_SOUND "join_sound"
#define DROP_SOUND "drop_sound"
#define JOIN_SOUND "join_snd"
#define DROP_SOUND "drop_snd"
#endif
#define APP_NAME "conference"
@ -67,79 +67,68 @@ PlayoutType ConferenceFactory::m_PlayoutType = ADAPTIVE_PLAYOUT;
mysqlpp::Connection ConferenceFactory::Connection(mysqlpp::use_exceptions);
#endif
int cache_audio_file(string message, string domain, string language,
int get_audio_file(string message, string domain, string language,
string *audio_file)
{
string query_string;
if (language.empty()) {
if (domain.empty()) {
*audio_file = string("/tmp/") + APP_NAME + "_" + message + ".wav";
query_string = "select audio from " + string(DEFAULT_AUDIO_TABLE) + " where application='" + APP_NAME + "' and message='" + message + "' and language is null";
} else {
*audio_file = "/tmp/" + domain + "_" + APP_NAME + "_" +
message + ".wav";
query_string = "select audio from " + string(DOMAIN_AUDIO_TABLE) + " where application='" + APP_NAME + "' and message='" + message + "' and domain='" + domain + "' and language is null";
}
} else {
if (domain.empty()) {
*audio_file = string("/tmp/") + APP_NAME + "_" + message + "_" +
language + ".wav";
query_string = "select audio from " + string(DEFAULT_AUDIO_TABLE) + " where application='" + APP_NAME + "' and message='" + message + "' and language='" + language + "'";
} else {
*audio_file = "/tmp/" + domain + "_" + APP_NAME + "_" +
message + "_" + language + ".wav";
query_string = "select audio from " + string(DOMAIN_AUDIO_TABLE) + " where application='" + APP_NAME + "' and message='" + message + "' and domain='" + domain + "' and language='" + language + "'";
}
}
if (file_exists(*audio_file)) {
return 1;
} else {
try {
try {
mysqlpp::Query query = ConferenceFactory::Connection.query();
mysqlpp::Query query = ConferenceFactory::Connection.query();
string query_string, table;
if (domain.empty()) {
table = DEFAULT_AUDIO_TABLE;
} else {
table = DOMAIN_AUDIO_TABLE;
}
if (language.empty()) {
query_string = "select audio from " + table + " where application='conference' and message='" + message + "' and language is null";
} else {
query_string = "select audio from " + table + " where application='conference' and message='" + message + "' and language='" + language + "'";
}
DBG("Query string <%s>\n", query_string.c_str());
DBG("Query string <%s>\n", query_string.c_str());
query << query_string;
mysqlpp::Result res = query.store();
query << query_string;
mysqlpp::Result res = query.store();
mysqlpp::Row row;
mysqlpp::Row row;
if (res) {
if ((res.num_rows() > 0) && (row = res.at(0))) {
FILE *file;
unsigned long length = row.raw_string(0).size();
file = fopen((*audio_file).c_str(), "wb");
fwrite(row.at(0).data(), 1, length, file);
fclose(file);
return 1;
} else {
*audio_file = "";
return 1;
}
if (res) {
if ((res.num_rows() > 0) && (row = res.at(0))) {
FILE *file;
unsigned long length = row.raw_string(0).size();
file = fopen((*audio_file).c_str(), "wb");
fwrite(row.at(0).data(), 1, length, file);
fclose(file);
return 1;
} else {
ERROR("Database query error\n");
return 0;
*audio_file = "";
return 1;
}
}
catch (const mysqlpp::Exception& er) {
// Catch-all for any MySQL++ exceptions
ERROR("MySQL++ error: %s\n", er.what());
} else {
ERROR("Database query error\n");
*audio_file = "";
return 0;
}
}
catch (const mysqlpp::Exception& er) {
// Catch-all for any MySQL++ exceptions
ERROR("MySQL++ error: %s\n", er.what());
*audio_file = "";
return 0;
}
}
int ConferenceFactory::onLoad()
@ -195,7 +184,7 @@ int ConferenceFactory::onLoad()
return -1;
}
if (!cache_audio_file(LONELY_USER_MSG, "", "", &LonelyUserFile)) {
if (!get_audio_file(LONELY_USER_MSG, "", "", &LonelyUserFile)) {
return -1;
}
@ -205,11 +194,11 @@ int ConferenceFactory::onLoad()
return -1;
}
if (!cache_audio_file(JOIN_SOUND, "", "", &JoinSound)) {
if (!get_audio_file(JOIN_SOUND, "", "", &JoinSound)) {
return -1;
}
if (!cache_audio_file(DROP_SOUND, "", "", &DropSound)) {
if (!get_audio_file(DROP_SOUND, "", "", &DropSound)) {
return -1;
}
@ -350,13 +339,13 @@ void ConferenceDialog::onSessionStart(const AmSipRequest& req)
#ifdef USE_MYSQL
/* Get domain/language specific lonely user file from MySQL */
if (cache_audio_file(LONELY_USER_MSG, req.domain, language,
&lonely_user_file) &&
if (get_audio_file(LONELY_USER_MSG, req.domain, language,
&lonely_user_file) &&
!lonely_user_file.empty()) {
ConferenceFactory::LonelyUserFile = lonely_user_file;
} else {
if (cache_audio_file(LONELY_USER_MSG, "", language,
&lonely_user_file) &&
if (get_audio_file(LONELY_USER_MSG, "", language,
&lonely_user_file) &&
!lonely_user_file.empty()) {
ConferenceFactory::LonelyUserFile = lonely_user_file;
}

@ -3,7 +3,7 @@ plug_in_name = conference
module_ldflags =
module_cflags =
# Uncomment following lines if you want to keep audio in MySQL database.
# Uncomment last two lines if you want to keep audio in MySQL database.
# You must also install MySQL++ development files and libraries
# (http://www.tangentsoft.net/mysql++/). If your MySQL++ version is older
# than 2.2, you must insert

@ -37,6 +37,21 @@
#include "sems.h"
#include "log.h"
#ifdef USE_MYSQL
#include <mysql++/mysql++.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#define DEFAULT_TEMPLATE_TABLE "default_template"
#define DOMAIN_TEMPLATE_TABLE "domain_template"
#define DEFAULT_AUDIO_TABLE "default_audio"
#define DOMAIN_AUDIO_TABLE "domain_audio"
#define USER_AUDIO_TABLE "user_audio"
#define GREETING_MSG "greeting_msg"
#define BEEP_SOUND "beep_snd"
#define EMAIL_TMPL "email_tmpl"
#endif
#include <unistd.h>
#include <dirent.h>
@ -61,6 +76,184 @@ string AnswerMachineFactory::DefaultAnnounce;
int AnswerMachineFactory::MaxRecordTime;
AmDynInvokeFactory* AnswerMachineFactory::UserTimer=0;
#ifdef USE_MYSQL
mysqlpp::Connection AnswerMachineFactory::Connection(mysqlpp::use_exceptions);
int get_audio_file(string message, string domain, string user,
string language, string *audio_file)
{
string query_string;
if (!user.empty()) {
*audio_file = string("/tmp/") + domain + "_" + user + "_" +
MOD_NAME + "_" + message + ".wav";
query_string = "select audio from " + string(USER_AUDIO_TABLE) + " where application='" + MOD_NAME + "' and message='" + message + "' and domain='" + domain + "' and userid='" + user + "'";
} else {
if (language.empty()) {
if (domain.empty()) {
*audio_file = string("/tmp/") + MOD_NAME + "_" + message +
".wav";
query_string = "select audio from " + string(DEFAULT_AUDIO_TABLE) + " where application='" + MOD_NAME + "' and message='" + message + "' and language is null";
} else {
*audio_file = string("/tmp/") + domain + "_" + MOD_NAME +
"_" + message + ".wav";
query_string = "select audio from " + string(DOMAIN_AUDIO_TABLE) + " where application='" + MOD_NAME + "' and message='" + message + "' and domain='" + domain + "' and language is null";
}
} else {
if (domain.empty()) {
*audio_file = string("/tmp/") + MOD_NAME + "_" + message +
"_" + language + ".wav";
query_string = "select audio from " + string(DEFAULT_AUDIO_TABLE) + " where application='" + MOD_NAME + "' and message='" + message + "' and language='" + language + "'";
} else {
*audio_file = string("/tmp/") + domain + "_" + MOD_NAME + "_" +
message + "_" + language + ".wav";
query_string = "select audio from " + string(DOMAIN_AUDIO_TABLE) + " where application='" + MOD_NAME + "' and message='" + message + "' and domain='" + domain + "' and language='" + language + "'";
}
}
}
try {
mysqlpp::Query query = AnswerMachineFactory::Connection.query();
DBG("Query string <%s>\n", query_string.c_str());
query << query_string;
mysqlpp::Result res = query.store();
mysqlpp::Row row;
if (res) {
if ((res.num_rows() > 0) && (row = res.at(0))) {
FILE *file;
unsigned long length = row.raw_string(0).size();
file = fopen((*audio_file).c_str(), "wb");
fwrite(row.at(0).data(), 1, length, file);
fclose(file);
return 1;
} else {
*audio_file = "";
return 1;
}
} else {
ERROR("Database query error\n");
*audio_file = "";
return 0;
}
}
catch (const mysqlpp::Exception& er) {
// Catch-all for any MySQL++ exceptions
ERROR("MySQL++ error: %s\n", er.what());
*audio_file = "";
return 0;
}
}
int AnswerMachineFactory::loadEmailTemplatesFromMySQL()
{
try {
mysqlpp::Query query = AnswerMachineFactory::Connection.query();
string query_string, table;
query_string = "select replace(template, '\r', '') as template, language from " + string(DEFAULT_TEMPLATE_TABLE) + " where application='" + MOD_NAME + "' and message='" + EMAIL_TMPL + "'";
DBG("Query string <%s>\n", query_string.c_str());
query << query_string;
mysqlpp::Result res = query.store();
mysqlpp::Row::size_type i;
mysqlpp::Row::size_type row_count = res.num_rows();
mysqlpp::Row row;
for (i = 0; i < row_count; i++) {
row = res.at(i);
FILE *file;
unsigned long length = row["template"].size();
string tmp_file, tmpl_name;
row = res.at(i);
if (string(row["language"]) == "NULL") {
tmp_file = "/tmp/voicemail_email.template";
tmpl_name = DEFAULT_MAIL_TMPL;
} else {
tmp_file = string("/tmp/voicemail_email_") +
string(row["language"]) + ".template";
tmpl_name = DEFAULT_MAIL_TMPL + "_" +
string(row["language"]);
}
file = fopen(tmp_file.c_str(), "wb");
fwrite(row["template"], 1, length, file);
fclose(file);
DBG("loading %s as %s ...\n", tmp_file.c_str(), tmpl_name.c_str());
EmailTemplate tmp_tmpl;
if (tmp_tmpl.load(tmp_file)) {
ERROR("Voicemail: could not load default"
" email template: '%s'\n", tmp_file.c_str());
return -1;
} else {
email_tmpl[tmpl_name] = tmp_tmpl;
}
}
if (email_tmpl.count(DEFAULT_MAIL_TMPL) == 0) {
ERROR("Voicemail: default email template does not exist\n");
return -1;
}
query_string = "select domain, replace(template, '\r', '') as template, language from " + string(DOMAIN_TEMPLATE_TABLE) + " where application='" + MOD_NAME +"' and message='" + EMAIL_TMPL + "'";
DBG("Query string <%s>\n", query_string.c_str());
query << query_string;
res = query.store();
row_count = res.num_rows();
for (i = 0; i < row_count; i++) {
row = res.at(i);
FILE *file;
unsigned long length = row["template"].size();
string tmp_file, tmpl_name;
row = res.at(i);
if (string(row["language"]) == "NULL") {
tmp_file = "/tmp/" + string(row["domain"]) +
"_voicemail_email.template";
tmpl_name = string(row["domain"]);
} else {
tmp_file = string("/tmp/") + string(row["domain"]) +
"_voicemail_email_" + string(row["language"]) +
".template";
tmpl_name = string(row["domain"]) + "_" +
string(row["language"]);
}
file = fopen(tmp_file.c_str(), "wb");
fwrite(row["template"], 1, length, file);
fclose(file);
DBG("loading %s as %s ...\n",tmp_file.c_str(), tmpl_name.c_str());
EmailTemplate tmp_tmpl;
if (tmp_tmpl.load(tmp_file) < 0) {
ERROR("Voicemail: could not load default"
" email template: '%s'\n", tmp_file.c_str());
return -1;
} else {
email_tmpl[tmpl_name] = tmp_tmpl;
}
}
}
catch (const mysqlpp::Exception& er) {
// Catch-all for any MySQL++ exceptions
ERROR("MySQL++ error: %s\n", er.what());
return -1;
}
return 0;
}
#else
int AnswerMachineFactory::loadEmailTemplates(const string& path)
{
string email_tmpl_file = add2path(path, 1,
@ -113,6 +306,8 @@ int AnswerMachineFactory::loadEmailTemplates(const string& path)
return err;
}
#endif
int AnswerMachineFactory::onLoad()
{
AmConfigReader cfg;
@ -122,16 +317,72 @@ int AnswerMachineFactory::onLoad()
// get application specific global parameters
configureModule(cfg);
AnnouncePath = cfg.getParameter("announce_path",ANNOUNCE_PATH);
DefaultAnnounce = cfg.getParameter("default_announce",DEFAULT_ANNOUNCE);
MaxRecordTime = cfg.getParameterInt("max_record_time",DEFAULT_RECORD_TIME);
RecFileExt = cfg.getParameter("rec_file_ext",DEFAULT_AUDIO_EXT);
#ifdef USE_MYSQL
/* Get email templates from MySQL */
string mysql_server, mysql_user, mysql_passwd, mysql_db;
mysql_server = cfg.getParameter("mysql_server");
if (mysql_server.empty()) {
mysql_server = "localhost";
}
mysql_user = cfg.getParameter("mysql_user");
if (mysql_user.empty()) {
ERROR("voicemail.conf paramater 'mysql_user' is missing.\n");
return -1;
}
mysql_passwd = cfg.getParameter("mysql_passwd");
if (mysql_passwd.empty()) {
ERROR("voicemail.conf paramater 'mysql_passwd' is missing.\n");
return -1;
}
mysql_db = cfg.getParameter("mysql_db");
if (mysql_db.empty()) {
mysql_db = "sems";
}
try {
Connection.connect(mysql_db.c_str(), mysql_server.c_str(),
mysql_user.c_str(), mysql_passwd.c_str());
if (!Connection) {
ERROR("Database connection failed: %s\n", Connection.error());
return -1;
}
}
catch (const mysqlpp::Exception& er) {
// Catch-all for any MySQL++ exceptions
ERROR("MySQL++ error: %s\n", er.what());
return -1;
}
if(loadEmailTemplatesFromMySQL()){
ERROR("while loading email templates from MySQL\n");
return -1;
}
#else
/* Get email templates from file system */
if(loadEmailTemplates(cfg.getParameter("email_template_path",DEFAULT_MAIL_TMPL_PATH))){
ERROR("while loading email templates\n");
return -1;
}
AnnouncePath = cfg.getParameter("announce_path",ANNOUNCE_PATH);
DefaultAnnounce = cfg.getParameter("default_announce",DEFAULT_ANNOUNCE);
#endif
MaxRecordTime = cfg.getParameterInt("max_record_time",DEFAULT_RECORD_TIME);
RecFileExt = cfg.getParameter("rec_file_ext",DEFAULT_AUDIO_EXT);
UserTimer = AmPlugIn::instance()->getFactory4Di("user_timer");
if(!UserTimer){
@ -166,7 +417,34 @@ AmSession* AnswerMachineFactory::onInvite(const AmSipRequest& req)
DBG("email address for user '%s': <%s> \n",
req.user.c_str(),email.c_str());
DBG("language: <%s> \n", language.c_str());
#ifdef USE_MYSQL
string announce_file;
if (get_audio_file(GREETING_MSG, req.domain, req.user, "",
&announce_file) && !announce_file.empty())
goto announce_found;
if (!language.empty()) {
if (get_audio_file(GREETING_MSG, req.domain, "", language,
&announce_file) && !announce_file.empty())
goto announce_found;
} else {
if (get_audio_file(GREETING_MSG, req.domain, "", "",
&announce_file) && !announce_file.empty())
goto announce_found;
}
if (!language.empty())
if (get_audio_file(GREETING_MSG, "", "", language,
&announce_file) && !announce_file.empty())
goto announce_found;
get_audio_file(GREETING_MSG, "", "", "", &announce_file);
#else
string announce_file = add2path(AnnouncePath,2, req.domain.c_str(), (req.user + ".wav").c_str());
if (file_exists(announce_file)) goto announce_found;
@ -187,6 +465,8 @@ AmSession* AnswerMachineFactory::onInvite(const AmSipRequest& req)
if (!file_exists(announce_file))
announce_file = "";
#endif
announce_found:
if(announce_file.empty())
throw AmSession::Exception(500,"voicemail: no greeting file found");
@ -307,9 +587,19 @@ void AnswerMachineDialog::onSessionStart(const AmSipRequest& req)
// disable DTMF detection - don't use DTMF here
setDtmfDetectionEnabled(false);
if(a_greeting.open(announce_file.c_str(),AmAudioFile::Read) ||
#ifdef USE_MYSQL
string beep_file;
if (!get_audio_file(BEEP_SOUND, "", "", "", &beep_file) ||
beep_file.empty())
throw string("AnswerMachine: could not find beep file\n");
if (a_greeting.open(announce_file.c_str(),AmAudioFile::Read) ||
a_beep.open(beep_file,AmAudioFile::Read))
throw string("AnswerMachine: could not open greeting or beep file\n");
#else
if (a_greeting.open(announce_file.c_str(),AmAudioFile::Read) ||
a_beep.open(add2path(AnswerMachineFactory::AnnouncePath,1, "beep.wav"),AmAudioFile::Read))
throw string("AnswerMachine: could not open annoucement files\n");
#endif
msg_filename = "/tmp/" + getLocalTag() + "."
+ AnswerMachineFactory::RecFileExt;

@ -28,6 +28,10 @@
#ifndef _ANSWERMACHINE_H_
#define _ANSWERMACHINE_H_
#ifdef USE_MYSQL
#include <mysql++/mysql++.h>
#endif
#include "AmSession.h"
#include "AmConfigReader.h"
#include "EmailTemplate.h"
@ -44,7 +48,12 @@ class AnswerMachineFactory: public AmSessionFactory
map<string, EmailTemplate> email_tmpl;
int getEmailAddress();
#ifdef USE_MYSQL
int loadEmailTemplatesFromMySQL();
#else
int loadEmailTemplates(const string& path);
#endif
public:
static string RecFileExt;
@ -53,6 +62,9 @@ public:
static int MaxRecordTime;
static AmDynInvokeFactory* UserTimer;
#ifdef USE_MYSQL
static mysqlpp::Connection Connection;
#endif
AnswerMachineFactory(const string& _app_name);

@ -3,6 +3,26 @@ plug_in_name = voicemail
module_ldflags =
module_cflags =
# Uncomment the last two lines if you want to keep templates and audio
# in MySQL database.
#
# You must also install MySQL++ development files and libraries
# (http://www.tangentsoft.net/mysql++/). If your MySQL++ version is older
# than 2.2, you must insert
#
# const std::string & raw_string(int i) const
# {
# return data_[i];
# }
#
# in /usr/include/mysql++/row.h.
#
# You must manually install default.template.sample to default_template
# database table.
#
#module_ldflags = -lmysqlpp
#module_cflags = -DUSE_MYSQL -I/usr/include/mysql++ -I/usr/include/mysql
extra_install = install_email_template $(plug_in_name)_audio
vm_module: all

@ -1,3 +1,5 @@
# These are needed if you keep audio and template files in file system:
#CFGOPTION_SEMS_ANNOUNCEPATH
announce_path=/usr/local/lib/sems/audio/voicemail/
#ENDCFGOPTION
@ -6,14 +8,23 @@ announce_path=/usr/local/lib/sems/audio/voicemail/
default_announce=default_en.wav
#ENDCFGOPTION
#CFGOPTION_SEMS_RECORDTIME
max_record_time=30
#ENDCFGOPTION
#CFGOPTION_SEMS_TEMPLATEDIR
email_template_path=/usr/local/etc/sems/
#ENDCFGOPTION
# These are needed if you keep audio and template files in MySQL database:
#mysql_host=localhost
#mysql_user=sems
#mysql_passwd=sems
#mysql_db=sems
# These are independent on where audio and template files are kept:
#CFGOPTION_SEMS_RECORDTIME
max_record_time=30
#ENDCFGOPTION
# rec_file_ext : extension to recorded file, determines file
# format (wav, mp3; need mp3 plugin loaded for mp3)
# default is 'wav'

@ -92,10 +92,10 @@ CREATE TABLE domain_audio (
The first one stores default audio files and the latter domain specific
audio files. Application value must be 'conference' and message values
are 'first_participant_msg', 'join_sound', and 'drop_sound'.
are 'first_participant_msg', 'join_snd', and 'drop_snd'.
When an audio file is fetched from database, it is cached in /tmp
directory and later on fetched from there.
When an audio file is fetched from database, it is stored in /tmp
directory.
These are independent of audio storage:

@ -3,8 +3,14 @@ voicemail (voicemail2email) application
This application plays a greeting message to the caller, records a
voicemail and sends it out as email via SMTP.
The voicemail application looks in various paths for the greeting
message to be played, the first file found will be played:
Audio Files
-----------
The voicemail application looks in various file system paths or database
tables for announce and beep messages to be played.
If file system is used to store audio files, the announcement file to be
played is looked for in the following order:
<announce_path><domain><user>'.wav'
<announce_path><domain><language><default_announce>
@ -16,18 +22,41 @@ where <announce_path> and <default_announce> is set in voicemail.conf,
<domain> is the host part of the request URI, <user> the user part of
the request URI, and <language> is the App-Param 'Language' (see below).
If you have a small application record or copy the greeting to
<announce_path><domain><user>'.wav' it will be played back instead of the
default announcement.
If MySQL database is used to store audio files, the announcement to be
played is looked for first from user_audio table, then from domain_audio
table, and last from default_audio table. The last two tables are
defined as described in Readme.conference. user_audio table is defined
as follows:
CREATE TABLE user_audio (
id int(10) unsigned NOT NULL auto_increment,
application varchar(32) NOT NULL,
message varchar(32) NOT NULL,
domain varchar(128) NOT NULL,
userid varchar(64) NOT NULL,
audio mediumblob NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY application (application,message,domain,userid)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Beep sound to be played is looked for only from default_audio table.
Application value is 'voicemail' and message values are 'greeting_msg'
and 'beep_snd'.
The format of the email can be configured using email templates
(see below).
When an audio file is fetched from database, it is stored in /tmp
directory.
Mail Server
-----------
The mail server to send the email with is configured in the main
sems.conf in smtp_server/smtp_port.
Other Items
-----------
further configuration items (voicemail.conf):
Further configuration items (voicemail.conf):
max_record_time - voicemail records voicemail up to the number of
seconds set here
@ -58,15 +87,16 @@ SEMS knows at least the email address to send the email to.
Voicemail email templates
-------------------------
Email templates will help you to customize the emails
sent by Voicemail. Just configure the path where the
templates can be found and edit your template files.
You will find detailed informations in the following
The format of the email can be configured using email templates. Email
templates will help you to customize the emails sent by Voicemail. Just
configure the path where the templates can be found and edit your
template files. You will find detailed informations in the following
sections.
Configuration parameters within voicemail.conf:
--------------------------------------------------
----------------------------------------------
This is needed in template files are kept in file system:
email_template_path:
@ -88,7 +118,33 @@ on, you should find in the log file during loading process following lines:
(9834) DEBUG: loadEmailTemplates (AnswerMachine.cpp:102): loading plug-in/voicemail/iptel.org.template ...
(9834) DEBUG: loadEmailTemplates (AnswerMachine.cpp:102): loading plug-in/voicemail/susie.at.template ...
If template files are kept in MySQL database, they are looked for first
from domain_template table and then from default_template table, which
are defined as follows:
CREATE TABLE domain_template (
id int(10) unsigned NOT NULL,
application varchar(32) NOT NULL,
message varchar(32) NOT NULL,
domain varchar(128) NOT NULL,
`language` char(2) default NULL,
template text NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE default_template (
id int(10) unsigned NOT NULL auto_increment,
application varchar(32) NOT NULL,
message varchar(32) NOT NULL,
`language` char(2) default NULL,
template text NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Application value is 'voicemail' and message value is 'email_tmpl'.
When an audio file is fetched from database, it is stored in /tmp
directory.
Email template format:
----------------------
@ -123,4 +179,3 @@ Following variables are supported:
- %from% : remote URI.
- %from_user% : remote user.
- %from_domain% : remote domain.

Loading…
Cancel
Save