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: 202471 $")
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
00055 AST_MUTEX_DEFINE_STATIC(lock);
00056
00057 static const char config_file[] = "cdr_sqlite3_custom.conf";
00058
00059 static char *desc = "Customizable SQLite3 CDR Backend";
00060 static char *name = "cdr_sqlite3_custom";
00061 static sqlite3 *db = NULL;
00062
00063 static char table[80];
00064 static char *columns;
00065
00066 struct values {
00067 char *expression;
00068 AST_LIST_ENTRY(values) list;
00069 };
00070
00071 static AST_LIST_HEAD_STATIC(sql_values, values);
00072
00073 static void free_config(void);
00074
00075 static int load_column_config(const char *tmp)
00076 {
00077 char *col = NULL;
00078 char *cols = NULL, *save = NULL;
00079 char *escaped = NULL;
00080 struct ast_str *column_string = NULL;
00081
00082 if (ast_strlen_zero(tmp)) {
00083 ast_log(LOG_WARNING, "Column names not specified. Module not loaded.\n");
00084 return -1;
00085 }
00086 if (!(column_string = ast_str_create(1024))) {
00087 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table);
00088 return -1;
00089 }
00090 if (!(save = cols = ast_strdup(tmp))) {
00091 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for column list for table '%s.'\n", table);
00092 ast_free(column_string);
00093 return -1;
00094 }
00095 while ((col = strsep(&cols, ","))) {
00096 col = ast_strip(col);
00097 escaped = sqlite3_mprintf("%q", col);
00098 if (!escaped) {
00099 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s.'\n", col, table);
00100 ast_free(column_string);
00101 ast_free(save);
00102 return -1;
00103 }
00104 if (!column_string->used)
00105 ast_str_set(&column_string, 0, "%s", escaped);
00106 else
00107 ast_str_append(&column_string, 0, ",%s", escaped);
00108 sqlite3_free(escaped);
00109 }
00110 if (!(columns = ast_strdup(column_string->str))) {
00111 ast_log(LOG_ERROR, "Out of memory copying columns string for table '%s.'\n", table);
00112 ast_free(column_string);
00113 ast_free(save);
00114 return -1;
00115 }
00116 ast_free(column_string);
00117 ast_free(save);
00118
00119 return 0;
00120 }
00121
00122 static int load_values_config(const char *tmp)
00123 {
00124 char *val = NULL;
00125 char *vals = NULL, *save = NULL;
00126 struct values *value = NULL;
00127
00128 if (ast_strlen_zero(tmp)) {
00129 ast_log(LOG_WARNING, "Values not specified. Module not loaded.\n");
00130 return -1;
00131 }
00132 if (!(save = vals = ast_strdup(tmp))) {
00133 ast_log(LOG_ERROR, "Out of memory creating temporary buffer for value '%s'\n", tmp);
00134 return -1;
00135 }
00136 while ((val = strsep(&vals, ","))) {
00137
00138 val = ast_strip_quoted(val, "'", "'");
00139 value = ast_calloc(sizeof(char), sizeof(*value) + strlen(val) + 1);
00140 if (!value) {
00141 ast_log(LOG_ERROR, "Out of memory creating entry for value '%s'\n", val);
00142 ast_free(save);
00143 return -1;
00144 }
00145 value->expression = (char *) value + sizeof(*value);
00146 ast_copy_string(value->expression, val, strlen(val) + 1);
00147 AST_LIST_INSERT_TAIL(&sql_values, value, list);
00148 }
00149 ast_free(save);
00150
00151 return 0;
00152 }
00153
00154 static int load_config(int reload)
00155 {
00156 struct ast_config *cfg;
00157 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00158 struct ast_variable *mappingvar;
00159 const char *tmp;
00160
00161 if (!(cfg = ast_config_load(config_file, config_flags))) {
00162 if (reload)
00163 ast_log(LOG_WARNING, "Failed to reload configuration file.\n");
00164 else
00165 ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
00166 return -1;
00167 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00168 return 0;
00169
00170 if (reload)
00171 free_config();
00172
00173 if (!(mappingvar = ast_variable_browse(cfg, "master"))) {
00174
00175 ast_config_destroy(cfg);
00176 return -1;
00177 }
00178
00179
00180 tmp = ast_variable_retrieve(cfg, "master", "table");
00181 if (!ast_strlen_zero(tmp))
00182 ast_copy_string(table, tmp, sizeof(table));
00183 else {
00184 ast_log(LOG_WARNING, "Table name not specified. Assuming cdr.\n");
00185 strcpy(table, "cdr");
00186 }
00187
00188
00189 tmp = ast_variable_retrieve(cfg, "master", "columns");
00190 if (load_column_config(tmp)) {
00191 ast_config_destroy(cfg);
00192 free_config();
00193 return -1;
00194 }
00195
00196
00197 tmp = ast_variable_retrieve(cfg, "master", "values");
00198 if (load_values_config(tmp)) {
00199 ast_config_destroy(cfg);
00200 free_config();
00201 return -1;
00202 }
00203
00204 ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);
00205
00206 ast_config_destroy(cfg);
00207
00208 return 0;
00209 }
00210
00211 static void free_config(void)
00212 {
00213 struct values *value;
00214
00215 if (db) {
00216 sqlite3_close(db);
00217 db = NULL;
00218 }
00219
00220 if (columns) {
00221 ast_free(columns);
00222 columns = NULL;
00223 }
00224
00225 while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list)))
00226 ast_free(value);
00227 }
00228
00229 static int sqlite3_log(struct ast_cdr *cdr)
00230 {
00231 int res = 0;
00232 char *error = NULL;
00233 char *sql = NULL;
00234 struct ast_channel dummy = { 0, };
00235 int count = 0;
00236
00237 if (db == NULL) {
00238
00239 return 0;
00240 }
00241
00242 ast_mutex_lock(&lock);
00243
00244 {
00245 char *escaped;
00246 char subst_buf[2048];
00247 struct values *value;
00248 struct ast_str *value_string = ast_str_create(1024);
00249 dummy.cdr = cdr;
00250 AST_LIST_TRAVERSE(&sql_values, value, list) {
00251 memset(subst_buf, 0, sizeof(subst_buf));
00252 pbx_substitute_variables_helper(&dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
00253 escaped = sqlite3_mprintf("%q", subst_buf);
00254 if (!value_string->used)
00255 ast_str_append(&value_string, 0, "'%s'", escaped);
00256 else
00257 ast_str_append(&value_string, 0, ",'%s'", escaped);
00258 sqlite3_free(escaped);
00259 }
00260 sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, value_string->str);
00261 ast_debug(1, "About to log: %s\n", sql);
00262 ast_free(value_string);
00263 }
00264
00265
00266 for (count = 0; count < 5; count++) {
00267 res = sqlite3_exec(db, sql, NULL, NULL, &error);
00268 if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
00269 break;
00270 usleep(200);
00271 }
00272
00273 if (error) {
00274 ast_log(LOG_ERROR, "%s. SQL: %s.\n", error, sql);
00275 sqlite3_free(error);
00276 }
00277
00278 if (sql)
00279 sqlite3_free(sql);
00280
00281 ast_mutex_unlock(&lock);
00282
00283 return res;
00284 }
00285
00286 static int unload_module(void)
00287 {
00288 ast_cdr_unregister(name);
00289
00290 free_config();
00291
00292 return 0;
00293 }
00294
00295 static int load_module(void)
00296 {
00297 char *error;
00298 char filename[PATH_MAX];
00299 int res;
00300 char *sql;
00301
00302 if (load_config(0)) {
00303 return AST_MODULE_LOAD_DECLINE;
00304 }
00305
00306
00307 snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR);
00308 res = sqlite3_open(filename, &db);
00309 if (res != SQLITE_OK) {
00310 ast_log(LOG_ERROR, "Could not open database %s.\n", filename);
00311 free_config();
00312 return AST_MODULE_LOAD_DECLINE;
00313 }
00314
00315
00316 sql = sqlite3_mprintf("SELECT COUNT(AcctId) FROM %q;", table);
00317 res = sqlite3_exec(db, sql, NULL, NULL, NULL);
00318 sqlite3_free(sql);
00319 if (res != SQLITE_OK) {
00320
00321 sql = sqlite3_mprintf("CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)", table, columns);
00322 res = sqlite3_exec(db, sql, NULL, NULL, &error);
00323 sqlite3_free(sql);
00324 if (res != SQLITE_OK) {
00325 ast_log(LOG_WARNING, "Unable to create table '%s': %s.\n", table, error);
00326 sqlite3_free(error);
00327 free_config();
00328 return AST_MODULE_LOAD_DECLINE;
00329 }
00330 }
00331
00332 res = ast_cdr_register(name, desc, sqlite3_log);
00333 if (res) {
00334 ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n");
00335 free_config();
00336 return AST_MODULE_LOAD_DECLINE;
00337 }
00338
00339 return AST_MODULE_LOAD_SUCCESS;
00340 }
00341
00342 static int reload(void)
00343 {
00344 int res = 0;
00345
00346 ast_mutex_lock(&lock);
00347 res = load_config(1);
00348 ast_mutex_unlock(&lock);
00349
00350 return res;
00351 }
00352
00353 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SQLite3 Custom CDR Module",
00354 .load = load_module,
00355 .unload = unload_module,
00356 .reload = reload,
00357 );