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: 337973 $")
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 struct ast_variable *mappingvar;
00160 const char *tmp;
00161
00162 if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
00163 ast_log(LOG_WARNING, "Failed to %sload configuration file. %s\n", reload ? "re" : "", reload ? "" : "Module not activated.");
00164 return -1;
00165 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00166 return 0;
00167 }
00168
00169 if (reload) {
00170 free_config(1);
00171 }
00172
00173 if (!(mappingvar = ast_variable_browse(cfg, "master"))) {
00174
00175 ast_config_destroy(cfg);
00176 return -1;
00177 }
00178
00179
00180 if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "master", "table"))) {
00181 ast_copy_string(table, tmp, sizeof(table));
00182 } else {
00183 ast_log(LOG_WARNING, "Table name not specified. Assuming cdr.\n");
00184 strcpy(table, "cdr");
00185 }
00186
00187
00188 if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) {
00189 ast_config_destroy(cfg);
00190 free_config(0);
00191 return -1;
00192 }
00193
00194
00195 if (load_values_config(ast_variable_retrieve(cfg, "master", "values"))) {
00196 ast_config_destroy(cfg);
00197 free_config(0);
00198 return -1;
00199 }
00200
00201 ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);
00202
00203 ast_config_destroy(cfg);
00204
00205 return 0;
00206 }
00207
00208 static void free_config(int reload)
00209 {
00210 struct values *value;
00211
00212 if (!reload && db) {
00213 sqlite3_close(db);
00214 db = NULL;
00215 }
00216
00217 if (columns) {
00218 ast_free(columns);
00219 columns = NULL;
00220 }
00221
00222 while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) {
00223 ast_free(value);
00224 }
00225 }
00226
00227 static int write_cdr(struct ast_cdr *cdr)
00228 {
00229 int res = 0;
00230 char *error = NULL;
00231 char *sql = NULL;
00232 int count = 0;
00233
00234 if (db == NULL) {
00235
00236 return 0;
00237 }
00238
00239 ast_mutex_lock(&lock);
00240
00241 {
00242 char *escaped;
00243 char subst_buf[2048];
00244 struct values *value;
00245 struct ast_channel *dummy;
00246 struct ast_str *value_string = ast_str_create(1024);
00247
00248 dummy = ast_dummy_channel_alloc();
00249 if (!dummy) {
00250 ast_log(LOG_ERROR, "Unable to allocate channel for variable subsitution.\n");
00251 ast_free(value_string);
00252 ast_mutex_unlock(&lock);
00253 return 0;
00254 }
00255 dummy->cdr = ast_cdr_dup(cdr);
00256 AST_LIST_TRAVERSE(&sql_values, value, list) {
00257 pbx_substitute_variables_helper(dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
00258 escaped = sqlite3_mprintf("%q", subst_buf);
00259 ast_str_append(&value_string, 0, "%s'%s'", ast_str_strlen(value_string) ? "," : "", escaped);
00260 sqlite3_free(escaped);
00261 }
00262 sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, ast_str_buffer(value_string));
00263 ast_debug(1, "About to log: %s\n", sql);
00264 ast_channel_unref(dummy);
00265 ast_free(value_string);
00266 }
00267
00268
00269 for (count = 0; count < 5; count++) {
00270 res = sqlite3_exec(db, sql, NULL, NULL, &error);
00271 if (res != SQLITE_BUSY && res != SQLITE_LOCKED) {
00272 break;
00273 }
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
00286 ast_mutex_unlock(&lock);
00287
00288 return res;
00289 }
00290
00291 static int unload_module(void)
00292 {
00293 ast_cdr_unregister(name);
00294
00295 free_config(0);
00296
00297 return 0;
00298 }
00299
00300 static int load_module(void)
00301 {
00302 char *error;
00303 char filename[PATH_MAX];
00304 int res;
00305 char *sql;
00306
00307 if (load_config(0)) {
00308 return AST_MODULE_LOAD_DECLINE;
00309 }
00310
00311
00312 snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR);
00313 res = sqlite3_open(filename, &db);
00314 if (res != SQLITE_OK) {
00315 ast_log(LOG_ERROR, "Could not open database %s.\n", filename);
00316 free_config(0);
00317 return AST_MODULE_LOAD_DECLINE;
00318 }
00319
00320
00321 sql = sqlite3_mprintf("SELECT COUNT(AcctId) FROM %q;", table);
00322 res = sqlite3_exec(db, sql, NULL, NULL, NULL);
00323 sqlite3_free(sql);
00324 if (res != SQLITE_OK) {
00325
00326 sql = sqlite3_mprintf("CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)", table, columns);
00327 res = sqlite3_exec(db, sql, NULL, NULL, &error);
00328 sqlite3_free(sql);
00329 if (res != SQLITE_OK) {
00330 ast_log(LOG_WARNING, "Unable to create table '%s': %s.\n", table, error);
00331 sqlite3_free(error);
00332 free_config(0);
00333 return AST_MODULE_LOAD_DECLINE;
00334 }
00335 }
00336
00337 res = ast_cdr_register(name, desc, write_cdr);
00338 if (res) {
00339 ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n");
00340 free_config(0);
00341 return AST_MODULE_LOAD_DECLINE;
00342 }
00343
00344 return AST_MODULE_LOAD_SUCCESS;
00345 }
00346
00347 static int reload(void)
00348 {
00349 int res = 0;
00350
00351 ast_mutex_lock(&lock);
00352 res = load_config(1);
00353 ast_mutex_unlock(&lock);
00354
00355 return res;
00356 }
00357
00358 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite3 Custom CDR Module",
00359 .load = load_module,
00360 .unload = unload_module,
00361 .reload = reload,
00362 .load_pri = AST_MODPRI_CDR_DRIVER,
00363 );