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