49 #define CSV_LOG_DIR "/cdr-csv"
50 #define CSV_MASTER "/Master.csv"
52 #define DATE_FORMAT "%Y-%m-%d %T"
54 static int usegmtime = 0;
55 static int accountlogs = 1;
56 static int loguniqueid = 0;
57 static int loguserfield = 0;
58 static int loaded = 0;
59 static int newcdrcolumns = 0;
60 static const char config[] =
"cdr.conf";
61 static char file_csv_master[PATH_MAX];
94 static char *name =
"csv";
96 AST_MUTEX_DEFINE_STATIC(f_lock);
98 static int load_config(
int reload)
104 if (!(cfg =
ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
105 ast_log(LOG_WARNING,
"unable to load config: %s\n", config);
107 }
else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
117 if (!(v = ast_variable_browse(cfg,
"csv"))) {
123 ast_mutex_lock(&f_lock);
124 snprintf(file_csv_master,
sizeof(file_csv_master),
125 "%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
126 ast_mutex_unlock(&f_lock);
128 for (; v; v = v->
next) {
129 if (!strcasecmp(v->
name,
"usegmtime")) {
131 }
else if (!strcasecmp(v->
name,
"accountlogs")) {
134 }
else if (!strcasecmp(v->
name,
"loguniqueid")) {
136 }
else if (!strcasecmp(v->
name,
"loguserfield")) {
138 }
else if (!strcasecmp(v->
name,
"newcdrcolumns")) {
147 static int append_string(
char *buf,
const char *s,
size_t bufsize)
149 int pos = strlen(buf), spos = 0, error = -1;
151 if (pos >= bufsize - 4)
156 while(pos < bufsize - 3) {
163 buf[pos++] = s[spos];
174 static int append_int(
char *buf,
int s,
size_t bufsize)
177 int pos = strlen(buf);
179 snprintf(tmp,
sizeof(tmp),
"%d", s);
181 if (pos + strlen(tmp) > bufsize - 3)
184 strncat(buf, tmp, bufsize - strlen(buf) - 1);
192 static int append_date(
char *buf,
struct timeval when,
size_t bufsize)
197 if (strlen(buf) > bufsize - 3)
201 strncat(buf,
",", bufsize - strlen(buf) - 1);
208 return append_string(buf, tmp, bufsize);
211 static int build_csv_record(
char *buf,
size_t bufsize,
struct ast_cdr *cdr)
218 append_string(buf, cdr->
src, bufsize);
220 append_string(buf, cdr->
dst, bufsize);
222 append_string(buf, cdr->
dcontext, bufsize);
224 append_string(buf, cdr->
clid, bufsize);
226 append_string(buf, cdr->channel, bufsize);
230 append_string(buf, cdr->
lastapp, bufsize);
232 append_string(buf, cdr->
lastdata, bufsize);
234 append_date(buf, cdr->start, bufsize);
236 append_date(buf, cdr->answer, bufsize);
238 append_date(buf, cdr->end, bufsize);
240 append_int(buf, cdr->
duration, bufsize);
242 append_int(buf, cdr->
billsec, bufsize);
249 append_string(buf, cdr->
uniqueid, bufsize);
252 append_string(buf, cdr->
userfield, bufsize);
255 append_string(buf, cdr->
linkedid, bufsize);
256 append_int(buf, cdr->
sequence, bufsize);
259 if (strlen(buf) < bufsize - 5) {
261 buf[strlen(buf) - 1] =
'\0';
262 strncat(buf,
"\n", bufsize - strlen(buf) - 1);
268 static int writefile(
char *s,
char *file_path)
274 if (!(f = fopen(file_path,
"a"))) {
275 ast_log(LOG_ERROR,
"Unable to open file %s : %s\n", file_path, strerror(errno));
286 static int writefile_account(
char *s,
char *acc)
288 char file_account[PATH_MAX];
289 if (strchr(acc,
'/') || (acc[0] ==
'.')) {
290 ast_log(LOG_WARNING,
"Account code '%s' insecure for writing file\n", acc);
293 snprintf(file_account,
sizeof(file_account),
"%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
294 return writefile(s, file_account);
297 static int csv_log(
struct ast_cdr *cdr)
301 if (build_csv_record(buf,
sizeof(buf), cdr)) {
302 ast_log(LOG_WARNING,
"Unable to create CSV record in %d bytes. CDR not recorded!\n", (
int)
sizeof(buf));
306 ast_mutex_lock(&f_lock);
307 if (writefile(buf, file_csv_master))
308 ast_log(LOG_WARNING,
"Unable to write CSV record to master '%s' : %s\n", file_csv_master, strerror(errno));
310 if (accountlogs && !ast_strlen_zero(cdr->
accountcode)) {
312 ast_log(LOG_WARNING,
"Unable to write CSV record to account file '%s' : %s\n", cdr->
accountcode, strerror(errno));
314 ast_mutex_unlock(&f_lock);
318 static int unload_module(
void)
328 static int load_module(
void)
332 if (!load_config(0)) {
337 ast_log(LOG_ERROR,
"Unable to register CSV CDR handling\n");
344 static int reload(
void)
346 if (load_config(1)) {
350 ast_log(LOG_WARNING,
"No [csv] section in cdr.conf. Unregistering backend.\n");
357 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"Comma Separated Values CDR Backend",
358 .support_level = AST_MODULE_SUPPORT_EXTENDED,
360 .unload = unload_module,
struct ast_variable * next
char accountcode[AST_MAX_ACCOUNT_CODE]
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
char dstchannel[AST_MAX_EXTENSION]
char dcontext[AST_MAX_EXTENSION]
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Structure for variables, used for configurations and for channel variables.
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
char lastdata[AST_MAX_EXTENSION]
Configuration File Parser.
#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.
char linkedid[AST_MAX_UNIQUEID]
char uniqueid[AST_MAX_UNIQUEID]
char dst[AST_MAX_EXTENSION]
Responsible for call detail data.
char lastapp[AST_MAX_EXTENSION]
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Module has failed to load, may be in an inconsistent state.
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Structure used to handle boolean flags.
char src[AST_MAX_EXTENSION]
char peeraccount[AST_MAX_ACCOUNT_CODE]
char clid[AST_MAX_EXTENSION]
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.
char userfield[AST_MAX_USER_FIELD]