various fixes:

use linked list macros for managing backend list (inspired by bug #4258)
  use ast_copy_string instead of strncpy when appropriate
  minor fixes and formatting cleanup
  add AST_LIST_HEAD_STATIC and AST_LIST_REMOVE_CURRENT macros


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5659 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kevin P. Fleming
2005-05-15 02:42:59 +00:00
parent 4515e94c39
commit 219541b5e0
2 changed files with 241 additions and 214 deletions

387
cdr.c
View File

@@ -25,20 +25,20 @@
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/options.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
int ast_default_amaflags = AST_CDR_DOCUMENTATION;
char ast_default_accountcode[20] = "";
AST_MUTEX_DEFINE_STATIC(cdrlock);
static struct ast_cdr_beitem {
struct ast_cdr_beitem {
char name[20];
char desc[80];
ast_cdrbe be;
struct ast_cdr_beitem *next;
} *bes = NULL;
AST_LIST_ENTRY(ast_cdr_beitem) list;
};
static AST_LIST_HEAD_STATIC(be_list, ast_cdr_beitem);
/*
* We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip
@@ -50,58 +50,58 @@ static struct ast_cdr_beitem {
int ast_cdr_register(char *name, char *desc, ast_cdrbe be)
{
struct ast_cdr_beitem *i;
if (!name)
return -1;
if (!be) {
ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
return -1;
}
ast_mutex_lock(&cdrlock);
i = bes;
while(i) {
AST_LIST_LOCK(&be_list);
AST_LIST_TRAVERSE(&be_list, i, list) {
if (!strcasecmp(name, i->name))
break;
i = i->next;
}
ast_mutex_unlock(&cdrlock);
AST_LIST_UNLOCK(&be_list);
if (i) {
ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
return -1;
}
i = malloc(sizeof(struct ast_cdr_beitem));
i = malloc(sizeof(*i));
if (!i)
return -1;
memset(i, 0, sizeof(struct ast_cdr_beitem));
strncpy(i->name, name, sizeof(i->name) - 1);
strncpy(i->desc, desc, sizeof(i->desc) - 1);
memset(i, 0, sizeof(*i));
i->be = be;
ast_mutex_lock(&cdrlock);
i->next = bes;
bes = i;
ast_mutex_unlock(&cdrlock);
ast_copy_string(i->name, name, sizeof(i->name));
ast_copy_string(i->desc, desc, sizeof(i->desc));
AST_LIST_LOCK(&be_list);
AST_LIST_INSERT_HEAD(&be_list, i, list);
AST_LIST_UNLOCK(&be_list);
return 0;
}
void ast_cdr_unregister(char *name)
{
struct ast_cdr_beitem *i, *prev = NULL;
ast_mutex_lock(&cdrlock);
i = bes;
while(i) {
struct ast_cdr_beitem *i = NULL;
AST_LIST_LOCK(&be_list);
AST_LIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
if (!strcasecmp(name, i->name)) {
if (prev)
prev->next = i->next;
else
bes = i->next;
AST_LIST_REMOVE_CURRENT(&be_list, list);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
free(i);
break;
}
i = i->next;
}
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
ast_mutex_unlock(&cdrlock);
if (i)
free(i);
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&be_list);
}
static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name, int recur)
@@ -109,110 +109,97 @@ static const char *ast_cdr_getvar_internal(struct ast_cdr *cdr, const char *name
struct ast_var_t *variables;
struct varshead *headp;
while(cdr) {
if (!name || ast_strlen_zero(name))
return NULL;
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);
}
AST_LIST_TRAVERSE(headp, variables, entries) {
if (!strcasecmp(name, ast_var_name(variables)))
return ast_var_value(variables);
}
if (!recur) {
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";
const char *varbuf;
*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")) {
if (!strcasecmp(name, "clid"))
ast_copy_string(workspace, cdr->clid, workspacelen);
else if (!strcasecmp(name, "src"))
ast_copy_string(workspace, cdr->src, workspacelen);
else if (!strcasecmp(name, "dst"))
ast_copy_string(workspace, cdr->dst, workspacelen);
else if (!strcasecmp(name, "dcontext"))
ast_copy_string(workspace, cdr->dcontext, workspacelen);
else if (!strcasecmp(name, "channel"))
ast_copy_string(workspace, cdr->channel, workspacelen);
else if (!strcasecmp(name, "dstchannel"))
ast_copy_string(workspace, cdr->dstchannel, workspacelen);
else if (!strcasecmp(name, "lastapp"))
ast_copy_string(workspace, cdr->lastapp, workspacelen);
else if (!strcasecmp(name, "lastdata"))
ast_copy_string(workspace, cdr->lastdata, workspacelen);
else if (!strcasecmp(name, "start")) {
t = cdr->start.tv_sec;
if (t) {
localtime_r(&t,&tm);
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);
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);
localtime_r(&t, &tm);
strftime(workspace, workspacelen, fmt, &tm);
*ret = workspace;
}
} else if (!strcasecmp(name, "duration")) {
} else if (!strcasecmp(name, "duration"))
snprintf(workspace, workspacelen, "%d", cdr->duration);
*ret = workspace;
} else if (!strcasecmp(name, "billsec")) {
else if (!strcasecmp(name, "billsec"))
snprintf(workspace, workspacelen, "%d", cdr->billsec);
else if (!strcasecmp(name, "disposition"))
ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
else if (!strcasecmp(name, "amaflags"))
ast_copy_string(workspace, ast_cdr_flags2str(cdr->amaflags), workspacelen);
else if (!strcasecmp(name, "accountcode"))
ast_copy_string(workspace, cdr->accountcode, workspacelen);
else if (!strcasecmp(name, "uniqueid"))
ast_copy_string(workspace, cdr->uniqueid, workspacelen);
else if (!strcasecmp(name, "userfield"))
ast_copy_string(workspace, cdr->userfield, workspacelen);
else if ((varbuf = ast_cdr_getvar_internal(cdr, name, recur)))
ast_copy_string(workspace, varbuf, workspacelen);
if (!ast_strlen_zero(workspace))
*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, const char *value, int recur)
{
struct ast_var_t *newvariable;
struct varshead *headp;
struct varshead *headp;
const char *read_only[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
"lastapp", "lastdata", "start", "answer", "end", "duration",
"billsec", "disposition", "amaflags", "accountcode", "uniqueid",
"userfield", NULL };
"lastapp", "lastdata", "start", "answer", "end", "duration",
"billsec", "disposition", "amaflags", "accountcode", "uniqueid",
"userfield", NULL };
int x;
for(x = 0; read_only[x]; x++) {
@@ -222,20 +209,22 @@ int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int
}
}
if (!cdr) {
if (!cdr) {
ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
return -1;
}
while (cdr) {
headp = &cdr->varshead;
AST_LIST_TRAVERSE (headp, newvariable, entries) {
if (strcasecmp(ast_var_name(newvariable), name) == 0) {
AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
if (!strcasecmp(ast_var_name(newvariable), name)) {
/* there is already such a variable, delete it */
AST_LIST_REMOVE(headp, newvariable, entries);
AST_LIST_REMOVE_CURRENT(headp, entries);
ast_var_delete(newvariable);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
if (value) {
newvariable = ast_var_assign(name, value);
@@ -245,23 +234,27 @@ int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int
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;
struct varshead *headpa, *headpb;
char *var, *val;
int x = 0;
headpa=&from_cdr->varshead;
headpb=&to_cdr->varshead;
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)) {
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++;
@@ -309,9 +302,11 @@ int ast_cdr_serialize_variables(struct ast_cdr *cdr, char *buf, size_t size, cha
if (x > 1) {
strncat(buf, "\n", size);
}
headp=&cdr->varshead;
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)) {
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");
@@ -338,8 +333,10 @@ int ast_cdr_serialize_variables(struct ast_cdr *cdr, char *buf, size_t size, cha
if (!recur) {
break;
}
cdr = cdr->next;
}
return total;
}
@@ -350,15 +347,17 @@ void ast_cdr_free_vars(struct ast_cdr *cdr, int recur)
struct ast_var_t *vardata;
/* clear variables */
while(cdr) {
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;
}
}
@@ -387,16 +386,18 @@ void ast_cdr_free(struct ast_cdr *cdr)
struct ast_cdr *ast_cdr_alloc(void)
{
struct ast_cdr *cdr;
cdr = malloc(sizeof(struct ast_cdr));
if (cdr) {
memset(cdr, 0, sizeof(struct ast_cdr));
}
cdr = malloc(sizeof(*cdr));
if (cdr)
memset(cdr, 0, sizeof(*cdr));
return cdr;
}
void ast_cdr_start(struct ast_cdr *cdr)
{
char *chan;
while (cdr) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
@@ -406,13 +407,14 @@ void ast_cdr_start(struct ast_cdr *cdr)
ast_log(LOG_WARNING, "CDR on channel '%s' already started\n", chan);
gettimeofday(&cdr->start, NULL);
}
cdr = cdr->next;
cdr = cdr->next;
}
}
void ast_cdr_answer(struct ast_cdr *cdr)
{
char *chan;
while (cdr) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
@@ -429,6 +431,7 @@ void ast_cdr_answer(struct ast_cdr *cdr)
void ast_cdr_busy(struct ast_cdr *cdr)
{
char *chan;
while (cdr) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
@@ -444,6 +447,7 @@ void ast_cdr_busy(struct ast_cdr *cdr)
void ast_cdr_failed(struct ast_cdr *cdr)
{
char *chan;
while (cdr) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
@@ -457,22 +461,23 @@ void ast_cdr_failed(struct ast_cdr *cdr)
int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
{
int res = 0;
while (cdr) {
switch(cause) {
case AST_CAUSE_BUSY:
ast_cdr_busy(cdr);
break;
case AST_CAUSE_FAILURE:
ast_cdr_failed(cdr);
break;
case AST_CAUSE_NORMAL:
break;
case AST_CAUSE_NOTDEFINED:
res = -1;
break;
default:
res = -1;
ast_log(LOG_WARNING, "Cause not handled\n");
case AST_CAUSE_BUSY:
ast_cdr_busy(cdr);
break;
case AST_CAUSE_FAILURE:
ast_cdr_failed(cdr);
break;
case AST_CAUSE_NORMAL:
break;
case AST_CAUSE_NOTDEFINED:
res = -1;
break;
default:
res = -1;
ast_log(LOG_WARNING, "Cause not handled\n");
}
cdr = cdr->next;
}
@@ -482,12 +487,13 @@ int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann)
{
char *chan;
while (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))
strncpy(cdr->dstchannel, chann, sizeof(cdr->dstchannel) - 1);
ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
cdr = cdr->next;
}
}
@@ -495,6 +501,7 @@ void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann)
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)) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
@@ -502,10 +509,10 @@ void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
if (!app)
app = "";
strncpy(cdr->lastapp, app, sizeof(cdr->lastapp) - 1);
ast_copy_string(cdr->lastapp, app, sizeof(cdr->lastapp));
if (!data)
data = "";
strncpy(cdr->lastdata, data, sizeof(cdr->lastdata) - 1);
ast_copy_string(cdr->lastdata, data, sizeof(cdr->lastdata));
}
cdr = cdr->next;
}
@@ -515,13 +522,11 @@ 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)) {
/* Grab source from ANI or normal Caller*ID */
if (c->cid.cid_ani)
num = c->cid.cid_ani;
else
num = c->cid.cid_num;
num = c->cid.cid_ani ? c->cid.cid_ani : c->cid.cid_num;
if (c->cid.cid_name && num)
snprintf(tmp, sizeof(tmp), "\"%s\" <%s>", c->cid.cid_name, num);
@@ -529,16 +534,12 @@ int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
strncpy(tmp, c->cid.cid_name, sizeof(tmp) - 1);
else if (num)
strncpy(tmp, num, sizeof(tmp) - 1);
else
strcpy(tmp, "");
strncpy(cdr->clid, tmp, sizeof(cdr->clid) - 1);
if (num)
strncpy(cdr->src, num, sizeof(cdr->src) - 1);
else
strcpy(cdr->src, "");
ast_copy_string(cdr->clid, tmp, sizeof(cdr->clid));
ast_copy_string(cdr->src, num ? num : "", sizeof(cdr->src));
}
cdr = cdr->next;
}
return 0;
}
@@ -548,17 +549,15 @@ 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)) {
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);
strncpy(cdr->channel, c->name, sizeof(cdr->channel) - 1);
ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
/* Grab source from ANI or normal Caller*ID */
if (c->cid.cid_ani)
num = c->cid.cid_ani;
else
num = c->cid.cid_num;
num = c->cid.cid_ani ? c->cid.cid_ani : c->cid.cid_num;
if (c->cid.cid_name && num)
snprintf(tmp, sizeof(tmp), "\"%s\" <%s>", c->cid.cid_name, num);
@@ -566,28 +565,17 @@ int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
strncpy(tmp, c->cid.cid_name, sizeof(tmp) - 1);
else if (num)
strncpy(tmp, num, sizeof(tmp) - 1);
else
strcpy(tmp, "");
strncpy(cdr->clid, tmp, sizeof(cdr->clid) - 1);
if (num)
strncpy(cdr->src, num, sizeof(cdr->src) - 1);
else
strcpy(cdr->src, "");
ast_copy_string(cdr->clid, tmp, sizeof(cdr->clid));
ast_copy_string(cdr->src, num ? num : "", sizeof(cdr->src));
if (c->_state == AST_STATE_UP)
cdr->disposition = AST_CDR_ANSWERED;
else
cdr->disposition = AST_CDR_NOANSWER;
if (c->amaflags)
cdr->amaflags = c->amaflags;
else
cdr->amaflags = ast_default_amaflags;
strncpy(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode) - 1);
cdr->disposition = (c->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NOANSWER;
cdr->amaflags = c->amaflags ? c->amaflags : ast_default_amaflags;
ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
/* Destination information */
strncpy(cdr->dst, c->exten, sizeof(cdr->dst) - 1);
strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1);
ast_copy_string(cdr->dst, c->exten, sizeof(cdr->dst));
ast_copy_string(cdr->dcontext, c->context, sizeof(cdr->dcontext));
/* Unique call identifier */
strncpy(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid) - 1);
ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
}
cdr = cdr->next;
}
@@ -597,6 +585,7 @@ int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
void ast_cdr_end(struct ast_cdr *cdr)
{
char *chan;
while (cdr) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
@@ -620,9 +609,8 @@ char *ast_cdr_disp2str(int disposition)
return "BUSY";
case AST_CDR_ANSWERED:
return "ANSWERED";
default:
return "UNKNOWN";
}
return "UNKNOWN";
}
char *ast_cdr_flags2str(int flag)
@@ -642,10 +630,10 @@ int ast_cdr_setaccount(struct ast_channel *chan, const char *account)
{
struct ast_cdr *cdr = chan->cdr;
strncpy(chan->accountcode, account, sizeof(chan->accountcode) - 1);
ast_copy_string(chan->accountcode, account, sizeof(chan->accountcode));
while (cdr) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode) - 1);
ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
cdr = cdr->next;
}
return 0;
@@ -657,9 +645,9 @@ int ast_cdr_setamaflags(struct ast_channel *chan, const char *flag)
int newflag;
newflag = ast_cdr_amaflags2int(flag);
if (newflag) {
if (newflag)
cdr->amaflags = newflag;
}
return 0;
}
@@ -669,9 +657,10 @@ int ast_cdr_setuserfield(struct ast_channel *chan, const char *userfield)
while (cdr) {
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->userfield, userfield, sizeof(cdr->userfield) - 1);
ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
cdr = cdr->next;
}
return 0;
}
@@ -679,14 +668,15 @@ int ast_cdr_appenduserfield(struct ast_channel *chan, const char *userfield)
{
struct ast_cdr *cdr = chan->cdr;
while (cdr)
{
while (cdr) {
int len = strlen(cdr->userfield);
if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
strncpy(cdr->userfield+len, userfield, sizeof(cdr->userfield) - len - 1);
cdr = cdr->next;
}
return 0;
}
@@ -695,14 +685,10 @@ int ast_cdr_update(struct ast_channel *c)
struct ast_cdr *cdr = c->cdr;
char *num;
char tmp[AST_MAX_EXTENSION] = "";
/* Grab source from ANI or normal Caller*ID */
while (cdr) {
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;
else
num = c->cid.cid_num;
num = c->cid.cid_ani ? c->cid.cid_ani : c->cid.cid_num;
if (c->cid.cid_name && num)
snprintf(tmp, sizeof(tmp), "\"%s\" <%s>", c->cid.cid_name, num);
@@ -710,25 +696,14 @@ int ast_cdr_update(struct ast_channel *c)
strncpy(tmp, c->cid.cid_name, sizeof(tmp) - 1);
else if (num)
strncpy(tmp, num, sizeof(tmp) - 1);
else
strcpy(tmp, "");
strncpy(cdr->clid, tmp, sizeof(cdr->clid) - 1);
if (num)
strncpy(cdr->src, num, sizeof(cdr->src) - 1);
else
strcpy(cdr->src, "");
ast_copy_string(cdr->clid, tmp, sizeof(cdr->clid));
ast_copy_string(cdr->src, num ? num : "", sizeof(cdr->src));
/* Copy account code et-al */
strncpy(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode) - 1);
ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
/* Destination information */
if (ast_strlen_zero(c->macroexten))
strncpy(cdr->dst, c->exten, sizeof(cdr->dst) - 1);
else
strncpy(cdr->dst, c->macroexten, sizeof(cdr->dst) - 1);
if (ast_strlen_zero(c->macrocontext))
strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1);
else
strncpy(cdr->dcontext, c->macrocontext, sizeof(cdr->dcontext) - 1);
ast_copy_string(cdr->dst, (ast_strlen_zero(c->macroexten)) ? c->exten : c->macroexten, sizeof(cdr->dst));
ast_copy_string(cdr->dcontext, (ast_strlen_zero(c->macrocontext)) ? c->context : c->macrocontext, sizeof(cdr->dcontext));
}
cdr = cdr->next;
}
@@ -753,6 +728,7 @@ void ast_cdr_post(struct ast_cdr *cdr)
{
char *chan;
struct ast_cdr_beitem *i;
while (cdr) {
chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
@@ -762,18 +738,16 @@ void ast_cdr_post(struct ast_cdr *cdr)
if (!cdr->start.tv_sec && !cdr->start.tv_usec)
ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec + (cdr->end.tv_usec - cdr->start.tv_usec) / 1000000;
if (cdr->answer.tv_sec || cdr->answer.tv_usec) {
if (cdr->answer.tv_sec || cdr->answer.tv_usec)
cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec + (cdr->end.tv_usec - cdr->answer.tv_usec) / 1000000;
} else
else
cdr->billsec = 0;
ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
ast_mutex_lock(&cdrlock);
i = bes;
while(i) {
AST_LIST_LOCK(&be_list);
AST_LIST_TRAVERSE(&be_list, i, list) {
i->be(cdr);
i = i->next;
}
ast_mutex_unlock(&cdrlock);
AST_LIST_UNLOCK(&be_list);
cdr = cdr->next;
}
}
@@ -781,6 +755,7 @@ void ast_cdr_post(struct ast_cdr *cdr)
void ast_cdr_reset(struct ast_cdr *cdr, int flags)
{
struct ast_flags tmp = {flags};
while (cdr) {
/* Post if requested */
if (ast_test_flag(&tmp, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
@@ -790,7 +765,7 @@ void ast_cdr_reset(struct ast_cdr *cdr, int flags)
}
/* clear variables */
if (! ast_test_flag(&tmp, AST_CDR_FLAG_KEEP_VARS)) {
if (!ast_test_flag(&tmp, AST_CDR_FLAG_KEEP_VARS)) {
ast_cdr_free_vars(cdr, 0);
}
@@ -807,19 +782,21 @@ void ast_cdr_reset(struct ast_cdr *cdr, int flags)
cdr = cdr->next;
}
}
struct ast_cdr *ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr)
{
struct ast_cdr *ret;
if (cdr) {
ret = cdr;
while(cdr->next)
while (cdr->next)
cdr = cdr->next;
cdr->next = newcdr;
} else {
ret = newcdr;
}
return ret;
}

View File

@@ -39,13 +39,15 @@
to hold a list of the entries of type \a type. It does not actually
declare (allocate) a structure; to do that, either follow this
macro with the desired name of the instance you wish to declare,
or use the specified \a name to declare instances elsewhere. It is
frequently used as follows:
or use the specified \a name to declare instances elsewhere.
Example usage:
\code
static AST_LIST_HEAD(entry_list, entry) entries;
\endcode
This would define \a struct \a entry_list, and declare an instance of it named
\a entries, all intended to hold a list of type \a struct \a entry.
This would define \c struct \c entry_list, and declare an instance of it named
\a entries, all intended to hold a list of type \c struct \c entry.
*/
#define AST_LIST_HEAD(name, type) \
struct name { \
@@ -53,6 +55,32 @@ struct name { \
ast_mutex_t lock; \
}
/*!
\brief Defines a structure to be used to hold a list of specified type, statically initialized.
\param name This will be the name of the defined structure.
\param type This is the type of each list entry.
This macro creates a structure definition that can be used
to hold a list of the entries of type \a type, and allocates an instance
of it, initialized to be empty.
Example usage:
\code
static AST_LIST_HEAD_STATIC(entry_list, entry) entries;
\endcode
This would define \c struct \c entry_list, and declare an instance of it named
\a entries, all intended to hold a list of type \c struct \c entry.
*/
#define AST_LIST_HEAD_STATIC(name, type) \
struct name { \
struct type *first; \
ast_mutex_t lock; \
} name = { \
.first = NULL, \
.lock = AST_MUTEX_INIT_VALUE, \
};
/*!
\brief Initializes a list head structure with a specified first entry.
\param head This is a pointer to the list head structure
@@ -73,12 +101,14 @@ struct name { \
This macro declares a structure to be used to link list entries together.
It must be used inside the definition of the structure named in
\a type, as follows:
\code
struct list_entry {
...
AST_LIST_ENTRY(list_entry) list;
}
\endcode
The field name \a list here is arbitrary, and can be anything you wish.
*/
#define AST_LIST_ENTRY(type) \
@@ -159,6 +189,7 @@ struct { \
This macro is used to safely loop over (traverse) the entries in a list. It
uses a \a for loop, and supplies the enclosed code with a pointer to each list
entry as it loops. It is typically used as follows:
\code
static AST_LIST_HEAD(entry_list, list_entry) entries;
...
@@ -172,20 +203,39 @@ struct { \
AST_LIST_TRAVERSE_SAFE_BEGIN(&entries, current, list) {
(do something with current here)
}
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_TRAVERSE_SAFE_END;
\endcode
It differs from AST_LIST_TRAVERSE in that the code inside the loop can modify
(or even free) the entry pointed to by the \a current pointer without affecting
the loop traversal.
It differs from AST_LIST_TRAVERSE() in that the code inside the loop can modify
(or even free, after calling AST_LIST_REMOVE_CURRENT()) the entry pointed to by
the \a current pointer without affecting the loop traversal.
*/
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) { \
typeof((head)->first) __list_next; \
typeof((head)->first) __list_prev = NULL; \
for ((var) = (head)->first, __list_next = (var) ? (var)->field.next : NULL; \
(var); \
(var) = __list_next, __list_next = (var) ? (var)->field.next : NULL \
__list_prev = (var), (var) = __list_next, \
__list_next = (var) ? (var)->field.next : NULL \
)
/*!
\brief Removes the \a current entry from a list during a traversal.
\param head This is a pointer to the list head structure
\param field This is the name of the field (declared using AST_LIST_ENTRY())
used to link entries of this list together.
\note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
block; it is used to unlink the current entry from the list without affecting
the list traversal (and without having to re-traverse the list to modify the
previous entry, if any).
*/
#define AST_LIST_REMOVE_CURRENT(head, field) \
if (__list_prev) \
__list_prev->field.next = __list_next; \
else \
(head)->first = __list_next;
/*!
\brief Closes a safe loop traversal block.
*/