cdr_csv.c File Reference

Comma Separated Value CDR records. More...

#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"

Include dependency graph for cdr_csv.c:

Go to the source code of this file.

Defines

#define CSV_LOG_DIR   "/cdr-csv"
#define CSV_MASTER   "/Master.csv"
#define DATE_FORMAT   "%Y-%m-%d %T"

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int append_date (char *buf, struct timeval when, size_t bufsize)
static int append_int (char *buf, int s, size_t bufsize)
static int append_string (char *buf, const char *s, size_t bufsize)
static int build_csv_record (char *buf, size_t bufsize, struct ast_cdr *cdr)
static int csv_log (struct ast_cdr *cdr)
static int load_config (int reload)
static int load_module (void)
static int reload (void)
static int unload_module (void)
static int writefile (char *s, char *acc)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Comma Separated Values CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, }
static int accountlogs = 1
static ast_mutex_t acf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static struct ast_module_infoast_module_info = &__mod_info
static const char config [] = "cdr.conf"
static int loaded = 0
static int loguniqueid = 0
static int loguserfield = 0
static ast_mutex_t mf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static char * name = "csv"
static int usegmtime = 0


Detailed Description

Comma Separated Value CDR records.

Author:
Mark Spencer <markster@digium.com>

Definition in file cdr_csv.c.


Define Documentation

#define CSV_LOG_DIR   "/cdr-csv"

Definition at line 51 of file cdr_csv.c.

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 52 of file cdr_csv.c.

Referenced by csv_log().

#define DATE_FORMAT   "%Y-%m-%d %T"

Definition at line 54 of file cdr_csv.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 361 of file cdr_csv.c.

static void __unreg_module ( void   )  [static]

Definition at line 361 of file cdr_csv.c.

static int append_date ( char *  buf,
struct timeval  when,
size_t  bufsize 
) [static]

Definition at line 183 of file cdr_csv.c.

References append_string(), ast_localtime(), ast_strftime(), ast_tvzero(), DATE_FORMAT, NULL, and tmp().

Referenced by build_csv_record().

00184 {
00185    char tmp[80] = "";
00186    struct ast_tm tm;
00187 
00188    if (strlen(buf) > bufsize - 3)
00189       return -1;
00190 
00191    if (ast_tvzero(when)) {
00192       strncat(buf, ",", bufsize - strlen(buf) - 1);
00193       return 0;
00194    }
00195 
00196    ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL);
00197    ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm);
00198 
00199    return append_string(buf, tmp, bufsize);
00200 }

static int append_int ( char *  buf,
int  s,
size_t  bufsize 
) [static]

Definition at line 165 of file cdr_csv.c.

References tmp().

Referenced by build_csv_record().

00166 {
00167    char tmp[32];
00168    int pos = strlen(buf);
00169 
00170    snprintf(tmp, sizeof(tmp), "%d", s);
00171 
00172    if (pos + strlen(tmp) > bufsize - 3)
00173       return -1;
00174 
00175    strncat(buf, tmp, bufsize - strlen(buf) - 1);
00176    pos = strlen(buf);
00177    buf[pos++] = ',';
00178    buf[pos++] = '\0';
00179 
00180    return 0;
00181 }

static int append_string ( char *  buf,
const char *  s,
size_t  bufsize 
) [static]

Definition at line 138 of file cdr_csv.c.

References error().

Referenced by append_date(), and build_csv_record().

00139 {
00140    int pos = strlen(buf), spos = 0, error = -1;
00141 
00142    if (pos >= bufsize - 4)
00143       return -1;
00144 
00145    buf[pos++] = '\"';
00146 
00147    while(pos < bufsize - 3) {
00148       if (!s[spos]) {
00149          error = 0;
00150          break;
00151       }
00152       if (s[spos] == '\"')
00153          buf[pos++] = '\"';
00154       buf[pos++] = s[spos];
00155       spos++;
00156    }
00157 
00158    buf[pos++] = '\"';
00159    buf[pos++] = ',';
00160    buf[pos++] = '\0';
00161 
00162    return error;
00163 }

static int build_csv_record ( char *  buf,
size_t  bufsize,
struct ast_cdr cdr 
) [static]

