00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "asterisk.h"
00040
00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 257067 $")
00042
00043 #include <time.h>
00044 #include <sqlite3.h>
00045
00046 #include "asterisk/paths.h"
00047 #include "asterisk/channel.h"
00048 #include "asterisk/cdr.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/pbx.h"
00052 #include "asterisk/utils.h"
00053 #include "asterisk/cli.h"
00054 #include "asterisk/app.h"
00055
00056 AST_MUTEX_DEFINE_STATIC(lock);
00057
00058 static const char config_file[] = "cdr_sqlite3_custom.conf";
00059
00060 static char *desc = "Customizable SQLite3 CDR Backend";
00061 static char *name = "cdr_sqlite3_custom";
00062 static sqlite3 *db = NULL;
00063
00064 static char table[80];
00065 static char *columns;
00066
00067 struct values {
00068 AST_LIST_ENTRY(values) list;
00069 char expression[1];
00070 };
00071
00072 static AST_LIST_HEAD_STATIC(sql_values, values);
00073
00074 static void free_config(int reload);
00075
00076 static int load_column_config(const char *tmp)
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 }
00122
00123 static int load_values_config(const char *tmp)
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];
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
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);
00151 AST_LIST_INSERT_TAIL(&sql_values, value, list);
00152 }
00153 ast_free(save);
00154
00155 return 0;
00156 }
00157
00158 static int load_config(int reload)
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
00179 ast_config_destroy(cfg);
00180 return -1;
00181 }
00182
00183
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
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
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 }
00214
00215 static void free_config(int reload)
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 }
00232
00233 static int write_cdr(struct ast_cdr *cdr)
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
00243 return 0;
00244 }
00245
00246 ast_mutex_lock(&lock);
00247
00248 {
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
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 }
00289
00290 static int unload_module(void)
00291 {
00292 ast_cdr_unregister(name);
00293
00294 free_config(0);
00295
00296 return 0;
00297 }
00298
00299 static int load_module(void)
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
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
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
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 }
00345
00346 static int reload(void)
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 }
00356
00357 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SQLite3 Custom CDR Module",
00358 .load = load_module,
00359 .unload = unload_module,
00360 .reload = reload,
00361 );