54 AST_MUTEX_DEFINE_STATIC(
lock);
56 static const char config_file[] =
"cdr_sqlite3_custom.conf";
58 static const char desc[] =
"Customizable SQLite3 CDR Backend";
59 static const char name[] =
"cdr_sqlite3_custom";
60 static sqlite3 *db = NULL;
62 static char table[80];
64 static int busy_timeout;
73 static void free_config(
int reload);
75 static int load_column_config(
const char *tmp)
78 char *cols = NULL, *save = NULL;
80 struct ast_str *column_string = NULL;
82 if (ast_strlen_zero(tmp)) {
83 ast_log(LOG_WARNING,
"Column names not specified. Module not loaded.\n");
87 ast_log(LOG_ERROR,
"Out of memory creating temporary buffer for column list for table '%s.'\n", table);
91 ast_log(LOG_ERROR,
"Out of memory creating temporary buffer for column list for table '%s.'\n", table);
92 ast_free(column_string);
95 while ((col = strsep(&cols,
","))) {
97 escaped = sqlite3_mprintf(
"%q", col);
99 ast_log(LOG_ERROR,
"Out of memory creating entry for column '%s' in table '%s.'\n", col, table);
100 ast_free(column_string);
105 sqlite3_free(escaped);
108 ast_log(LOG_ERROR,
"Out of memory copying columns string for table '%s.'\n", table);
109 ast_free(column_string);
113 ast_free(column_string);
119 static int load_values_config(
const char *tmp)
121 char *vals = NULL, *save = NULL;
122 struct values *value = NULL;
128 if (ast_strlen_zero(tmp)) {
129 ast_log(LOG_WARNING,
"Values not specified. Module not loaded.\n");
133 ast_log(LOG_ERROR,
"Out of memory creating temporary buffer for value '%s'\n", tmp);
136 AST_STANDARD_RAW_ARGS(
val, vals);
137 for (i = 0; i <
val.argc; i++) {
140 value =
ast_calloc(
sizeof(
char),
sizeof(*value) + strlen(v));
142 ast_log(LOG_ERROR,
"Out of memory creating entry for value '%s'\n", v);
146 strcpy(value->expression, v);
154 static int load_config(
int reload)
161 ast_log(LOG_WARNING,
"Failed to %sload configuration file. %s\n", reload ?
"re" :
"", reload ?
"" :
"Module not activated.");
163 }
else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
171 if (!ast_variable_browse(cfg,
"master")) {
178 if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg,
"master",
"table"))) {
181 ast_log(LOG_WARNING,
"Table name not specified. Assuming cdr.\n");
182 strcpy(table,
"cdr");
186 if ((tmp = ast_variable_retrieve(cfg,
"master",
"busy_timeout")) != NULL) {
187 if (
ast_parse_arg(tmp, PARSE_INT32|PARSE_DEFAULT, &busy_timeout, 1000) != 0) {
188 ast_log(LOG_WARNING,
"Invalid busy_timeout value '%s' specified. Using 1000 instead.\n", tmp);
195 if (load_column_config(ast_variable_retrieve(cfg,
"master",
"columns"))) {
202 if (load_values_config(ast_variable_retrieve(cfg,
"master",
"values"))) {
208 ast_verb(4,
"cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);
215 static void free_config(
int reload)
234 static int write_cdr(
struct ast_cdr *cdr)
245 ast_mutex_lock(&
lock);
249 char subst_buf[2048];
256 ast_log(LOG_ERROR,
"Unable to allocate channel for variable subsitution.\n");
257 ast_free(value_string);
258 ast_mutex_unlock(&
lock);
263 pbx_substitute_variables_helper(dummy, value->expression, subst_buf,
sizeof(subst_buf) - 1);
264 escaped = sqlite3_mprintf(
"%q", subst_buf);
266 sqlite3_free(escaped);
268 sql = sqlite3_mprintf(
"INSERT INTO %q (%s) VALUES (%s)", table,
columns,
ast_str_buffer(value_string));
271 ast_free(value_string);
274 if (sqlite3_exec(db, sql, NULL, NULL, &error) != SQLITE_OK) {
275 ast_log(LOG_ERROR,
"%s. SQL: %s.\n", error, sql);
283 ast_mutex_unlock(&
lock);
288 static int unload_module(
void)
299 static int load_module(
void)
302 char filename[PATH_MAX];
306 if (load_config(0)) {
311 snprintf(filename,
sizeof(filename),
"%s/master.db", ast_config_AST_LOG_DIR);
312 res = sqlite3_open(filename, &db);
313 if (res != SQLITE_OK) {
314 ast_log(LOG_ERROR,
"Could not open database %s.\n", filename);
318 sqlite3_busy_timeout(db, busy_timeout);
320 sql = sqlite3_mprintf(
"SELECT COUNT(AcctId) FROM %q;", table);
321 res = sqlite3_exec(db, sql, NULL, NULL, NULL);
323 if (res != SQLITE_OK) {
325 sql = sqlite3_mprintf(
"CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)", table,
columns);
326 res = sqlite3_exec(db, sql, NULL, NULL, &error);
328 if (res != SQLITE_OK) {
329 ast_log(LOG_WARNING,
"Unable to create table '%s': %s.\n", table, error);
338 ast_log(LOG_ERROR,
"Unable to register custom SQLite3 CDR handling\n");
346 static int reload(
void)
350 ast_mutex_lock(&
lock);
351 res = load_config(1);
352 ast_mutex_unlock(&
lock);
357 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"SQLite3 Custom CDR Module",
358 .support_level = AST_MODULE_SUPPORT_EXTENDED,
360 .unload = unload_module,
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
#define ast_channel_unref(c)
Decrease channel reference count.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
struct ast_cdr * ast_cdr_dup(struct ast_cdr *cdr)
Duplicate a public CDR.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_strdup(str)
A wrapper for strdup()
Configuration File Parser.
static const char config_file[]
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
#define ast_config_load(filename, flags)
Load a config file.
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
#define ast_dummy_channel_alloc()
Create a fake channel structure.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Core PBX routines and definitions.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Responsible for call detail data.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Support for dynamic strings.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define ast_calloc(num, len)
A wrapper for calloc()
Module has failed to load, may be in an inconsistent state.
Structure used to handle boolean flags.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define AST_APP_ARG(name)
Define an application argument.