Definition at line 202 of file cdr_csv.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, append_date(), append_int(), append_string(), ast_cdr_disp2str(), ast_channel_amaflags2string(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by csv_log().

00203 {
00204 
00205    buf[0] = '\0';
00206    /* Account code */
00207    append_string(buf, cdr->accountcode, bufsize);
00208    /* Source */
00209    append_string(buf, cdr->src, bufsize);
00210    /* Destination */
00211    append_string(buf, cdr->dst, bufsize);
00212    /* Destination context */
00213    append_string(buf, cdr->dcontext, bufsize);
00214    /* Caller*ID */
00215    append_string(buf, cdr->clid, bufsize);
00216    /* Channel */
00217    append_string(buf, cdr->channel, bufsize);
00218    /* Destination Channel */
00219    append_string(buf, cdr->dstchannel, bufsize);
00220    /* Last Application */
00221    append_string(buf, cdr->lastapp, bufsize);
00222    /* Last Data */
00223    append_string(buf, cdr->lastdata, bufsize);
00224    /* Start Time */
00225    append_date(buf, cdr->start, bufsize);
00226    /* Answer Time */
00227    append_date(buf, cdr->answer, bufsize);
00228    /* End Time */
00229    append_date(buf, cdr->end, bufsize);
00230    /* Duration */
00231    append_int(buf, cdr->duration, bufsize);
00232    /* Billable seconds */
00233    append_int(buf, cdr->billsec, bufsize);
00234    /* Disposition */
00235    append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
00236    /* AMA Flags */
00237    append_string(buf, ast_channel_amaflags2string(cdr->amaflags), bufsize);
00238    /* Unique ID */
00239    if (loguniqueid)
00240       append_string(buf, cdr->uniqueid, bufsize);
00241    /* append the user field */
00242    if(loguserfield)
00243       append_string(buf, cdr->userfield,bufsize);
00244    /* If we hit the end of our buffer, log an error */
00245    if (strlen(buf) < bufsize - 5) {
00246       /* Trim off trailing comma */
00247       buf[strlen(buf) - 1] = '\0';
00248       strncat(buf, "\n", bufsize - strlen(buf) - 1);
00249       return 0;
00250    }
00251    return -1;
00252 }

static int csv_log ( struct ast_cdr cdr  )  [static]

Definition at line 281 of file cdr_csv.c.

References ast_cdr::accountcode, ast_config_AST_LOG_DIR, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero, buf, build_csv_record(), CSV_LOG_DIR, CSV_MASTER, errno, LOG_ERROR, LOG_WARNING, mf_lock, NULL, and writefile().

Referenced by load_module().

00282 {
00283    FILE *mf = NULL;
00284    /* Make sure we have a big enough buf */
00285    char buf[1024];
00286    char csvmaster[PATH_MAX];
00287    snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
00288    if (build_csv_record(buf, sizeof(buf), cdr)) {
00289       ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
00290       return 0;
00291    }
00292 
00293    /* because of the absolutely unconditional need for the
00294       highest reliability possible in writing billing records,
00295       we open write and close the log file each time */
00296    ast_mutex_lock(&mf_lock);
00297    if ((mf = fopen(csvmaster, "a"))) {
00298       fputs(buf, mf);
00299       fflush(mf); /* be particularly anal here */
00300       fclose(mf);
00301       mf = NULL;
00302       ast_mutex_unlock(&mf_lock);
00303    } else {
00304       ast_mutex_unlock(&mf_lock);
00305       ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
00306    }
00307 
00308    if (accountlogs && !ast_strlen_zero(cdr->accountcode)) {
00309       if (writefile(buf, cdr->accountcode))
00310          ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
00311    }
00312 
00313    return 0;
00314 }

static int load_config ( int  reload  )  [static]

Definition at line 99 of file cdr_csv.c.

References ast_config_destroy(), ast_config_load, ast_log, ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, ast_variable::name, ast_variable::next, and ast_variable::value.

00100 {
00101    struct ast_config *cfg;
00102    struct ast_variable *v;
00103    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00104 
00105    if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00106       ast_log(LOG_WARNING, "unable to load config: %s\n", config);
00107       return 0;
00108    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00109       return 1;
00110    }
00111 
00112    accountlogs = 1;
00113    usegmtime = 0;
00114    loguniqueid = 0;
00115    loguserfield = 0;
00116 
00117    if (!(v = ast_variable_browse(cfg, "csv"))) {
00118       ast_config_destroy(cfg);
00119       return 0;
00120    }
00121 
00122    for (; v; v = v->next) {
00123       if (!strcasecmp(v->name, "usegmtime")) {
00124          usegmtime = ast_true(v->value);
00125       } else if (!strcasecmp(v->name, "accountlogs")) {
00126          /* Turn on/off separate files per accountcode. Default is on (as before) */
00127          accountlogs = ast_true(v->value);
00128       } else if (!strcasecmp(v->name, "loguniqueid")) {
00129          loguniqueid = ast_true(v->value);
00130       } else if (!strcasecmp(v->name, "loguserfield")) {
00131          loguserfield = ast_true(v->value);
00132       }
00133    }
00134    ast_config_destroy(cfg);
00135    return 1;
00136 }

