00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
#include <asterisk/lock.h>
00018
#include <asterisk/channel.h>
00019
#include <asterisk/cdr.h>
00020
#include <asterisk/logger.h>
00021
#include <asterisk/callerid.h>
00022
#include <asterisk/causes.h>
00023
#include <asterisk/options.h>
00024
#include <asterisk/utils.h>
00025
#include <unistd.h>
00026
#include <stdlib.h>
00027
#include <string.h>
00028
00029 int ast_default_amaflags =
AST_CDR_DOCUMENTATION;
00030 char ast_default_accountcode[20] =
"";
00031
00032
AST_MUTEX_DEFINE_STATIC(cdrlock);
00033
00034
static struct ast_cdr_beitem {
00035
char name[20];
00036
char desc[80];
00037
ast_cdrbe be;
00038
struct ast_cdr_beitem *next;
00039 } *bes = NULL;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 int ast_cdr_register(
char *name,
char *desc,
ast_cdrbe be)
00050 {
00051
struct ast_cdr_beitem *i;
00052
if (!name)
00053
return -1;
00054
if (!be) {
00055
ast_log(
LOG_WARNING,
"CDR engine '%s' lacks backend\n", name);
00056
return -1;
00057 }
00058
ast_mutex_lock(&cdrlock);
00059 i = bes;
00060
while(i) {
00061
if (!strcasecmp(name, i->name))
00062
break;
00063 i = i->next;
00064 }
00065
ast_mutex_unlock(&cdrlock);
00066
if (i) {
00067
ast_log(
LOG_WARNING,
"Already have a CDR backend called '%s'\n", name);
00068
return -1;
00069 }
00070 i =
malloc(
sizeof(
struct ast_cdr_beitem));
00071
if (!i)
00072
return -1;
00073 memset(i, 0,
sizeof(
struct ast_cdr_beitem));
00074 strncpy(i->name, name,
sizeof(i->name) - 1);
00075 strncpy(i->desc, desc,
sizeof(i->desc) - 1);
00076 i->be = be;
00077
ast_mutex_lock(&cdrlock);
00078 i->next = bes;
00079 bes = i;
00080
ast_mutex_unlock(&cdrlock);
00081
return 0;
00082 }
00083
00084 void ast_cdr_unregister(
char *name)
00085 {
00086
struct ast_cdr_beitem *i, *prev = NULL;
00087
ast_mutex_lock(&cdrlock);
00088 i = bes;
00089
while(i) {
00090
if (!strcasecmp(name, i->name)) {
00091
if (prev)
00092 prev->next = i->next;
00093
else
00094 bes = i->next;
00095
break;
00096 }
00097 i = i->next;
00098 }
00099
if (
option_verbose > 1)
00100
ast_verbose(
VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
00101
ast_mutex_unlock(&cdrlock);
00102
if (i)
00103
free(i);
00104 }
00105
00106 void ast_cdr_free(
struct ast_cdr *cdr)
00107 {
00108
char *chan;
00109
struct ast_cdr *next;
00110
while (cdr) {
00111 next = cdr->
next;
00112 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00113
if (!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00114
ast_log(
LOG_WARNING,
"CDR on channel '%s' not posted\n", chan);
00115
if (!cdr->
end.tv_sec && !cdr->
end.tv_usec)
00116
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks end\n", chan);
00117
if (!cdr->
start.tv_sec && !cdr->
start.tv_usec)
00118
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks start\n", chan);
00119
free(cdr);
00120 cdr = next;
00121 }
00122 }
00123
00124 struct ast_cdr *
ast_cdr_alloc(
void)
00125 {
00126
struct ast_cdr *cdr;
00127 cdr =
malloc(
sizeof(
struct ast_cdr));
00128
if (cdr) {
00129 memset(cdr, 0,
sizeof(
struct ast_cdr));
00130 }
00131
return cdr;
00132 }
00133
00134 void ast_cdr_start(
struct ast_cdr *cdr)
00135 {
00136
char *chan;
00137
while (cdr) {
00138
if (!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED)) {
00139 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00140
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00141
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00142
if (cdr->
start.tv_sec || cdr->
start.tv_usec)
00143
ast_log(
LOG_WARNING,
"CDR on channel '%s' already started\n", chan);
00144 gettimeofday(&cdr->
start, NULL);
00145 }
00146 cdr = cdr->
next;
00147 }
00148 }
00149
00150 void ast_cdr_answer(
struct ast_cdr *cdr)
00151 {
00152
char *chan;
00153
while (cdr) {
00154 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00155
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00156
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00157
if (cdr->
disposition <
AST_CDR_ANSWERED)
00158 cdr->
disposition =
AST_CDR_ANSWERED;
00159
if (!cdr->
answer.tv_sec && !cdr->
answer.tv_usec) {
00160 gettimeofday(&cdr->
answer, NULL);
00161 }
00162 cdr = cdr->
next;
00163 }
00164 }
00165
00166 void ast_cdr_busy(
struct ast_cdr *cdr)
00167 {
00168
char *chan;
00169
while (cdr) {
00170
if (!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED)) {
00171 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00172
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00173
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00174
if (cdr->
disposition <
AST_CDR_BUSY)
00175 cdr->
disposition =
AST_CDR_BUSY;
00176 }
00177 cdr = cdr->
next;
00178 }
00179 }
00180
00181 void ast_cdr_failed(
struct ast_cdr *cdr)
00182 {
00183
char *chan;
00184
while (cdr) {
00185 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00186
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00187
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00188
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED))
00189 cdr->
disposition =
AST_CDR_FAILED;
00190 cdr = cdr->
next;
00191 }
00192 }
00193
00194 int ast_cdr_disposition(
struct ast_cdr *cdr,
int cause)
00195 {
00196
int res = 0;
00197
while (cdr) {
00198
switch(cause) {
00199
case AST_CAUSE_BUSY:
00200
ast_cdr_busy(cdr);
00201
break;
00202
case AST_CAUSE_FAILURE:
00203
ast_cdr_failed(cdr);
00204
break;
00205
case AST_CAUSE_NORMAL:
00206
break;
00207
case AST_CAUSE_NOTDEFINED:
00208 res = -1;
00209
break;
00210
default:
00211 res = -1;
00212
ast_log(
LOG_WARNING,
"We don't handle that cause yet\n");
00213 }
00214 cdr = cdr->
next;
00215 }
00216
return res;
00217 }
00218
00219 void ast_cdr_setdestchan(
struct ast_cdr *cdr,
char *chann)
00220 {
00221
char *chan;
00222
while (cdr) {
00223 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00224
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00225
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00226
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED))
00227 strncpy(cdr->
dstchannel, chann,
sizeof(cdr->
dstchannel) - 1);
00228 cdr = cdr->
next;
00229 }
00230 }
00231
00232 void ast_cdr_setapp(
struct ast_cdr *cdr,
char *app,
char *data)
00233 {
00234
char *chan;
00235
while (cdr) {
00236
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED)) {
00237 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00238
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00239
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00240
if (!app)
00241 app =
"";
00242 strncpy(cdr->
lastapp, app,
sizeof(cdr->
lastapp) - 1);
00243
if (!data)
00244 data =
"";
00245 strncpy(cdr->
lastdata, data,
sizeof(cdr->
lastdata) - 1);
00246 }
00247 cdr = cdr->
next;
00248 }
00249 }
00250
00251 int ast_cdr_setcid(
struct ast_cdr *cdr,
struct ast_channel *c)
00252 {
00253
char tmp[
AST_MAX_EXTENSION] =
"";
00254
char *num, *name;
00255
while (cdr) {
00256
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED)) {
00257
00258
if (c->
ani)
00259 strncpy(tmp, c->
ani,
sizeof(tmp) - 1);
00260
else if (c->
callerid)
00261 strncpy(tmp, c->
callerid,
sizeof(tmp) - 1);
00262
if (c->
callerid)
00263 strncpy(cdr->
clid, c->
callerid,
sizeof(cdr->
clid) - 1);
00264 name = NULL;
00265 num = NULL;
00266
ast_callerid_parse(tmp, &name, &num);
00267
if (num) {
00268
ast_shrink_phone_number(num);
00269 strncpy(cdr->
src, num,
sizeof(cdr->
src) - 1);
00270 }
00271 }
00272 cdr = cdr->
next;
00273 }
00274
return 0;
00275 }
00276
00277 int ast_cdr_init(
struct ast_cdr *cdr,
struct ast_channel *c)
00278 {
00279
char *chan;
00280
char *num, *name;
00281
char tmp[
AST_MAX_EXTENSION] =
"";
00282
while (cdr) {
00283
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED)) {
00284 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00285
if (!ast_strlen_zero(cdr->
channel))
00286
ast_log(
LOG_WARNING,
"CDR already initialized on '%s'\n", chan);
00287 strncpy(cdr->
channel, c->
name,
sizeof(cdr->
channel) - 1);
00288
00289
if (c->
ani)
00290 strncpy(tmp, c->
ani,
sizeof(tmp) - 1);
00291
else if (c->
callerid)
00292 strncpy(tmp, c->
callerid,
sizeof(tmp) - 1);
00293
if (c->
callerid)
00294 strncpy(cdr->
clid, c->
callerid,
sizeof(cdr->
clid) - 1);
00295 name = NULL;
00296 num = NULL;
00297
ast_callerid_parse(tmp, &name, &num);
00298
if (num) {
00299
ast_shrink_phone_number(num);
00300 strncpy(cdr->
src, num,
sizeof(cdr->
src) - 1);
00301 }
00302
00303
if (c->
_state ==
AST_STATE_UP)
00304 cdr->
disposition =
AST_CDR_ANSWERED;
00305
else
00306 cdr->
disposition =
AST_CDR_NOANSWER;
00307
if (c->
amaflags)
00308 cdr->
amaflags = c->
amaflags;
00309
else
00310 cdr->
amaflags =
ast_default_amaflags;
00311 strncpy(cdr->
accountcode, c->
accountcode,
sizeof(cdr->
accountcode) - 1);
00312
00313 strncpy(cdr->
dst, c->
exten,
sizeof(cdr->
dst) - 1);
00314 strncpy(cdr->
dcontext, c->
context,
sizeof(cdr->
dcontext) - 1);
00315
00316 strncpy(cdr->
uniqueid, c->
uniqueid,
sizeof(cdr->
uniqueid) - 1);
00317 }
00318 cdr = cdr->
next;
00319 }
00320
return 0;
00321 }
00322
00323 void ast_cdr_end(
struct ast_cdr *cdr)
00324 {
00325
char *chan;
00326
while (cdr) {
00327 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00328
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00329
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00330
if (!cdr->
start.tv_sec && !cdr->
start.tv_usec)
00331
ast_log(
LOG_WARNING,
"CDR on channel '%s' has not started\n", chan);
00332
if (!cdr->
end.tv_sec && !cdr->
end.tv_usec)
00333 gettimeofday(&cdr->
end, NULL);
00334 cdr = cdr->
next;
00335 }
00336 }
00337
00338 char *
ast_cdr_disp2str(
int disposition)
00339 {
00340
switch (disposition) {
00341
case AST_CDR_NOANSWER:
00342
return "NO ANSWER";
00343
case AST_CDR_FAILED:
00344
return "FAILED";
00345
case AST_CDR_BUSY:
00346
return "BUSY";
00347
case AST_CDR_ANSWERED:
00348
return "ANSWERED";
00349
default:
00350
return "UNKNOWN";
00351 }
00352 }
00353
00354 char *
ast_cdr_flags2str(
int flag)
00355 {
00356
switch(flag) {
00357
case AST_CDR_OMIT:
00358
return "OMIT";
00359
case AST_CDR_BILLING:
00360
return "BILLING";
00361
case AST_CDR_DOCUMENTATION:
00362
return "DOCUMENTATION";
00363 }
00364
return "Unknown";
00365 }
00366
00367 int ast_cdr_setaccount(
struct ast_channel *chan,
char *account)
00368 {
00369
struct ast_cdr *cdr = chan->
cdr;
00370
00371 strncpy(chan->
accountcode, account,
sizeof(chan->
accountcode) - 1);
00372
while (cdr) {
00373
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED))
00374 strncpy(cdr->accountcode, chan->
accountcode,
sizeof(cdr->accountcode) - 1);
00375 cdr = cdr->next;
00376 }
00377
return 0;
00378 }
00379
00380 int ast_cdr_setamaflags(
struct ast_channel *chan,
char *flag)
00381 {
00382
struct ast_cdr *cdr = chan->
cdr;
00383
int newflag;
00384
00385 newflag =
ast_cdr_amaflags2int(flag);
00386
if (newflag) {
00387 cdr->amaflags = newflag;
00388 }
00389
return 0;
00390 }
00391
00392 int ast_cdr_setuserfield(
struct ast_channel *chan,
char *userfield)
00393 {
00394
struct ast_cdr *cdr = chan->
cdr;
00395
00396
while (cdr) {
00397
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED))
00398 strncpy(cdr->userfield, userfield,
sizeof(cdr->userfield) - 1);
00399 cdr = cdr->next;
00400 }
00401
return 0;
00402 }
00403
00404 int ast_cdr_appenduserfield(
struct ast_channel *chan,
char *userfield)
00405 {
00406
struct ast_cdr *cdr = chan->
cdr;
00407
00408
while (cdr)
00409 {
00410
00411
int len = strlen(cdr->userfield);
00412
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED))
00413 strncpy(cdr->userfield+len, userfield,
sizeof(cdr->userfield) - len - 1);
00414 cdr = cdr->next;
00415 }
00416
return 0;
00417 }
00418
00419 int ast_cdr_update(
struct ast_channel *c)
00420 {
00421
struct ast_cdr *cdr = c->
cdr;
00422
char *name, *num;
00423
char tmp[
AST_MAX_EXTENSION] =
"";
00424
00425
while (cdr) {
00426
if(!
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_LOCKED)) {
00427
if (c->
ani)
00428 strncpy(tmp, c->
ani,
sizeof(tmp) - 1);
00429
else if (c->
callerid && !ast_strlen_zero(c->
callerid))
00430 strncpy(tmp, c->
callerid,
sizeof(tmp) - 1);
00431
if (c->
callerid && !ast_strlen_zero(c->
callerid))
00432 strncpy(cdr->clid, c->
callerid,
sizeof(cdr->clid) - 1);
00433
else
00434 cdr->clid[0] =
'\0';
00435 name = NULL;
00436 num = NULL;
00437
ast_callerid_parse(tmp, &name, &num);
00438
if (num) {
00439
ast_shrink_phone_number(num);
00440 strncpy(cdr->src, num,
sizeof(cdr->src) - 1);
00441 }
00442
00443 strncpy(cdr->accountcode, c->
accountcode,
sizeof(cdr->accountcode) - 1);
00444
00445
if (ast_strlen_zero(c->
macroexten))
00446 strncpy(cdr->dst, c->
exten,
sizeof(cdr->dst) - 1);
00447
else
00448 strncpy(cdr->dst, c->
macroexten,
sizeof(cdr->dst) - 1);
00449
if (ast_strlen_zero(c->
macrocontext))
00450 strncpy(cdr->dcontext, c->
context,
sizeof(cdr->dcontext) - 1);
00451
else
00452 strncpy(cdr->dcontext, c->
macrocontext,
sizeof(cdr->dcontext) - 1);
00453 }
00454 cdr = cdr->next;
00455 }
00456
00457
return 0;
00458 }
00459
00460 int ast_cdr_amaflags2int(
char *flag)
00461 {
00462
if (!strcasecmp(flag,
"default"))
00463
return 0;
00464
if (!strcasecmp(flag,
"omit"))
00465
return AST_CDR_OMIT;
00466
if (!strcasecmp(flag,
"billing"))
00467
return AST_CDR_BILLING;
00468
if (!strcasecmp(flag,
"documentation"))
00469
return AST_CDR_DOCUMENTATION;
00470
return -1;
00471 }
00472
00473 void ast_cdr_post(
struct ast_cdr *cdr)
00474 {
00475
char *chan;
00476
struct ast_cdr_beitem *i;
00477
while (cdr) {
00478 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00479
if (
ast_cdr_has_flag(cdr,
AST_CDR_FLAG_POSTED))
00480
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00481
if (!cdr->
end.tv_sec && !cdr->
end.tv_usec)
00482
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks end\n", chan);
00483
if (!cdr->
start.tv_sec && !cdr->
start.tv_usec)
00484
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks start\n", chan);
00485 cdr->
duration = cdr->
end.tv_sec - cdr->
start.tv_sec + (cdr->
end.tv_usec - cdr->
start.tv_usec) / 1000000;
00486
if (cdr->
answer.tv_sec || cdr->
answer.tv_usec) {
00487 cdr->
billsec = cdr->
end.tv_sec - cdr->
answer.tv_sec + (cdr->
end.tv_usec - cdr->
answer.tv_usec) / 1000000;
00488 }
else
00489 cdr->
billsec = 0;
00490
ast_cdr_add_flag(cdr,
AST_CDR_FLAG_POSTED);
00491
ast_mutex_lock(&cdrlock);
00492 i = bes;
00493
while(i) {
00494 i->be(cdr);
00495 i = i->next;
00496 }
00497
ast_mutex_unlock(&cdrlock);
00498 cdr = cdr->
next;
00499 }
00500 }
00501
00502 void ast_cdr_reset(
struct ast_cdr *cdr,
int post)
00503 {
00504
while (cdr) {
00505
00506
if (post) {
00507
ast_cdr_end(cdr);
00508
ast_cdr_post(cdr);
00509 }
00510
00511 cdr->
flags=0;
00512 memset(&cdr->
start, 0,
sizeof(cdr->
start));
00513 memset(&cdr->
end, 0,
sizeof(cdr->
end));
00514 memset(&cdr->
answer, 0,
sizeof(cdr->
answer));
00515 cdr->
billsec = 0;
00516 cdr->
duration = 0;
00517
ast_cdr_start(cdr);
00518 cdr->
disposition =
AST_CDR_NOANSWER;
00519 cdr = cdr->
next;
00520 }
00521 }
00522
00523 void ast_cdr_append(
struct ast_cdr *cdr,
struct ast_cdr *newcdr) {
00524
if (cdr) {
00525
while(cdr->
next)
00526 cdr = cdr->
next;
00527 cdr->
next = newcdr;
00528 }
else
00529
ast_log(
LOG_ERROR,
"Can't append a CDR to NULL!\n");
00530 }