Index: cdr.c =================================================================== RCS file: /usr/cvsroot/asterisk/cdr.c,v retrieving revision 1.30 diff -u -r1.30 cdr.c --- cdr.c 21 Jan 2005 07:06:24 -0000 1.30 +++ cdr.c 26 Jan 2005 18:09:34 -0000 @@ -35,6 +35,7 @@ char name[20]; char desc[80]; ast_cdrbe be; + ast_cdrupd upd; struct ast_cdr_beitem *next; } *bes = NULL; @@ -46,7 +47,7 @@ * isn't properly generated and posted. */ -int ast_cdr_register(char *name, char *desc, ast_cdrbe be) +int ast_cdr_register(char *name, char *desc, ast_cdrbe be, ast_cdrupd upd) { struct ast_cdr_beitem *i; if (!name) @@ -74,6 +75,7 @@ strncpy(i->name, name, sizeof(i->name) - 1); strncpy(i->desc, desc, sizeof(i->desc) - 1); i->be = be; + i->upd = upd; ast_mutex_lock(&cdrlock); i->next = bes; bes = i; @@ -107,6 +109,8 @@ { char *chan; struct ast_cdr *next; + struct vendor_cdr_field *vendor; + while (cdr) { next = cdr->next; chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : ""; @@ -116,6 +120,14 @@ ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan); if (!cdr->start.tv_sec && !cdr->start.tv_usec) ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan); + vendor = cdr->vendor; + while (vendor) { + struct vendor_cdr_field *tmp = vendor; + vendor = vendor->next; + if (tmp->value) + free(tmp->value); + free(tmp); + } free(cdr); cdr = next; } @@ -426,11 +438,24 @@ return 0; } +char *ast_cdr_getvendorfield(struct ast_cdr *cdr, char *module, char *name) +{ + struct vendor_cdr_field *vendor; + + for (vendor=cdr->vendor; vendor; vendor=vendor->next) { + if ((!strcasecmp(vendor->module, module)) && (!strcasecmp(vendor->name, name))) { + return vendor->value; + } + } + return NULL; +} + int ast_cdr_update(struct ast_channel *c) { struct ast_cdr *cdr = c->cdr; char *num; char tmp[AST_MAX_EXTENSION] = ""; + struct ast_cdr_beitem *i; /* Grab source from ANI or normal Caller*ID */ while (cdr) { if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { @@ -465,6 +490,13 @@ strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1); else strncpy(cdr->dcontext, c->macrocontext, sizeof(cdr->dcontext) - 1); + + /* Vendor-defined CDR records may need other non-standard fields posted */ + for (i=bes; i; i=i->next) { + if (i->upd) { + i->upd(cdr, c); + } + } } cdr = cdr->next; } @@ -517,6 +549,7 @@ void ast_cdr_reset(struct ast_cdr *cdr, int flags) { struct ast_flags tmp = {flags}; + struct vendor_cdr_field *vendor; while (cdr) { /* Post if requested */ if (ast_test_flag(&tmp, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) { @@ -534,7 +567,14 @@ ast_cdr_start(cdr); cdr->disposition = AST_CDR_NOANSWER; } - + vendor = cdr->vendor; + while (vendor) { + struct vendor_cdr_field *tmp2 = vendor; + vendor = vendor->next; + if (tmp2->value) + free(tmp2->value); + free(tmp2); + } cdr = cdr->next; } Index: include/asterisk/cdr.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/cdr.h,v retrieving revision 1.20 diff -u -r1.20 cdr.h --- include/asterisk/cdr.h 21 Jan 2005 07:06:25 -0000 1.20 +++ include/asterisk/cdr.h 26 Jan 2005 18:09:34 -0000 @@ -38,6 +38,44 @@ struct ast_channel; +#define VENDOR_CDR_COPYVAR(varname, flag) \ + if (strcasecmp(field->name, varname)) { \ + char *tmp = pbx_builtin_getvar_helper(c, varname); \ + if (field->value && tmp && strcasecmp((char *)field->value, tmp)) \ + free((char *)field->value); \ + if (tmp) \ + field->value = (void *)strdup(tmp); \ + flag = 1; \ + } + +#define VENDOR_CDR_NEWVAR(varname) \ + { \ + char *tmp = pbx_builtin_getvar_helper(c, varname); \ + field = malloc(sizeof(struct vendor_cdr_field)); \ + if (field && tmp) { \ + strncpy(field->module, name, sizeof(field->module)); \ + strncpy(field->name, varname, sizeof(field->name)); \ + (char *)field->value = strdup(tmp); \ + if (field->value) { \ + ast_mutex_lock(&(c->lock)); \ + field->next = cdr->vendor; \ + cdr->vendor = field; \ + ast_mutex_unlock(&(c->lock)); \ + } else { \ + free(field); \ + } \ + } else if (field) { \ + free(field); \ + } \ + } + +struct vendor_cdr_field { + char module[AST_MAX_EXTENSION]; + char name[AST_MAX_EXTENSION]; + char *value; + struct vendor_cdr_field *next; +}; + /*! Responsible for call detail data */ struct ast_cdr { /*! Caller*ID with text */ @@ -78,10 +116,13 @@ char uniqueid[32]; /* User field */ char userfield[AST_MAX_USER_FIELD]; + + struct vendor_cdr_field *vendor; struct ast_cdr *next; }; typedef int (*ast_cdrbe)(struct ast_cdr *cdr); +typedef int (*ast_cdrupd)(struct ast_cdr *cdr, struct ast_channel *chan); /*! Allocate a record */ /*! @@ -121,7 +162,7 @@ * Used to register a Call Detail Record handler. * Returns -1 on error, 0 on success. */ -extern int ast_cdr_register(char *name, char *desc, ast_cdrbe be); +extern int ast_cdr_register(char *name, char *desc, ast_cdrbe be, ast_cdrupd upd); /*! Unregister a CDR handling engine */ /*! @@ -182,6 +223,14 @@ * Returns nothing */ extern void ast_cdr_post(struct ast_cdr *cdr); + +/*! Retrieve the value of a vendor field */ +/*! + * \param cdr Which cdr to retrieve from + * \param module Name of the associated CDR vendor + * \param name Vendor field name + */ +extern char *ast_cdr_getvendorfield(struct ast_cdr *cdr, char *module, char *name); /*! Set the destination channel, if there was one */ /*!