static int load_module ( void   )  [static]

Definition at line 326 of file cdr_csv.c.

References ast_cdr_register(), ast_log, AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.

00327 {
00328    int res;
00329 
00330    if (!load_config(0)) {
00331       return AST_MODULE_LOAD_DECLINE;
00332    }
00333 
00334    if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) {
00335       ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n");
00336    } else {
00337       loaded = 1;
00338    }
00339    return res;
00340 }

static int reload ( void   )  [static]

Definition at line 342 of file cdr_csv.c.

References ast_cdr_unregister(), ast_log, load_config(), and LOG_WARNING.

00343 {
00344    if (load_config(1)) {
00345       loaded = 1;
00346    } else {
00347       loaded = 0;
00348       ast_log(LOG_WARNING, "No [csv] section in cdr.conf.  Unregistering backend.\n");
00349       ast_cdr_unregister(name);
00350    }
00351 
00352    return 0;
00353 }

static int unload_module ( void   )  [static]

Definition at line 316 of file cdr_csv.c.

References ast_cdr_unregister().

00317 {
00318    if (ast_cdr_unregister(name)) {
00319       return -1;
00320    }
00321 
00322    loaded = 0;
00323    return 0;
00324 }

static int writefile ( char *  s,
char *  acc 
) [static]

Definition at line 254 of file cdr_csv.c.

References acf_lock, ast_config_AST_LOG_DIR, ast_log, ast_mutex_lock, ast_mutex_unlock, CSV_LOG_DIR, errno, f, LOG_ERROR, LOG_WARNING, and tmp().

Referenced by csv_log().

00255 {
00256    char tmp[PATH_MAX];
00257    FILE *f;
00258 
00259    if (strchr(acc, '/') || (acc[0] == '.')) {
00260       ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
00261       return -1;
00262    }
00263 
00264    snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
00265 
00266    ast_mutex_lock(&acf_lock);
00267    if (!(f = fopen(tmp, "a"))) {
00268       ast_mutex_unlock(&acf_lock);
00269       ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno));
00270       return -1;
00271    }
00272    fputs(s, f);
00273    fflush(f);
00274    fclose(f);
00275    ast_mutex_unlock(&acf_lock);
00276 
00277    return 0;
00278 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Comma Separated Values CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static]

Definition at line 361 of file cdr_csv.c.

int accountlogs = 1 [static]

Definition at line 57 of file cdr_csv.c.

ast_mutex_t acf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 97 of file cdr_csv.c.

Referenced by writefile().

Definition at line 361 of file cdr_csv.c.

const char config[] = "cdr.conf" [static]

Definition at line 61 of file cdr_csv.c.

int loaded = 0 [static]

Definition at line 60 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 58 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 59 of file cdr_csv.c.

ast_mutex_t mf_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 96 of file cdr_csv.c.

Referenced by csv_log().

char* name = "csv" [static]

Definition at line 94 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 56 of file cdr_csv.c.

Referenced by load_config().


Generated on Thu Apr 16 06:29:23 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6