Various code and documentation cleanups for res_config_sqlite

(closes issue #10711, rbraun_proformatique)


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@82321 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.6.0
Russell Bryant 18 years ago
parent 5b1668603f
commit 1282de797d

@ -9,7 +9,3 @@ dbfile => /var/lib/asterisk/sqlite.db
; support is simply disabled.
config_table => ast_config
cdr_table => ast_cdr
; This parameter controls the registration of the SQLITE() Dialplan application.
app_enable => yes

@ -1,8 +1,8 @@
/*
* res_sqlite - SQLite 2 support for Asterisk
*
* res_config_sqlite - SQLite 2 support for Asterisk
*
* This module can be used as a static/RealTime configuration module, and a CDR
* handler. See the Doxygen documentation for a detailed description of the
* handler. See the Doxygen documentation for a detailed description of the
* module, and the configs/ directory for the sample configuration file.
*/
@ -13,105 +13,109 @@
/*
* RealTime static table.
*/
CREATE TABLE ast_config
(
id INTEGER PRIMARY KEY,
commented INT(11) NOT NULL DEFAULT '0',
filename VARCHAR(128) NOT NULL,
category VARCHAR(128) NOT NULL,
var_name VARCHAR(128) NOT NULL,
var_val VARCHAR(128) NOT NULL
CREATE TABLE ast_config (
id INTEGER,
commented TINYINT(1) NOT NULL DEFAULT 0,
filename VARCHAR(128) NOT NULL DEFAULT '',
category VARCHAR(128) NOT NULL DEFAULT 'default',
var_name VARCHAR(128) NOT NULL DEFAULT '',
var_val TEXT NOT NULL DEFAULT '',
PRIMARY KEY (id)
);
CREATE INDEX ast_config_filename_commented ON ast_config(filename, commented);
CREATE INDEX ast_config__idx__filename_commented ON ast_config(filename, commented);
CREATE INDEX ast_config__idx__category ON ast_config(category);
/*
* CDR table (this table is automatically created if non existent).
*
* CREATE TABLE ast_cdr
* (
* id INTEGER PRIMARY KEY,
* clid VARCHAR(80) NOT NULL DEFAULT '',
* src VARCHAR(80) NOT NULL DEFAULT '',
* dst VARCHAR(80) NOT NULL DEFAULT '',
* dcontext VARCHAR(80) NOT NULL DEFAULT '',
* channel VARCHAR(80) NOT NULL DEFAULT '',
* dstchannel VARCHAR(80) NOT NULL DEFAULT '',
* lastapp VARCHAR(80) NOT NULL DEFAULT '',
* lastdata VARCHAR(80) NOT NULL DEFAULT '',
* start CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',
* answer CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',
* end CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',
* duration INT(11) NOT NULL DEFAULT '0',
* billsec INT(11) NOT NULL DEFAULT '0',
* disposition INT(11) NOT NULL DEFAULT '0',
* amaflags INT(11) NOT NULL DEFAULT '0',
* accountcode VARCHAR(20) NOT NULL DEFAULT '',
* uniqueid VARCHAR(32) NOT NULL DEFAULT '',
* userfield VARCHAR(255) NOT NULL DEFAULT ''
* );
*/
CREATE TABLE ast_cdr (
id INTEGER,
clid VARCHAR(80) NOT NULL DEFAULT '',
src VARCHAR(80) NOT NULL DEFAULT '',
dst VARCHAR(80) NOT NULL DEFAULT '',
dcontext VARCHAR(80) NOT NULL DEFAULT '',
channel VARCHAR(80) NOT NULL DEFAULT '',
dstchannel VARCHAR(80) NOT NULL DEFAULT '',
lastapp VARCHAR(80) NOT NULL DEFAULT '',
lastdata VARCHAR(80) NOT NULL DEFAULT '',
start DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
answer DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
end DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
duration INT(11) NOT NULL DEFAULT 0,
billsec INT(11) NOT NULL DEFAULT 0,
disposition VARCHAR(45) NOT NULL DEFAULT '',
amaflags INT(11) NOT NULL DEFAULT 0,
accountcode VARCHAR(20) NOT NULL DEFAULT '',
uniqueid VARCHAR(32) NOT NULL DEFAULT '',
userfield VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (id)
);
/*
* SIP RealTime table.
*/
CREATE TABLE ast_sip
(
id INTEGER PRIMARY KEY,
commented INT(11) NOT NULL DEFAULT '0',
name VARCHAR(80) NOT NULL,
accountcode VARCHAR(20),
amaflags VARCHAR(13),
callgroup VARCHAR(10),
callerid VARCHAR(80),
canreinvite CHAR(3),
context VARCHAR(80),
defaultip VARCHAR(15),
dtmfmode VARCHAR(7),
fromuser VARCHAR(80),
fromdomain VARCHAR(80),
fullcontact VARCHAR(80),
host VARCHAR(31) NOT NULL,
insecure VARCHAR(4),
language CHAR(2),
mailbox VARCHAR(50),
md5secret VARCHAR(80),
nat VARCHAR(5) NOT NULL DEFAULT 'no',
deny VARCHAR(95),
permit VARCHAR(95),
mask VARCHAR(95),
pickupgroup VARCHAR(10),
port VARCHAR(5) NOT NULL,
qualify CHAR(3),
restrictcid CHAR(1),
rtptimeout CHAR(3),
rtpholdtimeout CHAR(3),
secret VARCHAR(80),
type VARCHAR(6) NOT NULL DEFAULT 'friend',
username VARCHAR(80) NOT NULL,
disallow VARCHAR(100),
allow VARCHAR(100),
musiconhold VARCHAR(100),
regseconds INT(11) NOT NULL DEFAULT '0',
ipaddr VARCHAR(15) NOT NULL,
regexten VARCHAR(80) NOT NULL,
cancallforward CHAR(3),
setvar VARCHAR(100) NOT NULL
CREATE TABLE ast_sip (
id INTEGER,
commented TINYINT(1) NOT NULL DEFAULT 0,
name VARCHAR(80) NOT NULL DEFAULT '',
host VARCHAR(31) NOT NULL DEFAULT '',
nat VARCHAR(5) NOT NULL DEFAULT 'no',
type VARCHAR(6) NOT NULL DEFAULT 'friend',
accountcode VARCHAR(20) DEFAULT NULL,
amaflags VARCHAR(13) DEFAULT NULL,
callgroup VARCHAR(10) DEFAULT NULL,
callerid VARCHAR(80) DEFAULT NULL,
cancallforward CHAR(3) DEFAULT 'yes',
canreinvite CHAR(3) DEFAULT 'yes',
context VARCHAR(80) DEFAULT NULL,
defaultip VARCHAR(15) DEFAULT NULL,
dtmfmode VARCHAR(7) DEFAULT NULL,
fromuser VARCHAR(80) DEFAULT NULL,
fromdomain VARCHAR(80) DEFAULT NULL,
insecure VARCHAR(4) DEFAULT NULL,
language CHAR(2) DEFAULT NULL,
mailbox VARCHAR(50) DEFAULT NULL,
md5secret VARCHAR(80) DEFAULT NULL,
deny VARCHAR(95) DEFAULT NULL,
permit VARCHAR(95) DEFAULT NULL,
mask VARCHAR(95) DEFAULT NULL,
musiconhold VARCHAR(100) DEFAULT NULL,
pickupgroup VARCHAR(10) DEFAULT NULL,
qualify CHAR(3) DEFAULT NULL,
regexten VARCHAR(80) DEFAULT NULL,
restrictcid CHAR(3) DEFAULT NULL,
rtptimeout CHAR(3) DEFAULT NULL,
rtpholdtimeout CHAR(3) DEFAULT NULL,
secret VARCHAR(80) DEFAULT NULL,
setvar VARCHAR(100) DEFAULT NULL,
disallow VARCHAR(100) DEFAULT 'all',
allow VARCHAR(100) DEFAULT 'g729,ilbc,gsm,ulaw,alaw',
fullcontact VARCHAR(80) NOT NULL DEFAULT '',
ipaddr VARCHAR(15) NOT NULL DEFAULT '',
port INT(11) NOT NULL DEFAULT 0,
regserver VARCHAR(100) DEFAULT NULL,
regseconds INT(11) NOT NULL DEFAULT 0,
username VARCHAR(80) NOT NULL DEFAULT '',
PRIMARY KEY (id)
UNIQUE (name)
);
CREATE UNIQUE INDEX ast_sip_name ON ast_sip(name);
CREATE INDEX ast_sip__idx__commented ON ast_sip(commented);
/*
* Dialplan RealTime table.
*/
CREATE TABLE ast_exten
(
id INTEGER PRIMARY KEY,
commented INT(11) NOT NULL DEFAULT '0',
context VARCHAR(20) NOT NULL,
exten VARCHAR(20) NOT NULL,
priority TINYINT(4) NOT NULL,
app VARCHAR(20) NOT NULL,
appdata VARCHAR(128) NOT NULL
CREATE TABLE ast_exten (
id INTEGER,
commented TINYINT(1) NOT NULL DEFAULT 0,
context VARCHAR(80) NOT NULL DEFAULT '',
exten VARCHAR(40) NOT NULL DEFAULT '',
priority INT(11) NOT NULL DEFAULT 0,
app VARCHAR(128) NOT NULL DEFAULT '',
appdata VARCHAR(128) NOT NULL DEFAULT '',
PRIMARY KEY (id)
);
CREATE INDEX ast_exten__idx__commented ON ast_exten(commented);
CREATE INDEX ast_exten__idx__context_exten_priority ON ast_exten(context, exten, priority);

@ -252,6 +252,7 @@ DUNDi is not itself a Voice-over IP signaling or media protocol. Instead, it pub
* \arg \link Config_enum ENUM configuration \endlink
* \arg \link Config_moh Music on Hold configuration \endlink
* \arg \link Config_vm Voicemail configuration \endlink
* \arg \link res_config_sqlite SQLite Resource driver configuration \endlink
*/
/*! \page Config_ast Asterisk.conf
@ -551,3 +552,13 @@ DUNDi is not itself a Voice-over IP signaling or media protocol. Instead, it pub
* \arg \link Config_ami Configuration file \endlink
* \verbinclude ajam.txt
*/
/*! \page res_config_sqlite SQLite Resource driver configuration
* \arg Implemented in \ref res_config_sqlite.c
* \arg Configuration file:
* \verbinclude res_config_sqlite.conf
* \arg SQL tables:
* \verbinclude res_config_sqlite.txt
* \arg See also:
* http://www.sqlite.org
*/

@ -5,7 +5,7 @@
*
* Written by Richard Braun <rbraun@proformatique.com>
*
* Based on res_sqlite3 by Anthony Minessale II,
* Based on res_sqlite3 by Anthony Minessale II,
* and res_config_mysql by Matthew Boehm
*
* See http://www.asterisk.org for more information about
@ -21,75 +21,60 @@
/*!
* \page res_config_sqlite
*
*
* \section intro_sec Presentation
*
* res_config_sqlite is a module for the Asterisk Open Source PBX to
* support SQLite 2 databases. It can be used to fetch configuration
* from a database (static configuration files and/or using the Asterisk
*
* res_config_sqlite is a module for the Asterisk Open Source PBX to
* support SQLite 2 databases. It can be used to fetch configuration
* from a database (static configuration files and/or using the Asterisk
* RealTime Architecture - ARA).
* It can also be used to log CDR entries. Finally, it can be used for simple
* queries in the Dialplan. Note that Asterisk already comes with a module
* named cdr_sqlite. There are two reasons for including it in res_sqlite:
* named cdr_sqlite. There are two reasons for including it in res_config_sqlite:
* the first is that rewriting it was a training to learn how to write a
* simple module for Asterisk, the other is to have the same database open for
* all kinds of operations, which improves reliability and performance.
*
*
* There is already a module for SQLite 3 (named res_sqlite3) in the Asterisk
* addons. res_sqlite was developed because we, at Proformatique, are using
* addons. res_config_sqlite was developed because we, at Proformatique, are using
* PHP 4 in our embedded systems, and PHP 4 has no stable support for SQLite 3
* at this time. We also needed RealTime support.
*
*
* \section conf_sec Configuration
*
*
* The main configuration file is res_config_sqlite.conf. It must be readable or
* res_sqlite will fail to start. It is suggested to use the sample file
* res_config_sqlite will fail to start. It is suggested to use the sample file
* in this package as a starting point. The file has only one section
* named <code>general</code>. Here are the supported parameters :
*
*
* <dl>
* <dt><code>dbfile</code></dt>
* <dd>The absolute path to the SQLite database (the file can be non existent,
* res_sqlite will create it if is has the appropriate rights)</dd>
* res_config_sqlite will create it if it has the appropriate rights)</dd>
* <dt><code>config_table</code></dt>
* <dd>The table used for static configuration</dd>
* <dt><code>cdr_table</code></dt>
* <dd>The table used to store CDR entries (if ommitted, CDR support is
* disabled)</dd>
* </dl>
*
* To use res_sqlite for static and/or RealTime configuration, refer to the
*
* To use res_config_sqlite for static and/or RealTime configuration, refer to the
* Asterisk documentation. The file tables.sql can be used to create the
* needed tables.
*
* The SQLITE() application is very similar to the MYSQL() application. You
* can find more details at
* <a href="http://voip-info.org/wiki/view/Asterisk+cmd+MYSQL">http://voip-info.org/wiki/view/Asterisk+cmd+MYSQL</a>.
* The main difference is that you cannot choose your database - it's the
* file set in the <code>dbfile</code> parameter. As a result, there is no
* Connect or Disconnect command, and there is no connid variable.
*
*
* \section status_sec Driver status
*
*
* The CLI command <code>show sqlite status</code> returns status information
* about the running driver. One information is more important than others:
* the number of registered virtual machines. A SQLite virtual machine is
* created each time a SQLITE() query command is used. If the number of
* registered virtual machines isn't 0 (or near 0, since one or more SQLITE()
* commands can be running when requesting the module status) and increases
* over time, this probably means that you're badly using the application
* and you're creating resource leaks. You should check your Dialplan and
* reload res_sqlite (by unloading and then loading again - reloading isn't
* supported)
*
* about the running driver.
*
* \section credits_sec Credits
*
*
* res_config_sqlite was developed by Richard Braun at the Proformatique company.
*/
/*!
* \file
* \brief res_sqlite module.
* \file
* \brief res_config_sqlite module.
*/
/*** MODULEINFO
@ -114,94 +99,85 @@
#include "asterisk/options.h"
#include "asterisk/linkedlists.h"
#define RES_SQLITE_NAME "res_sqlite"
#define RES_SQLITE_DRIVER "sqlite"
#define RES_SQLITE_APP_DRIVER "SQLITE"
#define RES_SQLITE_DESCRIPTION "Resource Module for SQLite 2"
#define RES_SQLITE_CONF_FILE "res_config_sqlite.conf"
#define RES_SQLITE_APP_SYNOPSIS "Dialplan access to SQLite 2"
#define RES_SQLITE_APP_DESCRIPTION \
"SQLITE(): " RES_SQLITE_APP_SYNOPSIS "\n"
#define RES_SQLITE_STATUS_SUMMARY \
"Show status information about the SQLite 2 driver"
#define RES_SQLITE_STATUS_USAGE \
"Usage: show sqlite status\n" \
" " RES_SQLITE_STATUS_SUMMARY "\n"
#define MACRO_BEGIN do {
#define MACRO_END } while (0)
#define RES_CONFIG_SQLITE_NAME "res_config_sqlite"
#define RES_CONFIG_SQLITE_DRIVER "sqlite"
#define RES_CONFIG_SQLITE_DESCRIPTION "Resource Module for SQLite 2"
#define RES_CONFIG_SQLITE_CONF_FILE "res_config_sqlite.conf"
#define RES_CONFIG_SQLITE_STATUS_SUMMARY "Show status information about the SQLite 2 driver"
#define RES_CONFIG_SQLITE_STATUS_USAGE \
"Usage: show sqlite status\n" \
" " RES_CONFIG_SQLITE_STATUS_SUMMARY "\n"
enum {
RES_SQLITE_CONFIG_ID,
RES_SQLITE_CONFIG_COMMENTED,
RES_SQLITE_CONFIG_FILENAME,
RES_SQLITE_CONFIG_CATEGORY,
RES_SQLITE_CONFIG_VAR_NAME,
RES_SQLITE_CONFIG_VAR_VAL,
RES_SQLITE_CONFIG_COLUMNS,
RES_CONFIG_SQLITE_CONFIG_ID,
RES_CONFIG_SQLITE_CONFIG_COMMENTED,
RES_CONFIG_SQLITE_CONFIG_FILENAME,
RES_CONFIG_SQLITE_CONFIG_CATEGORY,
RES_CONFIG_SQLITE_CONFIG_VAR_NAME,
RES_CONFIG_SQLITE_CONFIG_VAR_VAL,
RES_CONFIG_SQLITE_CONFIG_COLUMNS,
};
/*!
* Limit the number of maximum simultaneous registered SQLite VMs to avoid
* a denial of service attack.
*/
#define RES_SQLITE_VM_MAX 1024
#define SET_VAR(config, to, from) \
do \
{ \
int __error; \
__error = set_var(&to, #to, from->value); \
if (__error) \
{ \
ast_config_destroy(config); \
unload_config(); \
return 1; \
} \
} \
while (0)
#define SET_VAR(config, to, from) \
MACRO_BEGIN \
int __error; \
\
__error = set_var(&to, #to, from->value); \
\
if (__error) { \
ast_config_destroy(config); \
unload_config(); \
return 1; \
} \
MACRO_END
/*!
* Maximum number of loops before giving up executing a query. Calls to
* sqlite_xxx() functions which can return SQLITE_BUSY or SQLITE_LOCKED
* are enclosed by RES_SQLITE_BEGIN and RES_SQLITE_END, e.g.
* are enclosed by RES_CONFIG_SQLITE_BEGIN and RES_CONFIG_SQLITE_END, e.g.
* <pre>
* char *errormsg;
* int error;
*
* RES_SQLITE_BEGIN
*
* RES_CONFIG_SQLITE_BEGIN
* error = sqlite_exec(db, query, NULL, NULL, &errormsg);
* RES_SQLITE_END(error)
*
* RES_CONFIG_SQLITE_END(error)
*
* if (error)
* ...;
* </pre>
*/
#define RES_SQLITE_MAX_LOOPS 10
#define RES_CONFIG_SQLITE_MAX_LOOPS 10
/*!
* Macro used before executing a query.
*
* \see RES_SQLITE_MAX_LOOPS.
*
* \see RES_CONFIG_SQLITE_MAX_LOOPS.
*/
#define RES_SQLITE_BEGIN \
{ \
int __i; \
for (__i = 0; __i < RES_SQLITE_MAX_LOOPS; __i++) \
{
#define RES_CONFIG_SQLITE_BEGIN \
MACRO_BEGIN \
int __i; \
\
for (__i = 0; __i < RES_CONFIG_SQLITE_MAX_LOOPS; __i++) {
/*!
* Macro used after executing a query.
*
* \see RES_SQLITE_MAX_LOOPS.
*
* \see RES_CONFIG_SQLITE_MAX_LOOPS.
*/
#define RES_SQLITE_END(error) \
if (error != SQLITE_BUSY && error != SQLITE_LOCKED) \
break; \
usleep(1000); \
} \
}
#define RES_CONFIG_SQLITE_END(error) \
if (error != SQLITE_BUSY && error != SQLITE_LOCKED) \
break; \
usleep(1000); \
} \
MACRO_END;
/*!
* Structure sent to the SQLite callback function for static configuration.
*
*
* \see add_cfg_entry()
*/
struct cfg_entry_args {
@ -212,7 +188,7 @@ struct cfg_entry_args {
/*!
* Structure sent to the SQLite callback function for RealTime configuration.
*
*
* \see add_rt_cfg_entry()
*/
struct rt_cfg_entry_args {
@ -223,7 +199,7 @@ struct rt_cfg_entry_args {
/*!
* Structure sent to the SQLite callback function for RealTime configuration
* (realtime_multi_handler()).
*
*
* \see add_rt_multi_cfg_entry()
*/
struct rt_multi_cfg_entry_args {
@ -244,10 +220,10 @@ static int set_var(char **var, char *name, char *value);
/*!
* \brief Load the configuration file.
* \see unload_config()
*
*
* This function sets dbfile, config_table, and cdr_table. It calls
* check_vars() before returning, and unload_config() if an error occurred.
*
*
* \retval 0 on success
* \retval 1 if an error occurred
*/
@ -262,10 +238,10 @@ static void unload_config(void);
/*!
* \brief Asterisk callback function for CDR support.
* \param cdr the CDR entry Asterisk sends us.
*
*
* Asterisk will call this function each time a CDR entry must be logged if
* CDR support is enabled.
*
*
* \retval 0 on success
* \retval 1 if an error occurred
*/
@ -273,11 +249,11 @@ static int cdr_handler(struct ast_cdr *cdr);
/*!
* \brief SQLite callback function for static configuration.
*
*
* This function is passed to the SQLite engine as a callback function to
* parse a row and store it in a struct ast_config object. It relies on
* resulting rows being sorted by category.
*
* resulting rows being sorted by category.
*
* \param arg a pointer to a struct cfg_entry_args object
* \param argc number of columns
* \param argv values in the row
@ -292,10 +268,10 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames);
/*!
* \brief Asterisk callback function for static configuration.
*
*
* Asterisk will call this function when it loads its static configuration,
* which usually happens at startup and reload.
*
*
* \param database the database to use (ignored)
* \param table the table to use
* \param file the file to load from the database
@ -307,24 +283,24 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames);
* \see add_cfg_entry()
*/
static struct ast_config * config_handler(const char *database, const char *table, const char *file,
struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl);
struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl);
/*!
* \brief Helper function to parse a va_list object into 2 dynamic arrays of
* strings, parameters and values.
*
*
* ap must have the following format : param1 val1 param2 val2 param3 val3 ...
* arguments will be extracted to create 2 arrays:
*
*
* <ul>
* <li>params : param1 param2 param3 ...</li>
* <li>vals : val1 val2 val3 ...</li>
* </ul>
*
*
* The address of these arrays are stored in params_ptr and vals_ptr. It
* is the responsibility of the caller to release the memory of these arrays.
* It is considered an error that va_list has a null or odd number of strings.
*
*
* \param ap the va_list object to parse
* \param params_ptr where the address of the params array is stored
* \param vals_ptr where the address of the vals array is stored
@ -336,10 +312,10 @@ static size_t get_params(va_list ap, const char ***params_ptr,
/*!
* \brief SQLite callback function for RealTime configuration.
*
*
* This function is passed to the SQLite engine as a callback function to
* parse a row and store it in a linked list of struct ast_variable objects.
*
*
* \param arg a pointer to a struct rt_cfg_entry_args object
* \param argc number of columns
* \param argv values in the row
@ -354,16 +330,16 @@ static int add_rt_cfg_entry(void *arg, int argc, char **argv,
/*!
* Asterisk callback function for RealTime configuration.
*
*
* Asterisk will call this function each time it requires a variable
* through the RealTime architecture. ap is a list of parameters and
* values used to find a specific row, e.g one parameter "name" and
* one value "123" so that the SQL query becomes <code>SELECT * FROM
* table WHERE name = '123';</code>.
*
*
* \param database the database to use (ignored)
* \param table the table to use
* \param ap list of parameters and values to match
* \param table the table to use
* \param ap list of parameters and values to match
*
* \retval a linked list of struct ast_variable objects
* \retval NULL if an error occurred
@ -374,11 +350,11 @@ static struct ast_variable * realtime_handler(const char *database,
/*!
* \brief SQLite callback function for RealTime configuration.
*
*
* This function performs the same actions as add_rt_cfg_entry() except
* that the rt_multi_cfg_entry_args structure is designed to store
* categories in addition of variables.
*
* categories in addition to variables.
*
* \param arg a pointer to a struct rt_multi_cfg_entry_args object
* \param argc number of columns
* \param argv values in the row
@ -393,11 +369,11 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv,
/*!
* \brief Asterisk callback function for RealTime configuration.
*
*
* This function performs the same actions as realtime_handler() except
* that it can store variables per category, and can return several
* categories.
*
*
* \param database the database to use (ignored)
* \param table the table to use
* \param ap list of parameters and values to match
@ -407,19 +383,18 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv,
* \see add_rt_multi_cfg_entry()
*/
static struct ast_config * realtime_multi_handler(const char *database,
const char *table,
va_list ap);
const char *table, va_list ap);
/*!
* \brief Asterisk callback function for RealTime configuration (variable
* update).
*
*
* Asterisk will call this function each time a variable has been modified
* internally and must be updated in the backend engine. keyfield and entity
* are used to find the row to update, e.g. <code>UPDATE table SET ... WHERE
* keyfield = 'entity';</code>. ap is a list of parameters and values with the
* same format as the other realtime functions.
*
*
* \param database the database to use (ignored)
* \param table the table to use
* \param keyfield the column of the matching cell
@ -429,18 +404,17 @@ static struct ast_config * realtime_multi_handler(const char *database,
* \retval -1 if an error occurred.
*/
static int realtime_update_handler(const char *database, const char *table,
const char *keyfield, const char *entity,
va_list ap);
const char *keyfield, const char *entity, va_list ap);
/*!
* \brief Asterisk callback function for RealTime configuration (variable
* create/store).
*
*
* Asterisk will call this function each time a variable has been created
* internally and must be stored in the backend engine.
* are used to find the row to update, e.g. ap is a list of parameters and
* internally and must be stored in the backend engine.
* are used to find the row to update, e.g. ap is a list of parameters and
* values with the same format as the other realtime functions.
*
*
* \param database the database to use (ignored)
* \param table the table to use
* \param ap list of parameters and new values to insert into the database
@ -451,15 +425,15 @@ static int realtime_store_handler(const char *database, const char *table,
va_list ap);
/*!
* \brief Asterisk callback function for RealTime configuration (destroys
* \brief Asterisk callback function for RealTime configuration (destroys
* variable).
*
*
* Asterisk will call this function each time a variable has been destroyed
* internally and must be removed from the backend engine. keyfield and entity
* are used to find the row to delete, e.g. <code>DELETE FROM table WHERE
* keyfield = 'entity';</code>. ap is a list of parameters and values with the
* same format as the other realtime functions.
*
*
* \param database the database to use (ignored)
* \param table the table to use
* \param keyfield the column of the matching cell
@ -469,12 +443,11 @@ static int realtime_store_handler(const char *database, const char *table,
* \retval -1 if an error occurred.
*/
static int realtime_destroy_handler(const char *database, const char *table,
const char *keyfield, const char *entity,
va_list ap);
const char *keyfield, const char *entity, va_list ap);
/*!
* \brief Asterisk callback function for the CLI status command.
*
*
* \param fd file descriptor provided by Asterisk to use with ast_cli()
* \param argc number of arguments
* \param argv arguments list
@ -503,16 +476,13 @@ static char *config_table;
/*! The name of the table used to store CDR entries. */
static char *cdr_table;
/*! The number of registered virtual machines. */
static int vm_count;
/*!
* The structure specifying all callback functions used by Asterisk for static
* and RealTime configuration.
*/
static struct ast_config_engine sqlite_engine =
{
.name = RES_SQLITE_DRIVER,
.name = RES_CONFIG_SQLITE_DRIVER,
.load_func = config_handler,
.realtime_func = realtime_handler,
.realtime_multi_func = realtime_multi_handler,
@ -523,7 +493,6 @@ static struct ast_config_engine sqlite_engine =
/*!
* The mutex used to prevent simultaneous access to the SQLite database.
* SQLite isn't always compiled with thread safety.
*/
AST_MUTEX_DEFINE_STATIC(mutex);
@ -535,8 +504,8 @@ static struct ast_cli_entry cli_status_cmd =
{
.cmda = {"show", "sqlite", "status", NULL},
.handler = cli_status,
.summary = RES_SQLITE_STATUS_SUMMARY,
.usage = RES_SQLITE_STATUS_USAGE
.summary = RES_CONFIG_SQLITE_STATUS_SUMMARY,
.usage = RES_CONFIG_SQLITE_STATUS_USAGE
};
/*
@ -545,32 +514,33 @@ static struct ast_cli_entry cli_status_cmd =
/*! SQL query format to create the CDR table if non existent. */
static char *sql_create_cdr_table =
"CREATE TABLE '%q' ("
" id INTEGER PRIMARY KEY,"
" clid VARCHAR(80) NOT NULL DEFAULT '',"
" src VARCHAR(80) NOT NULL DEFAULT '',"
" dst VARCHAR(80) NOT NULL DEFAULT '',"
" dcontext VARCHAR(80) NOT NULL DEFAULT '',"
" channel VARCHAR(80) NOT NULL DEFAULT '',"
" dstchannel VARCHAR(80) NOT NULL DEFAULT '',"
" lastapp VARCHAR(80) NOT NULL DEFAULT '',"
" lastdata VARCHAR(80) NOT NULL DEFAULT '',"
" start CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',"
" answer CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',"
" end CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',"
" duration INT(11) NOT NULL DEFAULT '0',"
" billsec INT(11) NOT NULL DEFAULT '0',"
" disposition INT(11) NOT NULL DEFAULT '0',"
" amaflags INT(11) NOT NULL DEFAULT '0',"
" accountcode VARCHAR(20) NOT NULL DEFAULT '',"
" uniqueid VARCHAR(32) NOT NULL DEFAULT '',"
" userfield VARCHAR(255) NOT NULL DEFAULT ''"
"CREATE TABLE '%q' (\n"
" id INTEGER,\n"
" clid VARCHAR(80) NOT NULL DEFAULT '',\n"
" src VARCHAR(80) NOT NULL DEFAULT '',\n"
" dst VARCHAR(80) NOT NULL DEFAULT '',\n"
" dcontext VARCHAR(80) NOT NULL DEFAULT '',\n"
" channel VARCHAR(80) NOT NULL DEFAULT '',\n"
" dstchannel VARCHAR(80) NOT NULL DEFAULT '',\n"
" lastapp VARCHAR(80) NOT NULL DEFAULT '',\n"
" lastdata VARCHAR(80) NOT NULL DEFAULT '',\n"
" start DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',\n"
" answer DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',\n"
" end DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',\n"
" duration INT(11) NOT NULL DEFAULT 0,\n"
" billsec INT(11) NOT NULL DEFAULT 0,\n"
" disposition VARCHAR(45) NOT NULL DEFAULT '',\n"
" amaflags INT(11) NOT NULL DEFAULT 0,\n"
" accountcode VARCHAR(20) NOT NULL DEFAULT '',\n"
" uniqueid VARCHAR(32) NOT NULL DEFAULT '',\n"
" userfield VARCHAR(255) NOT NULL DEFAULT '',\n"
" PRIMARY KEY (id)\n"
");";
/*! SQL query format to insert a CDR entry. */
static char *sql_add_cdr_entry =
"INSERT INTO '%q' ("
" clid,"
" clid,"
" src,"
" dst,"
" dcontext,"
@ -612,7 +582,7 @@ static char *sql_add_cdr_entry =
/*!
* SQL query format to fetch the static configuration of a file.
* Rows must be sorted by category.
*
*
* \see add_cfg_entry()
*/
static char *sql_get_config_table =
@ -655,10 +625,10 @@ static int load_config(void)
int error;
struct ast_flags config_flags = { 0 };
config = ast_config_load(RES_SQLITE_CONF_FILE, config_flags);
config = ast_config_load(RES_CONFIG_SQLITE_CONF_FILE, config_flags);
if (!config) {
ast_log(LOG_ERROR, "Unable to load " RES_SQLITE_CONF_FILE "\n");
ast_log(LOG_ERROR, "Unable to load " RES_CONFIG_SQLITE_CONF_FILE "\n");
return 1;
}
@ -696,27 +666,37 @@ static void unload_config(void)
static int cdr_handler(struct ast_cdr *cdr)
{
char *errormsg;
char *query, *errormsg;
int error;
query = sqlite_mprintf(sql_add_cdr_entry, cdr_table, cdr->clid,
cdr->src, cdr->dst, cdr->dcontext, cdr->channel,
cdr->dstchannel, cdr->lastapp, cdr->lastdata,
cdr->start.tv_sec, cdr->answer.tv_sec,
cdr->end.tv_sec, cdr->duration, cdr->billsec,
cdr->disposition, cdr->amaflags, cdr->accountcode,
cdr->uniqueid, cdr->userfield);
if (!query) {
ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
return 1;
}
ast_debug(1, "SQL query: %s\n", query);
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
error = sqlite_exec_printf(db, sql_add_cdr_entry, NULL, NULL, &errormsg,
cdr_table, cdr->clid, cdr->src, cdr->dst,
cdr->dcontext, cdr->channel, cdr->dstchannel,
cdr->lastapp, cdr->lastdata, cdr->start.tv_sec,
cdr->answer.tv_sec, cdr->end.tv_sec,
cdr->duration, cdr->billsec, cdr->disposition,
cdr->amaflags, cdr->accountcode, cdr->uniqueid,
cdr->userfield);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, NULL, NULL, &errormsg);
RES_CONFIG_SQLITE_END(error)
ast_mutex_unlock(&mutex);
sqlite_freemem(query);
if (error) {
ast_log(LOG_ERROR, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
return 1;
}
@ -728,15 +708,15 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
struct cfg_entry_args *args;
struct ast_variable *var;
if (argc != RES_SQLITE_CONFIG_COLUMNS) {
if (argc != RES_CONFIG_SQLITE_CONFIG_COLUMNS) {
ast_log(LOG_WARNING, "Corrupt table\n");
return 1;
}
args = arg;
if (!args->cat_name || strcmp(args->cat_name, argv[RES_SQLITE_CONFIG_CATEGORY])) {
args->cat = ast_category_new(argv[RES_SQLITE_CONFIG_CATEGORY], "", 99999);
if (!args->cat_name || strcmp(args->cat_name, argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY])) {
args->cat = ast_category_new(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY], "", 99999);
if (!args->cat) {
ast_log(LOG_WARNING, "Unable to allocate category\n");
@ -744,7 +724,7 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
}
ast_free(args->cat_name);
args->cat_name = ast_strdup(argv[RES_SQLITE_CONFIG_CATEGORY]);
args->cat_name = ast_strdup(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY]);
if (!args->cat_name) {
ast_category_destroy(args->cat);
@ -754,8 +734,7 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
ast_category_append(args->cfg, args->cat);
}
var = ast_variable_new(argv[RES_SQLITE_CONFIG_VAR_NAME],
argv[RES_SQLITE_CONFIG_VAR_VAL], "");
var = ast_variable_new(argv[RES_CONFIG_SQLITE_CONFIG_VAR_NAME], argv[RES_CONFIG_SQLITE_CONFIG_VAR_VAL], "");
if (!var) {
ast_log(LOG_WARNING, "Unable to allocate variable");
@ -763,15 +742,15 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
}
ast_variable_append(args->cat, var);
return 0;
}
static struct ast_config *config_handler(const char *database, const char *table, const char *file,
struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl)
struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl)
{
struct cfg_entry_args args;
char *errormsg;
char *query, *errormsg;
int error;
if (!config_table) {
@ -782,24 +761,32 @@ struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl)
} else
table = config_table;
query = sqlite_mprintf(sql_get_config_table, table, file);
if (!query) {
ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
return NULL;
}
ast_debug(1, "SQL query: %s\n", query);
args.cfg = cfg;
args.cat = NULL;
args.cat_name = NULL;
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
error = sqlite_exec_printf(db, sql_get_config_table, add_cfg_entry,
&args, &errormsg, table, file);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, add_cfg_entry, &args, &errormsg);
RES_CONFIG_SQLITE_END(error)
ast_mutex_unlock(&mutex);
ast_free(args.cat_name);
sqlite_freemem(query);
if (error) {
ast_log(LOG_ERROR, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
return NULL;
}
@ -873,8 +860,7 @@ static int add_rt_cfg_entry(void *arg, int argc, char **argv, char **columnNames
return 0;
}
static struct ast_variable *
realtime_handler(const char *database, const char *table, va_list ap)
static struct ast_variable * realtime_handler(const char *database, const char *table, va_list ap)
{
char *query, *errormsg, *op, *tmp_str;
struct rt_cfg_entry_args args;
@ -913,8 +899,7 @@ realtime_handler(const char *database, const char *table, va_list ap)
for (i = 1; i < params_count; i++) {
op = (strchr(params[i], ' ') == NULL) ? " =" : "";
tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op,
vals[i]);
tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op, vals[i]);
sqlite_freemem(query);
if (!tmp_str) {
@ -946,9 +931,9 @@ realtime_handler(const char *database, const char *table, va_list ap)
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, add_rt_cfg_entry, &args, &errormsg);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_END(error)
ast_mutex_unlock(&mutex);
@ -956,7 +941,7 @@ realtime_handler(const char *database, const char *table, va_list ap)
if (error) {
ast_log(LOG_WARNING, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
ast_variables_destroy(args.var);
return NULL;
}
@ -972,7 +957,7 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum
char *cat_name;
size_t i;
args = (struct rt_multi_cfg_entry_args *)arg;
args = arg;
cat_name = NULL;
/*
@ -1012,7 +997,7 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum
return 0;
}
static struct ast_config *realtime_multi_handler(const char *database,
static struct ast_config *realtime_multi_handler(const char *database,
const char *table, va_list ap)
{
char *query, *errormsg, *op, *tmp_str, *initfield;
@ -1076,8 +1061,7 @@ static struct ast_config *realtime_multi_handler(const char *database,
for (i = 1; i < params_count; i++) {
op = (!strchr(params[i], ' ')) ? " =" : "";
tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op,
vals[i]);
tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op, vals[i]);
sqlite_freemem(query);
if (!tmp_str) {
@ -1111,9 +1095,9 @@ static struct ast_config *realtime_multi_handler(const char *database,
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, add_rt_multi_cfg_entry, &args, &errormsg);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_END(error)
ast_mutex_unlock(&mutex);
@ -1122,7 +1106,7 @@ static struct ast_config *realtime_multi_handler(const char *database,
if (error) {
ast_log(LOG_WARNING, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
ast_config_destroy(cfg);
return NULL;
}
@ -1131,8 +1115,7 @@ static struct ast_config *realtime_multi_handler(const char *database,
}
static int realtime_update_handler(const char *database, const char *table,
const char *keyfield, const char *entity,
va_list ap)
const char *keyfield, const char *entity, va_list ap)
{
char *query, *errormsg, *tmp_str;
const char **params, **vals;
@ -1163,8 +1146,7 @@ static int realtime_update_handler(const char *database, const char *table,
size_t i;
for (i = 1; i < params_count; i++) {
tmp_str = sqlite_mprintf("%s, %q = '%q'", query, params[i],
vals[i]);
tmp_str = sqlite_mprintf("%s, %q = '%q'", query, params[i], vals[i]);
sqlite_freemem(query);
if (!tmp_str) {
@ -1192,9 +1174,9 @@ static int realtime_update_handler(const char *database, const char *table,
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, NULL, NULL, &errormsg);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_END(error)
if (!error)
rows_num = sqlite_changes(db);
@ -1207,7 +1189,7 @@ static int realtime_update_handler(const char *database, const char *table,
if (error) {
ast_log(LOG_WARNING, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
}
return rows_num;
@ -1282,9 +1264,9 @@ static int realtime_store_handler(const char *database, const char *table, va_li
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, tmp_str, NULL, NULL, &errormsg);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_END(error)
if (!error) {
rows_id = sqlite_last_insert_rowid(db);
@ -1298,15 +1280,14 @@ static int realtime_store_handler(const char *database, const char *table, va_li
if (error) {
ast_log(LOG_WARNING, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
}
return rows_id;
}
static int realtime_destroy_handler(const char *database, const char *table,
const char *keyfield, const char *entity,
va_list ap)
const char *keyfield, const char *entity, va_list ap)
{
char *query, *errormsg, *tmp_str;
const char **params, **vals;
@ -1356,14 +1337,13 @@ static int realtime_destroy_handler(const char *database, const char *table,
}
sqlite_freemem(query);
query = tmp_str;
ast_debug(1, "SQL query: %s\n", query);
ast_mutex_lock(&mutex);
RES_SQLITE_BEGIN
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, NULL, NULL, &errormsg);
RES_SQLITE_END(error)
RES_CONFIG_SQLITE_END(error)
if (!error)
rows_num = sqlite_changes(db);
@ -1376,7 +1356,7 @@ static int realtime_destroy_handler(const char *database, const char *table,
if (error) {
ast_log(LOG_WARNING, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
}
return rows_num;
@ -1409,7 +1389,7 @@ static int unload_module(void)
ast_cli_unregister(&cli_status_cmd);
if (cdr_registered)
ast_cdr_unregister(RES_SQLITE_NAME);
ast_cdr_unregister(RES_CONFIG_SQLITE_NAME);
ast_config_engine_deregister(&sqlite_engine);
@ -1432,7 +1412,6 @@ static int load_module(void)
dbfile = NULL;
config_table = NULL;
cdr_table = NULL;
vm_count = 0;
error = load_config();
if (error)
@ -1440,7 +1419,7 @@ static int load_module(void)
if (!(db = sqlite_open(dbfile, 0660, &errormsg))) {
ast_log(LOG_ERROR, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
unload_module();
return 1;
}
@ -1448,10 +1427,28 @@ static int load_module(void)
ast_config_engine_register(&sqlite_engine);
if (use_cdr) {
RES_SQLITE_BEGIN
error = sqlite_exec_printf(db, "SELECT COUNT(id) FROM %Q;", NULL, NULL,
&errormsg, cdr_table);
RES_SQLITE_END(error)
char *query;
/* \cond DOXYGEN_CAN_PARSE_THIS */
#undef QUERY
#define QUERY "SELECT COUNT(id) FROM %Q;"
/* \endcond */
query = sqlite_mprintf(QUERY, cdr_table);
if (!query) {
ast_log(LOG_ERROR, "Unable to allocate SQL query\n");
unload_module();
return 1;
}
ast_debug(1, "SQL query: %s\n", query);
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, NULL, NULL, &errormsg);
RES_CONFIG_SQLITE_END(error)
sqlite_freemem(query);
if (error) {
/*
@ -1459,26 +1456,37 @@ static int load_module(void)
*/
if (error != SQLITE_ERROR) {
ast_log(LOG_ERROR, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
unload_module();
return 1;
}
sqlite_freemem(errormsg);
query = sqlite_mprintf(sql_create_cdr_table, cdr_table);
if (!query) {
ast_log(LOG_ERROR, "Unable to allocate SQL query\n");
unload_module();
return 1;
}
RES_SQLITE_BEGIN
error = sqlite_exec_printf(db, sql_create_cdr_table, NULL, NULL,
&errormsg, cdr_table);
RES_SQLITE_END(error)
ast_debug(1, "SQL query: %s\n", query);
RES_CONFIG_SQLITE_BEGIN
error = sqlite_exec(db, query, NULL, NULL, &errormsg);
RES_CONFIG_SQLITE_END(error)
sqlite_freemem(query);
if (error) {
ast_log(LOG_ERROR, "%s\n", errormsg);
ast_free(errormsg);
sqlite_freemem(errormsg);
unload_module();
return 1;
}
}
error = ast_cdr_register(RES_SQLITE_NAME, RES_SQLITE_DESCRIPTION,
cdr_handler);
error = ast_cdr_register(RES_CONFIG_SQLITE_NAME, RES_CONFIG_SQLITE_DESCRIPTION, cdr_handler);
if (error) {
unload_module();

Loading…
Cancel
Save