#include "asterisk.h"
#include <time.h>
#include <sqlite3.h>
#include "asterisk/paths.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
Go to the source code of this file.
Data Structures | |
struct | sql_values |
struct | values |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | free_config (int reload) |
static int | load_column_config (const char *tmp) |
static int | load_config (int reload) |
static int | load_module (void) |
static int | load_values_config (const char *tmp) |
static int | reload (void) |
static int | unload_module (void) |
static int | write_cdr (struct ast_cdr *cdr) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SQLite3 Custom CDR Module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char * | columns |
static const char | config_file [] = "cdr_sqlite3_custom.conf" |
static sqlite3 * | db = NULL |
static char * | desc = "Customizable SQLite3 CDR Backend" |
static ast_mutex_t | lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) |
static char * | name = "cdr_sqlite3_custom" |
static char | table [80] |
Definition in file cdr_sqlite3_custom.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 361 of file cdr_sqlite3_custom.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 361 of file cdr_sqlite3_custom.c.
static void free_config | ( | int | reload | ) | [static] |
Definition at line 215 of file cdr_sqlite3_custom.c.
References ast_free, AST_LIST_REMOVE_HEAD, columns, and values::list.
00216 { 00217 struct values *value; 00218 00219 if (!reload && db) { 00220 sqlite3_close(db); 00221 db = NULL; 00222 } 00223 00224 if (columns) { 00225 ast_free(columns); 00226 columns = NULL; 00227 } 00228 00229 while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) 00230 ast_free(value); 00231 }
static int load_column_config | ( | const char * | tmp | ) | [static] |
Definition at line 76 of file cdr_sqlite3_custom.c.
References ast_free, ast_log(), ast_str_append(), ast_str_create(), ast_str_set(), ast_strdup, ast_strip(), ast_strlen_zero(), LOG_ERROR, LOG_WARNING, ast_str::str, strsep(), and ast_str::used.
Referenced by load_config().
00077 { 00078 char *col = NULL; 00079 char *cols = NULL, *save = NULL; 00080 char *escaped = NULL; 00081 struct ast_str *column_string = NULL; 00082 00083 if (ast_strlen_zero(tmp)) { 00084 ast_log(LOG_WARNING, "Column names not specified. Module not loaded.\n"); 00085 return -1; 00086 } 00087 if (!(column_string = ast_str_create(1024))) { 00088 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table); 00089 return -1; 00090 } 00091 if (!(save = cols = ast_strdup(tmp))) { 00092 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table); 00093 ast_free(column_string); 00094 return -1; 00095 } 00096 while ((col = strsep(&cols, ","))) { 00097 col = ast_strip(col); 00098 escaped = sqlite3_mprintf("%q", col); 00099 if (!escaped) { 00100 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s.'\n", col, table); 00101 ast_free(column_string); 00102 ast_free(save); 00103 return -1; 00104 } 00105 if (!column_string->used) 00106 ast_str_set(&column_string, 0, "%s", escaped); 00107 else 00108 ast_str_append(&column_string, 0, ",%s", escaped); 00109 sqlite3_free(escaped); 00110 } 00111 if (!(columns = ast_strdup(column_string->str))) { 00112 ast_log(LOG_ERROR, "Out of memory copying columns string for table '%s.'\n", table); 00113 ast_free(column_string); 00114 ast_free(save); 00115 return -1; 00116 } 00117 ast_free(column_string); 00118 ast_free(save); 00119 00120 return 0; 00121 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 158 of file cdr_sqlite3_custom.c.
References ast_config_destroy(), ast_config_load, ast_copy_string(), ast_log(), ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, free_config(), load_column_config(), load_values_config(), and LOG_WARNING.
00159 { 00160 struct ast_config *cfg; 00161 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00162 struct ast_variable *mappingvar; 00163 const char *tmp; 00164 00165 if (!(cfg = ast_config_load(config_file, config_flags))) { 00166 if (reload) 00167 ast_log(LOG_WARNING, "Failed to reload configuration file.\n"); 00168 else 00169 ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n"); 00170 return -1; 00171 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00172 return 0; 00173 00174 if (reload) 00175 free_config(1); 00176 00177 if (!(mappingvar = ast_variable_browse(cfg, "master"))) { 00178 /* Nothing configured */ 00179 ast_config_destroy(cfg); 00180 return -1; 00181 } 00182 00183 /* Mapping must have a table name */ 00184 tmp = ast_variable_retrieve(cfg, "master", "table"); 00185 if (!ast_strlen_zero(tmp)) 00186 ast_copy_string(table, tmp, sizeof(table)); 00187 else { 00188 ast_log(LOG_WARNING, "Table name not specified. Assuming cdr.\n"); 00189 strcpy(table, "cdr"); 00190 } 00191 00192 /* Columns */ 00193 tmp = ast_variable_retrieve(cfg, "master", "columns"); 00194 if (load_column_config(tmp)) { 00195 ast_config_destroy(cfg); 00196 free_config(0); 00197 return -1; 00198 } 00199 00200 /* Values */ 00201 tmp = ast_variable_retrieve(cfg, "master", "values"); 00202 if (load_values_config(tmp)) { 00203 ast_config_destroy(cfg); 00204 free_config(0); 00205 return -1; 00206 } 00207 00208 ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table); 00209 00210 ast_config_destroy(cfg); 00211 00212 return 0; 00213 }
static int load_module | ( | void | ) | [static] |
Definition at line 299 of file cdr_sqlite3_custom.c.
References ast_cdr_register(), ast_config_AST_LOG_DIR, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, free_config(), load_config(), LOG_ERROR, LOG_WARNING, and write_cdr().
00300 { 00301 char *error; 00302 char filename[PATH_MAX]; 00303 int res; 00304 char *sql; 00305 00306 if (load_config(0)) { 00307 return AST_MODULE_LOAD_DECLINE; 00308 } 00309 00310 /* is the database there? */ 00311 snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR); 00312 res = sqlite3_open(filename, &db); 00313 if (res != SQLITE_OK) { 00314 ast_log(LOG_ERROR, "Could not open database %s.\n", filename); 00315 free_config(0); 00316 return AST_MODULE_LOAD_DECLINE; 00317 } 00318 00319 /* is the table there? */ 00320 sql = sqlite3_mprintf("SELECT COUNT(AcctId) FROM %q;", table); 00321 res = sqlite3_exec(db, sql, NULL, NULL, NULL); 00322 sqlite3_free(sql); 00323 if (res != SQLITE_OK) { 00324 /* We don't use %q for the column list here since we already escaped when building it */ 00325 sql = sqlite3_mprintf("CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)", table, columns); 00326 res = sqlite3_exec(db, sql, NULL, NULL, &error); 00327 sqlite3_free(sql); 00328 if (res != SQLITE_OK) { 00329 ast_log(LOG_WARNING, "Unable to create table '%s': %s.\n", table, error); 00330 sqlite3_free(error); 00331 free_config(0); 00332 return AST_MODULE_LOAD_DECLINE; 00333 } 00334 } 00335 00336 res = ast_cdr_register(name, desc, write_cdr); 00337 if (res) { 00338 ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n"); 00339 free_config(0); 00340 return AST_MODULE_LOAD_DECLINE; 00341 } 00342 00343 return AST_MODULE_LOAD_SUCCESS; 00344 }
static int load_values_config | ( | const char * | tmp | ) | [static] |
Definition at line 123 of file cdr_sqlite3_custom.c.
References AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_STANDARD_RAW_ARGS, ast_strdup, ast_strip_quoted(), ast_strlen_zero(), values::list, LOG_ERROR, and LOG_WARNING.
Referenced by load_config().
00124 { 00125 char *vals = NULL, *save = NULL; 00126 struct values *value = NULL; 00127 int i; 00128 AST_DECLARE_APP_ARGS(val, 00129 AST_APP_ARG(ues)[200]; /* More than 200 columns in this CDR? Yeah, right... */ 00130 ); 00131 00132 if (ast_strlen_zero(tmp)) { 00133 ast_log(LOG_WARNING, "Values not specified. Module not loaded.\n"); 00134 return -1; 00135 } 00136 if (!(save = vals = ast_strdup(tmp))) { 00137 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for value '%s'\n", tmp); 00138 return -1; 00139 } 00140 AST_STANDARD_RAW_ARGS(val, vals); 00141 for (i = 0; i < val.argc; i++) { 00142 /* Strip the single quotes off if they are there */ 00143 char *v = ast_strip_quoted(val.ues[i], "'", "'"); 00144 value = ast_calloc(sizeof(char), sizeof(*value) + strlen(v)); 00145 if (!value) { 00146 ast_log(LOG_ERROR, "Out of memory creating entry for value '%s'\n", v); 00147 ast_free(save); 00148 return -1; 00149 } 00150 strcpy(value->expression, v); /* SAFE */ 00151 AST_LIST_INSERT_TAIL(&sql_values, value, list); 00152 } 00153 ast_free(save); 00154 00155 return 0; 00156 }
static int reload | ( | void | ) | [static] |
Definition at line 346 of file cdr_sqlite3_custom.c.
References ast_mutex_lock(), ast_mutex_unlock(), load_config(), and lock.
00347 { 00348 int res = 0; 00349 00350 ast_mutex_lock(&lock); 00351 res = load_config(1); 00352 ast_mutex_unlock(&lock); 00353 00354 return res; 00355 }
static int unload_module | ( | void | ) | [static] |
Definition at line 290 of file cdr_sqlite3_custom.c.
References ast_cdr_unregister(), and free_config().
00291 { 00292 ast_cdr_unregister(name); 00293 00294 free_config(0); 00295 00296 return 0; 00297 }
static int write_cdr | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 233 of file cdr_sqlite3_custom.c.
References ast_debug, ast_free, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_str_append(), ast_str_create(), dummy(), values::expression, values::list, lock, LOG_ERROR, pbx_substitute_variables_helper(), ast_str::str, and ast_str::used.
Referenced by load_module().
00234 { 00235 int res = 0; 00236 char *error = NULL; 00237 char *sql = NULL; 00238 struct ast_channel dummy = { 0, }; 00239 int count = 0; 00240 00241 if (db == NULL) { 00242 /* Should not have loaded, but be failsafe. */ 00243 return 0; 00244 } 00245 00246 ast_mutex_lock(&lock); 00247 00248 { /* Make it obvious that only sql should be used outside of this block */ 00249 char *escaped; 00250 char subst_buf[2048]; 00251 struct values *value; 00252 struct ast_str *value_string = ast_str_create(1024); 00253 dummy.cdr = cdr; 00254 AST_LIST_TRAVERSE(&sql_values, value, list) { 00255 memset(subst_buf, 0, sizeof(subst_buf)); 00256 pbx_substitute_variables_helper(&dummy, value->expression, subst_buf, sizeof(subst_buf) - 1); 00257 escaped = sqlite3_mprintf("%q", subst_buf); 00258 if (!value_string->used) 00259 ast_str_append(&value_string, 0, "'%s'", escaped); 00260 else 00261 ast_str_append(&value_string, 0, ",'%s'", escaped); 00262 sqlite3_free(escaped); 00263 } 00264 sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, value_string->str); 00265 ast_debug(1, "About to log: %s\n", sql); 00266 ast_free(value_string); 00267 } 00268 00269 /* XXX This seems awful arbitrary... */ 00270 for (count = 0; count < 5; count++) { 00271 res = sqlite3_exec(db, sql, NULL, NULL, &error); 00272 if (res != SQLITE_BUSY && res != SQLITE_LOCKED) 00273 break; 00274 usleep(200); 00275 } 00276 00277 if (error) { 00278 ast_log(LOG_ERROR, "%s. SQL: %s.\n", error, sql); 00279 sqlite3_free(error); 00280 } 00281 00282 if (sql) 00283 sqlite3_free(sql); 00284 00285 ast_mutex_unlock(&lock); 00286 00287 return res; 00288 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SQLite3 Custom CDR Module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 361 of file cdr_sqlite3_custom.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 361 of file cdr_sqlite3_custom.c.
char* columns [static] |
const char config_file[] = "cdr_sqlite3_custom.conf" [static] |
Definition at line 58 of file cdr_sqlite3_custom.c.
sqlite3* db = NULL [static] |
Definition at line 62 of file cdr_sqlite3_custom.c.
char* desc = "Customizable SQLite3 CDR Backend" [static] |
Definition at line 60 of file cdr_sqlite3_custom.c.
ast_mutex_t lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static] |
Definition at line 56 of file cdr_sqlite3_custom.c.
char* name = "cdr_sqlite3_custom" [static] |
Definition at line 61 of file cdr_sqlite3_custom.c.
char table[80] [static] |
Definition at line 64 of file cdr_sqlite3_custom.c.