Index: doc/res_config_sqlite.txt =================================================================== --- doc/res_config_sqlite.txt (revision 82230) +++ doc/res_config_sqlite.txt (working copy) @@ -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); Index: include/asterisk/doxyref.h =================================================================== --- include/asterisk/doxyref.h (revision 82230) +++ include/asterisk/doxyref.h (working copy) @@ -252,6 +252,7 @@ * \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 @@ * \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 + */ Index: configs/res_config_sqlite.conf =================================================================== --- configs/res_config_sqlite.conf (revision 82230) +++ configs/res_config_sqlite.conf (working copy) @@ -9,7 +9,3 @@ ; 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 - Index: res/res_config_sqlite.c =================================================================== --- res/res_config_sqlite.c (revision 82230) +++ res/res_config_sqlite.c (working copy) @@ -5,7 +5,7 @@ * * Written by Richard Braun * - * 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 general. Here are the supported parameters : - * + * *
*
dbfile
*
The absolute path to the SQLite database (the file can be non existent, - * res_sqlite will create it if is has the appropriate rights)
+ * res_config_sqlite will create it if it has the appropriate rights) *
config_table
*
The table used for static configuration
*
cdr_table
*
The table used to store CDR entries (if ommitted, CDR support is * disabled)
*
- * - * 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 - * http://voip-info.org/wiki/view/Asterisk+cmd+MYSQL. - * The main difference is that you cannot choose your database - it's the - * file set in the dbfile 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 show sqlite status 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) \ +MACRO_BEGIN \ + int __error; \ + \ + __error = set_var(&to, #to, from->value); \ + \ + if (__error) { \ + ast_config_destroy(config); \ + unload_config(); \ + return 1; \ + } \ +MACRO_END -#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) - /*! * 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. *
  * 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)
  *	 ...;
  * 
*/ -#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 @@ /*! * Structure sent to the SQLite callback function for RealTime configuration. - * + * * \see add_rt_cfg_entry() */ struct rt_cfg_entry_args { @@ -223,7 +199,7 @@ /*! * 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 @@ /*! * \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 @@ /*! * \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 @@ /*! * \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 @@ /*! * \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 @@ * \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: - * + * * - * + * * 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 @@ /*! * \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 @@ /*! * 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 SELECT * FROM * table WHERE name = '123';. - * + * * \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 @@ /*! * \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 @@ /*! * \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 @@ * \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. UPDATE table SET ... WHERE * keyfield = 'entity';. 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 @@ * \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 @@ 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. DELETE FROM table WHERE * keyfield = 'entity';. 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 @@ * \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 @@ /*! 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 @@ /*! * 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 @@ { .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 @@ /*! 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 @@ /*! * 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 @@ 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 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 @@ 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 @@ } 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 @@ 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 @@ } 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ char *cat_name; size_t i; - args = (struct rt_multi_cfg_entry_args *)arg; + args = arg; cat_name = NULL; /* @@ -1012,7 +997,7 @@ 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 @@ 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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ if (error) { ast_log(LOG_WARNING, "%s\n", errormsg); - ast_free(errormsg); + sqlite_freemem(errormsg); } return rows_num; @@ -1282,9 +1264,9 @@ 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 @@ 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 @@ } 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 @@ if (error) { ast_log(LOG_WARNING, "%s\n", errormsg); - ast_free(errormsg); + sqlite_freemem(errormsg); } return rows_num; @@ -1409,7 +1389,7 @@ 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 @@ dbfile = NULL; config_table = NULL; cdr_table = NULL; - vm_count = 0; error = load_config(); if (error) @@ -1440,7 +1419,7 @@ 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,37 +1427,66 @@ 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) { /* * Unexpected error. */ if (error != SQLITE_ERROR) { ast_log(LOG_ERROR, "%s\n", errormsg); - ast_free(errormsg); + sqlite_freemem(errormsg); 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) + 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; + } + + 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();