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