Merge anthm's CDR updates (bug #3595)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5068 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Mark Spencer 20 years ago
parent 7954654d15
commit b6c4282a03

@ -25,8 +25,10 @@ static char *app = "ForkCDR";
static char *synopsis =
"Forks the Call Data Record";
static char *descrip =
" ForkCDR(): Causes the Call Data Record to fork an additional\n"
"cdr record starting from the time of the fork call\n";
" ForkCDR([options]): Causes the Call Data Record to fork an additional\n"
"cdr record starting from the time of the fork call\n"
"If the option 'v' is passed all cdr variables will be passed along also.\n"
"";
STANDARD_LOCAL_USER;
@ -34,17 +36,24 @@ STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static void ast_cdr_clone(struct ast_cdr *cdr) {
static void ast_cdr_clone(struct ast_cdr *cdr)
{
struct ast_cdr *newcdr = ast_cdr_alloc();
memcpy(newcdr,cdr,sizeof(struct ast_cdr));
ast_cdr_append(cdr,newcdr);
gettimeofday(&newcdr->start, NULL);
memset(&newcdr->answer, 0, sizeof(newcdr->answer));
memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
ast_cdr_copy_vars(newcdr, cdr);
if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS)) {
ast_cdr_free_vars(cdr, 0);
}
newcdr->disposition = AST_CDR_NOANSWER;
ast_set_flag(cdr, AST_CDR_FLAG_CHILD|AST_CDR_FLAG_LOCKED);
}
static void ast_cdr_fork(struct ast_channel *chan) {
static void ast_cdr_fork(struct ast_channel *chan)
{
if(chan && chan->cdr) {
ast_cdr_clone(chan->cdr);
}
@ -55,7 +64,8 @@ static int forkcdr_exec(struct ast_channel *chan, void *data)
int res=0;
struct localuser *u;
LOCAL_USER_ADD(u);
ast_set2_flag(chan->cdr, strchr((char *)data, 'v'), AST_CDR_FLAG_KEEP_VARS);
ast_cdr_fork(chan);
LOCAL_USER_REMOVE(u);

275
cdr.c

@ -103,10 +103,258 @@ void ast_cdr_unregister(char *name)
free(i);
}
static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name, int recur)
{
struct ast_var_t *variables;
struct varshead *headp;
while(cdr) {
headp = &cdr->varshead;
if (name) {
AST_LIST_TRAVERSE(headp,variables,entries) {
if (!strcmp(name, ast_var_name(variables)))
return ast_var_value(variables);
}
}
if (!recur) {
break;
}
cdr = cdr->next;
}
return NULL;
}
#define ast_val_or_null(val) do { \
if (val[0]) { \
strncpy(workspace, val, workspacelen - 1);\
*ret = workspace; \
} \
} while(0)
void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur)
{
struct tm tm;
time_t t;
const char *fmt = "%Y-%m-%d %T";
*ret = NULL;
/* special vars (the ones from the struct ast_cdr when requested by name)
I'd almost say we should convert all the stringed vals to vars */
if (!strcasecmp(name, "clid")) {
ast_val_or_null(cdr->clid);
} else if (!strcasecmp(name, "src")) {
ast_val_or_null(cdr->src);
} else if (!strcasecmp(name, "dst")) {
ast_val_or_null(cdr->dst);
} else if (!strcasecmp(name, "dcontext")) {
ast_val_or_null(cdr->dcontext);
} else if (!strcasecmp(name, "channel")) {
ast_val_or_null(cdr->channel);
} else if (!strcasecmp(name, "dstchannel")) {
ast_val_or_null(cdr->dstchannel);
} else if (!strcasecmp(name, "lastapp")) {
ast_val_or_null(cdr->lastapp);
} else if (!strcasecmp(name, "lastdata")) {
ast_val_or_null(cdr->lastdata);
} else if (!strcasecmp(name, "start")) {
t = cdr->start.tv_sec;
if (t) {
localtime_r(&t,&tm);
strftime(workspace, workspacelen, fmt, &tm);
*ret = workspace;
}
} else if (!strcasecmp(name, "answer")) {
t = cdr->start.tv_sec;
if (t) {
localtime_r(&t,&tm);
strftime(workspace, workspacelen, fmt, &tm);
*ret = workspace;
}
} else if (!strcasecmp(name, "end")) {
t = cdr->start.tv_sec;
if (t) {
localtime_r(&t,&tm);
strftime(workspace, workspacelen, fmt, &tm);
*ret = workspace;
}
} else if (!strcasecmp(name, "duration")) {
snprintf(workspace, workspacelen, "%d", cdr->duration);
*ret = workspace;
} else if (!strcasecmp(name, "billsec")) {
snprintf(workspace, workspacelen, "%d", cdr->billsec);
*ret = workspace;
} else if (!strcasecmp(name, "disposition")) {
strncpy(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen - 1);
*ret = workspace;
} else if (!strcasecmp(name, "amaflags")) {
strncpy(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen - 1);
*ret = workspace;
} else if (!strcasecmp(name, "accountcode")) {
ast_val_or_null(cdr->accountcode);
} else if (!strcasecmp(name, "uniqueid")) {
ast_val_or_null(cdr->uniqueid);
} else if (!strcasecmp(name, "userfield")) {
ast_val_or_null(cdr->userfield);
} else {
if ((*ret = (char *)ast_cdr_getvar_internal(cdr, name, recur))) {
strncpy(workspace, *ret, workspacelen - 1);
*ret = workspace;
}
}
}
int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, char *value, int recur)
{
struct ast_var_t *newvariable;
struct varshead *headp;
if (!cdr) {
ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistant CDR record.\n");
return -1;
}
while (cdr) {
headp = &cdr->varshead;
AST_LIST_TRAVERSE (headp, newvariable, entries) {
if (strcasecmp(ast_var_name(newvariable), name) == 0) {
/* there is already such a variable, delete it */
AST_LIST_REMOVE(headp, newvariable, entries);
ast_var_delete(newvariable);
break;
}
}
if (value) {
newvariable = ast_var_assign(name, value);
AST_LIST_INSERT_HEAD(headp, newvariable, entries);
}
if (!recur) {
break;
}
cdr = cdr->next;
}
return 0;
}
int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
{
struct ast_var_t *variables, *newvariable = NULL;
struct varshead *headpa, *headpb;
char *var, *val;
int x = 0;
headpa=&from_cdr->varshead;
headpb=&to_cdr->varshead;
AST_LIST_TRAVERSE(headpa,variables,entries) {
if (variables && (var=ast_var_name(variables)) && (val=ast_var_value(variables)) && !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
newvariable = ast_var_assign(var, val);
AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
x++;
}
}
return x;
}
#define CDR_CLEN 18
int ast_cdr_serialize_variables(struct ast_cdr *cdr, char *buf, size_t size, char delim, char sep, int recur)
{
struct ast_var_t *variables;
struct varshead *headp;
char *var=NULL ,*val=NULL;
char *tmp = NULL;
char workspace[256];
int workspacelen;
int total = 0, x = 0, i = 0;
const char *cdrcols[CDR_CLEN] = {
"clid",
"src",
"dst",
"dcontext",
"channel",
"dstchannel",
"lastapp",
"lastdata",
"start",
"answer",
"end",
"duration",
"billsec",
"disposition",
"amaflags",
"accountcode",
"uniqueid",
"userfield"
};
memset(buf,0,size);
while (cdr) {
x++;
if (x > 1) {
strncat(buf, "\n", size);
}
headp=&cdr->varshead;
AST_LIST_TRAVERSE(headp,variables,entries) {
if (cdr && variables && (var=ast_var_name(variables)) && (val=ast_var_value(variables)) && !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
snprintf(buf + strlen(buf), size - strlen(buf), "level %d: %s%c%s%c", x, var, delim, val, sep);
if (strlen(buf) >= size) {
ast_log(LOG_ERROR,"Data Buffer Size Exceeded!\n");
break;
}
total++;
} else
break;
}
for (i = 0 ; i < CDR_CLEN; i++) {
workspacelen = sizeof(workspace);
ast_cdr_getvar(cdr, cdrcols[i], &tmp, workspace, workspacelen, 0);
if (!tmp)
continue;
snprintf(buf + strlen(buf), size - strlen(buf), "level %d: %s%c%s%c", x, cdrcols[i], delim, tmp, sep);
if (strlen(buf) >= size) {
ast_log(LOG_ERROR,"Data Buffer Size Exceeded!\n");
break;
}
total++;
}
if (!recur) {
break;
}
cdr = cdr->next;
}
return total;
}
void ast_cdr_free_vars(struct ast_cdr *cdr, int recur)
{
struct varshead *headp;
struct ast_var_t *vardata;
/* clear variables */
while(cdr) {
headp = &cdr->varshead;
while (!AST_LIST_EMPTY(headp)) {
vardata = AST_LIST_REMOVE_HEAD(headp, entries);
ast_var_delete(vardata);
}
if (!recur) {
break;
}
cdr = cdr->next;
}
}
void ast_cdr_free(struct ast_cdr *cdr)
{
char *chan;
struct ast_cdr *next;
while (cdr) {
next = cdr->next;
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
@ -116,6 +364,8 @@ void ast_cdr_free(struct ast_cdr *cdr)
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);
ast_cdr_free_vars(cdr, 0);
free(cdr);
cdr = next;
}
@ -185,7 +435,7 @@ void ast_cdr_failed(struct ast_cdr *cdr)
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
cdr->disposition = AST_CDR_FAILED;
cdr = cdr->next;
}
@ -223,7 +473,7 @@ void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann)
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->dstchannel, chann, sizeof(cdr->dstchannel) - 1);
cdr = cdr->next;
}
@ -233,7 +483,7 @@ void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
{
char *chan;
while (cdr) {
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
@ -253,7 +503,7 @@ int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
char tmp[AST_MAX_EXTENSION] = "";
char *num;
while (cdr) {
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
/* Grab source from ANI or normal Caller*ID */
if (c->cid.cid_ani)
num = c->cid.cid_ani;
@ -279,13 +529,14 @@ int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
return 0;
}
int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
{
char *chan;
char *num;
char tmp[AST_MAX_EXTENSION] = "";
while (cdr) {
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (!ast_strlen_zero(cdr->channel))
ast_log(LOG_WARNING, "CDR already initialized on '%s'\n", chan);
@ -380,7 +631,7 @@ int ast_cdr_setaccount(struct ast_channel *chan, const char *account)
strncpy(chan->accountcode, account, sizeof(chan->accountcode) - 1);
while (cdr) {
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode) - 1);
cdr = cdr->next;
}
@ -404,7 +655,7 @@ int ast_cdr_setuserfield(struct ast_channel *chan, const char *userfield)
struct ast_cdr *cdr = chan->cdr;
while (cdr) {
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->userfield, userfield, sizeof(cdr->userfield) - 1);
cdr = cdr->next;
}
@ -419,7 +670,7 @@ int ast_cdr_appenduserfield(struct ast_channel *chan, const char *userfield)
{
int len = strlen(cdr->userfield);
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->userfield+len, userfield, sizeof(cdr->userfield) - len - 1);
cdr = cdr->next;
}
@ -433,7 +684,7 @@ int ast_cdr_update(struct ast_channel *c)
char tmp[AST_MAX_EXTENSION] = "";
/* Grab source from ANI or normal Caller*ID */
while (cdr) {
if(!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
/* Grab source from ANI or normal Caller*ID */
if (c->cid.cid_ani)
num = c->cid.cid_ani;
@ -524,6 +775,12 @@ void ast_cdr_reset(struct ast_cdr *cdr, int flags)
ast_cdr_end(cdr);
ast_cdr_post(cdr);
}
/* clear variables */
if (! ast_test_flag(&tmp, AST_CDR_FLAG_KEEP_VARS)) {
ast_cdr_free_vars(cdr, 0);
}
/* Reset to initial state */
ast_clear_flag(cdr, AST_FLAGS_ALL);
memset(&cdr->start, 0, sizeof(cdr->start));

@ -651,10 +651,11 @@ static int handle_showchan(int fd, int argc, char *argv[])
{
struct ast_channel *c=NULL;
struct timeval now;
char buf[1024];
char buf[2048];
char cdrtime[256];
long elapsed_seconds=0;
int hour=0, min=0, sec=0;
if (argc != 3)
return RESULT_SHOWUSAGE;
gettimeofday(&now, NULL);
@ -709,9 +710,11 @@ static int handle_showchan(int fd, int argc, char *argv[])
( c-> data ? (!ast_strlen_zero(c->data) ? c->data : "(Empty)") : "(None)"),
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
if(pbx_builtin_serialize_variables(c,buf,sizeof(buf)))
ast_cli(fd,"Variables:\n%s\n",buf);
ast_cli(fd," Variables:\n%s\n",buf);
if(c->cdr && ast_cdr_serialize_variables(c->cdr,buf, sizeof(buf), '=', '\n', 1))
ast_cli(fd," CDR Variables:\n%s\n",buf);
ast_mutex_unlock(&c->lock);
ast_mutex_unlock(&c->lock);
break;
}
ast_mutex_unlock(&c->lock);

@ -22,14 +22,15 @@ MySQL.
Applications
------------
* SetAccount Set account code for billing
* SetAMAFlags Sets AMA flags
* NoCDR Make sure no CDR is saved for a specific call
* ResetCDR Reset CDR
* ForkCDR Save current CDR and start a new CDR for this call
* Authenticate Authenticates and sets the account code
* SetCDRUserField Set CDR user field
* AppendCDRUserField Append data to CDR User field
* SetAccount Set account code for billing
* SetAMAFlags Sets AMA flags
* NoCDR Make sure no CDR is saved for a specific call
* ResetCDR Reset CDR
* ForkCDR Save current CDR and start a new CDR for this call
* Authenticate Authenticates and sets the account code
* SetCDRUserField Set CDR user field
* AppendCDRUserField Append data to CDR User field
* SetVarCDR Set CDR Vars
For more information, use the "show application" command.
You can set default account codes and AMA flags for devices in
@ -72,4 +73,53 @@ will report a short call time. If you want detailed records you must
turn off IAX transfer, but unless your servers are very close together, you
will definitely get a latency hit from doing so.
____________________________________
CDR Variables
------------------------------------
If the channel has a cdr, that cdr record has it's own set of variables which
can be accessed just like channel variables. The following builtin variables
are available.
${CDR(clid)} Caller ID
${CDR(src)} Source
${CDR(dst)} Destination
${CDR(dcontext)} Destination context
${CDR(channel)} Channel name
${CDR(dstchannel)} Destination channel
${CDR(lastapp)} Last app executed
${CDR(lastdata)} Last app's arguments
${CDR(start)} Time the call started.
${CDR(answer)} Time the call was answered.
${CDR(end)} Time the call ended.
${CDR(duration)} Duration of the call.
${CDR(billsec)} Duration of the call once it was answered.
${CDR(disposition)} ANSWERED, NO ANSWER, BUSY
${CDR(amaflags)} DOCUMENTATION, BILL, IGNORE etc
${CDR(accountcode)} The channel's account code.
${CDR(uniqueid)} The channel's unique id.
${CDR(userfield)} The channels uses specified field.
In addition, you can set your own extra variables with the application SetVarCDR(var=val)
or a traditional SetVAR(CDR(var=val) to anything you want.
SetVar(CDR(var)=val) will set the var to all cdr in a stack of cdrs.
______________________________
cdr_csv2
------------------------------
This module is an experimental new cdr module to demonstrate the cdr vars.
usage(
*) Create a file called cdr.conf and place it in your /etc/asterisk (or wherever your config files are) in the [cdr_csv2] section.
*) Add an entry called format to indicate any format you want for the output.
The following format string will emulate the regular cdr file format:
[cdr_csv2]
format => "${CDR(clid)}","${CDR(src)}","${CDR(dst)}","${CDR(dcontext)}","${CDR(channel)}","${CDR(dstchannel)}","${CDR(lastapp)}","${CDR(lastdata)}","${CDR(start)}","${CDR(answer)}","${CDR(end)}","${CDR(duration)}","${CDR(billsec)}","${CDR(disposition)}","${CDR(amaflags)}","${CDR(accountcode)}","${CDR(uniqueid)}","${CDR(userfield)}"
You can put anything you want as the value of format incuding new cdr vars you make up or any global variables.

@ -456,3 +456,33 @@ ${OSPDEST} OSP Destination from Library
${OSPTOKEN} OSP Token to use for call from Library
${OSPRESULTS} Number of OSP results
____________________________________
CDR Variables
------------------------------------
If the channel has a cdr, that cdr record has it's own set of variables which
can be accessed just like channel variables. The following builtin variables
are available.
${CDR(clid)} Caller ID
${CDR(src)} Source
${CDR(dst)} Destination
${CDR(dcontext)} Destination context
${CDR(channel)} Channel name
${CDR(dstchannel)} Destination channel
${CDR(lastapp)} Last app executed
${CDR(lastdata)} Last app's arguments
${CDR(start)} Time the call started.
${CDR(answer)} Time the call was answered.
${CDR(end)} Time the call ended.
${CDR(duration)} Duration of the call.
${CDR(billsec)} Duration of the call once it was answered.
${CDR(disposition)} ANSWERED, NO ANSWER, BUSY
${CDR(amaflags)} DOCUMENTATION, BILL, IGNORE etc
${CDR(accountcode)} The channel's account code.
${CDR(uniqueid)} The channel's unique id.
${CDR(userfield)} The channels uses specified field.
In addition, you can set your own extra variables with a traditional
SetVAR(CDR(var)=val) to anything you want.

@ -19,10 +19,12 @@
#include <asterisk/channel.h>
#include <sys/time.h>
#define AST_CDR_FLAG_KEEP_VARS (1 << 0)
#define AST_CDR_FLAG_POSTED (1 << 1)
#define AST_CDR_FLAG_LOCKED (1 << 2)
#define AST_CDR_FLAG_CHILD (1 << 3)
#define AST_CDR_FLAG_SETVAR (1 << 4)
#define AST_CDR_FLAG_RECUR (1 << 5)
#define AST_CDR_NOANSWER (1 << 0)
#define AST_CDR_BUSY (1 << 1)
@ -37,6 +39,7 @@
#define AST_MAX_USER_FIELD 256
struct ast_channel;
AST_LIST_HEAD(varshead,ast_var_t);
/*! Responsible for call detail data */
struct ast_cdr {
@ -78,9 +81,19 @@ struct ast_cdr {
char uniqueid[32];
/* User field */
char userfield[AST_MAX_USER_FIELD];
/* A linked list for variables */
struct varshead varshead;
struct ast_cdr *next;
};
extern void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur);
extern int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, char *value, int recur);
extern int ast_cdr_serialize_variables(struct ast_cdr *cdr, char *buf, size_t size, char delim, char sep, int recur);
extern void ast_cdr_free_vars(struct ast_cdr *cdr, int recur);
extern int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr);
typedef int (*ast_cdrbe)(struct ast_cdr *cdr);
/*! Allocate a record */

@ -211,7 +211,7 @@ struct ast_channel {
int hangupcause;
/* A linked list for variables */
AST_LIST_HEAD(varshead,ast_var_t) varshead;
struct varshead varshead;
unsigned int callgroup;
unsigned int pickupgroup;

97
pbx.c

@ -321,8 +321,11 @@ static struct pbx_builtin {
{ "ResetCDR", pbx_builtin_resetcdr,
"Resets the Call Data Record",
" ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
"storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
"record WILL be stored.\nAlways returns 0.\n"
"storing the current CDR before zeroing it out\b"
"(if 'w' option is specifed) record will be stored.\n"
"(if 'a' option is specifed) any stacked records will be stored.\n"
"(if 'v' option is specifed) any variables will be saved.\n"
"Always returns 0.\n"
},
{ "ResponseTimeout", pbx_builtin_rtimeout,
@ -393,7 +396,14 @@ static struct pbx_builtin {
{ "SetVar", pbx_builtin_setvar,
"Set variable to value",
" SetVar(#n=value): Sets variable n to value. If prefixed with _, single\n"
" SetVar(#n1=value|#n2=value|..[|options]) Set a variables to a CDR.\n"
"You can specify an endless list of name / value pairs to be set as channel variables.\n"
"The last arg (if it doesn't contain an '=' ) is intrepreted as a string of\n"
"options. Valid Options:\n"
" - c - CDR, if set set the var as a CDR variable also.\n"
" - r - Recursive CDR, if there are any stacked CDRs, also apply to all as a cdr var.\n"
" - g - Set a global variable not a channel variable.\n"
" #n=value: Sets variable n to value. If prefixed with _, single\n"
"inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
{ "ImportVar", pbx_builtin_importvar,
@ -820,8 +830,17 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
if (c)
headp=&c->varshead;
*ret=NULL;
/* Now we have the variable name on cp3 */
if (!strncasecmp(var,"LEN(",4)) { /* ${LEN(<string>)} */
if (c && c->cdr && !strncasecmp(var, "CDR(", 4)) { /* ${CDR(NEET)} */
char *vtmp, *nt;
if ((vtmp = ast_strdupa((char *) var + 4)) && (nt = strchr(vtmp, ')'))) {
*nt = '\0';
ast_cdr_getvar(c->cdr, vtmp, ret, workspace, workspacelen, 1);
} else
ast_log(LOG_WARNING, "Invalid CDR variable.\n");
return;
} else if (!strncasecmp(var,"LEN(",4)) { /* ${LEN(<string>)} */
/* Now we have the variable name on cp3 */
int len=strlen(var);
int len_len=4;
if (strrchr(var,')')) {
@ -4900,6 +4919,8 @@ static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
flags |= AST_CDR_FLAG_POSTED;
if(strchr((char *)data, 'a'))
flags |= AST_CDR_FLAG_LOCKED;
if(strchr((char *)data, 'v'))
flags |= AST_CDR_FLAG_KEEP_VARS;
}
ast_cdr_reset(chan->cdr, flags);
@ -5202,8 +5223,25 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value
struct ast_var_t *newvariable;
struct varshead *headp;
if (chan)
if (chan) {
headp = &chan->varshead;
if (!strncasecmp(name, "CDR(", 4)) { /* CDR VARS */
char *vtmp, *nt;
int recur = 0;
if ((vtmp = ast_strdupa((char *) name + 4)) && (nt = strchr(vtmp, ')'))) {
*nt = '\0';
if(vtmp[0] == '-') {
vtmp++;
recur = 1;
}
ast_cdr_setvar(chan->cdr, vtmp, value, recur);
} else {
ast_log(LOG_WARNING, "Invalid CDR variable.\n");
}
return;
}
}
else
headp = &globals;
@ -5226,21 +5264,44 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value
int pbx_builtin_setvar(struct ast_channel *chan, void *data)
{
char *name;
char *value;
char *stringp=NULL;
char *name, *value, *mydata, *next, *fstr = NULL;
struct ast_flags flags = {0};
if (!data || ast_strlen_zero(data)) {
if (data && !ast_strlen_zero(data) && chan->cdr && (mydata = ast_strdupa(data))) {
next = mydata;
while(next) {
name = next;
if ((next = strchr(next, '|'))) {
*next = '\0';
next++;
}
if ((value = strchr(name, '='))) {
*value = '\0';
value++;
if( fstr && strchr(fstr, 'g') ) {
pbx_builtin_setvar_helper(NULL, name, value);
}
else {
pbx_builtin_setvar_helper(chan, name, value);
if (ast_test_flag(&flags, AST_CDR_FLAG_SETVAR)) {
ast_cdr_setvar(chan->cdr, name, value, ast_test_flag(&flags, AST_CDR_FLAG_RECUR));
}
}
} else if (!next) {
name++;
if (strchr(name, 'c') ) {
ast_set_flag(&flags, AST_CDR_FLAG_SETVAR);
} else if (strchr(name, 'r') ) {
ast_set_flag(&flags, AST_CDR_FLAG_RECUR | AST_CDR_FLAG_SETVAR);
}
} else
ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
}
} else {
ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
return 0;
}
stringp = ast_strdupa(data);
name = strsep(&stringp,"=");
value = strsep(&stringp,"\0");
pbx_builtin_setvar_helper(chan, name, value);
return(0);
}

Loading…
Cancel
Save