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
#include <pthread.h>
00029
00030 int ast_default_amaflags =
AST_CDR_DOCUMENTATION;
00031 char ast_default_accountcode[20] =
"";
00032
00033
AST_MUTEX_DEFINE_STATIC(cdrlock);
00034
00035
static struct ast_cdr_beitem {
00036
char name[20];
00037
char desc[80];
00038
ast_cdrbe be;
00039
struct ast_cdr_beitem *next;
00040 } *bes = NULL;
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
if (cdr) {
00110 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00111
if (!cdr->
posted)
00112
ast_log(
LOG_WARNING,
"CDR on channel '%s' not posted\n", chan);
00113
if (!cdr->
end.tv_sec && !cdr->
end.tv_usec)
00114
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks end\n", chan);
00115
if (!cdr->
start.tv_sec && !cdr->
start.tv_usec)
00116
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks start\n", chan);
00117
free(cdr);
00118 }
00119 }
00120
00121 struct ast_cdr *
ast_cdr_alloc(
void)
00122 {
00123
struct ast_cdr *cdr;
00124 cdr =
malloc(
sizeof(
struct ast_cdr));
00125
if (cdr) {
00126 memset(cdr, 0,
sizeof(
struct ast_cdr));
00127 }
00128
return cdr;
00129 }
00130
00131 void ast_cdr_start(
struct ast_cdr *cdr)
00132 {
00133
char *chan;
00134
if (cdr) {
00135 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00136
if (cdr->
posted)
00137
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00138
if (cdr->
start.tv_sec || cdr->
start.tv_usec)
00139
ast_log(
LOG_WARNING,
"CDR on channel '%s' already started\n", chan);
00140 gettimeofday(&cdr->
start, NULL);
00141 }
00142 }
00143
00144 void ast_cdr_answer(
struct ast_cdr *cdr)
00145 {
00146
char *chan;
00147
if (cdr) {
00148 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00149
if (cdr->
posted)
00150
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00151
if (cdr->
disposition <
AST_CDR_ANSWERED)
00152 cdr->
disposition =
AST_CDR_ANSWERED;
00153
if (!cdr->
answer.tv_sec && !cdr->
answer.tv_usec) {
00154 gettimeofday(&cdr->
answer, NULL);
00155 }
00156 }
00157 }
00158
00159 void ast_cdr_busy(
struct ast_cdr *cdr)
00160 {
00161
char *chan;
00162
if (cdr) {
00163 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00164
if (cdr->
posted)
00165
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00166
if (cdr->
disposition <
AST_CDR_BUSY)
00167 cdr->
disposition =
AST_CDR_BUSY;
00168 }
00169 }
00170
00171 void ast_cdr_failed(
struct ast_cdr *cdr)
00172 {
00173
char *chan;
00174
if (cdr) {
00175 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00176
if (cdr->
posted)
00177
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00178 cdr->
disposition =
AST_CDR_FAILED;
00179 }
00180 }
00181
00182 int ast_cdr_disposition(
struct ast_cdr *cdr,
int cause)
00183 {
00184
int res = 0;
00185
if (cdr) {
00186
switch(cause) {
00187
case AST_CAUSE_BUSY:
00188
ast_cdr_busy(cdr);
00189
break;
00190
case AST_CAUSE_FAILURE:
00191
ast_cdr_failed(cdr);
00192
break;
00193
case AST_CAUSE_NORMAL:
00194
break;
00195
case AST_CAUSE_NOTDEFINED:
00196 res = -1;
00197
break;
00198
default:
00199 res = -1;
00200
ast_log(
LOG_WARNING,
"We don't handle that cause yet\n");
00201 }
00202 }
00203
return res;
00204 }
00205
00206 void ast_cdr_setdestchan(
struct ast_cdr *cdr,
char *chann)
00207 {
00208
char *chan;
00209
if (cdr) {
00210 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00211
if (cdr->
posted)
00212
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00213 strncpy(cdr->
dstchannel, chann,
sizeof(cdr->
dstchannel) - 1);
00214 }
00215 }
00216
00217 void ast_cdr_setapp(
struct ast_cdr *cdr,
char *app,
char *data)
00218 {
00219
char *chan;
00220
if (cdr) {
00221 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00222
if (cdr->
posted)
00223
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00224
if (!app)
00225 app =
"";
00226 strncpy(cdr->
lastapp, app,
sizeof(cdr->
lastapp) - 1);
00227
if (!data)
00228 data =
"";
00229 strncpy(cdr->
lastdata, data,
sizeof(cdr->
lastdata) - 1);
00230 }
00231 }
00232
00233 int ast_cdr_setcid(
struct ast_cdr *cdr,
struct ast_channel *c)
00234 {
00235
char tmp[
AST_MAX_EXTENSION] =
"";
00236
char *num, *name;
00237
if (cdr) {
00238
00239
if (c->
ani)
00240 strncpy(tmp, c->
ani,
sizeof(tmp) - 1);
00241
else if (c->
callerid)
00242 strncpy(tmp, c->
callerid,
sizeof(tmp) - 1);
00243
if (c->
callerid)
00244 strncpy(cdr->
clid, c->
callerid,
sizeof(cdr->
clid) - 1);
00245 name = NULL;
00246 num = NULL;
00247
ast_callerid_parse(tmp, &name, &num);
00248
if (num) {
00249
ast_shrink_phone_number(num);
00250 strncpy(cdr->
src, num,
sizeof(cdr->
src) - 1);
00251 }
00252 }
00253
return 0;
00254 }
00255
00256 int ast_cdr_init(
struct ast_cdr *cdr,
struct ast_channel *c)
00257 {
00258
char *chan;
00259
char *num, *name;
00260
char tmp[
AST_MAX_EXTENSION] =
"";
00261
if (cdr) {
00262 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00263
if (!ast_strlen_zero(cdr->
channel))
00264
ast_log(
LOG_WARNING,
"CDR already initialized on '%s'\n", chan);
00265 strncpy(cdr->
channel, c->
name,
sizeof(cdr->
channel) - 1);
00266
00267
if (c->
ani)
00268 strncpy(tmp, c->
ani,
sizeof(tmp) - 1);
00269
else if (c->
callerid)
00270 strncpy(tmp, c->
callerid,
sizeof(tmp) - 1);
00271
if (c->
callerid)
00272 strncpy(cdr->
clid, c->
callerid,
sizeof(cdr->
clid) - 1);
00273 name = NULL;
00274 num = NULL;
00275
ast_callerid_parse(tmp, &name, &num);
00276
if (num) {
00277
ast_shrink_phone_number(num);
00278 strncpy(cdr->
src, num,
sizeof(cdr->
src) - 1);
00279 }
00280
00281
if (c->
_state ==
AST_STATE_UP)
00282 cdr->
disposition =
AST_CDR_ANSWERED;
00283
else
00284 cdr->
disposition =
AST_CDR_NOANSWER;
00285
if (c->
amaflags)
00286 cdr->
amaflags = c->
amaflags;
00287
else
00288 cdr->
amaflags =
ast_default_amaflags;
00289 strncpy(cdr->
accountcode, c->
accountcode,
sizeof(cdr->
accountcode) - 1);
00290
00291 strncpy(cdr->
dst, c->
exten,
sizeof(cdr->
dst) - 1);
00292 strncpy(cdr->
dcontext, c->
context,
sizeof(cdr->
dcontext) - 1);
00293
00294 strncpy(cdr->
uniqueid, c->
uniqueid,
sizeof(cdr->
uniqueid) - 1);
00295 }
00296
return 0;
00297 }
00298
00299 void ast_cdr_end(
struct ast_cdr *cdr)
00300 {
00301
char *chan;
00302
if (cdr) {
00303 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00304
if (cdr->
posted)
00305
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00306
if (!cdr->
start.tv_sec && !cdr->
start.tv_usec)
00307
ast_log(
LOG_WARNING,
"CDR on channel '%s' has not started\n", chan);
00308
if (!cdr->
end.tv_sec && !cdr->
end.tv_usec)
00309 gettimeofday(&cdr->
end, NULL);
00310 }
00311 }
00312
00313 char *
ast_cdr_disp2str(
int disposition)
00314 {
00315
switch (disposition) {
00316
case AST_CDR_NOANSWER:
00317
return "NO ANSWER";
00318
case AST_CDR_FAILED:
00319
return "FAILED";
00320
case AST_CDR_BUSY:
00321
return "BUSY";
00322
case AST_CDR_ANSWERED:
00323
return "ANSWERED";
00324
default:
00325
return "UNKNOWN";
00326 }
00327 }
00328
00329 char *
ast_cdr_flags2str(
int flag)
00330 {
00331
switch(flag) {
00332
case AST_CDR_OMIT:
00333
return "OMIT";
00334
case AST_CDR_BILLING:
00335
return "BILLING";
00336
case AST_CDR_DOCUMENTATION:
00337
return "DOCUMENTATION";
00338 }
00339
return "Unknown";
00340 }
00341
00342 int ast_cdr_setaccount(
struct ast_channel *chan,
char *account)
00343 {
00344
struct ast_cdr *cdr = chan->
cdr;
00345
00346 strncpy(chan->
accountcode, account,
sizeof(chan->
accountcode) - 1);
00347
if (cdr)
00348 strncpy(cdr->accountcode, chan->
accountcode,
sizeof(cdr->accountcode) - 1);
00349
return 0;
00350 }
00351
00352 int ast_cdr_setuserfield(
struct ast_channel *chan,
char *userfield)
00353 {
00354
struct ast_cdr *cdr = chan->
cdr;
00355
00356
if (cdr)
00357 strncpy(cdr->userfield, userfield,
sizeof(cdr->userfield) - 1);
00358
return 0;
00359 }
00360
00361 int ast_cdr_appenduserfield(
struct ast_channel *chan,
char *userfield)
00362 {
00363
struct ast_cdr *cdr = chan->
cdr;
00364
00365
if (cdr)
00366 {
00367
int len = strlen(cdr->userfield);
00368 strncpy(cdr->userfield+len, userfield,
sizeof(cdr->userfield) - len - 1);
00369 }
00370
return 0;
00371 }
00372
00373 int ast_cdr_update(
struct ast_channel *c)
00374 {
00375
struct ast_cdr *cdr = c->
cdr;
00376
char *name, *num;
00377
char tmp[
AST_MAX_EXTENSION] =
"";
00378
00379
if (cdr) {
00380
if (c->
ani)
00381 strncpy(tmp, c->
ani,
sizeof(tmp) - 1);
00382
else if (c->
callerid && !ast_strlen_zero(c->
callerid))
00383 strncpy(tmp, c->
callerid,
sizeof(tmp) - 1);
00384
if (c->
callerid && !ast_strlen_zero(c->
callerid))
00385 strncpy(cdr->clid, c->
callerid,
sizeof(cdr->clid) - 1);
00386
else
00387 strcpy(cdr->clid,
"");
00388 name = NULL;
00389 num = NULL;
00390
ast_callerid_parse(tmp, &name, &num);
00391
if (num) {
00392
ast_shrink_phone_number(num);
00393 strncpy(cdr->src, num,
sizeof(cdr->src) - 1);
00394 }
00395
00396 strncpy(cdr->accountcode, c->
accountcode,
sizeof(cdr->accountcode) - 1);
00397
00398 strncpy(cdr->dst, c->
exten,
sizeof(cdr->dst) - 1);
00399 strncpy(cdr->dcontext, c->
context,
sizeof(cdr->dcontext) - 1);
00400 }
00401
return 0;
00402 }
00403
00404 int ast_cdr_amaflags2int(
char *flag)
00405 {
00406
if (!strcasecmp(flag,
"default"))
00407
return 0;
00408
if (!strcasecmp(flag,
"omit"))
00409
return AST_CDR_OMIT;
00410
if (!strcasecmp(flag,
"billing"))
00411
return AST_CDR_BILLING;
00412
if (!strcasecmp(flag,
"documentation"))
00413
return AST_CDR_DOCUMENTATION;
00414
return -1;
00415 }
00416
00417 void ast_cdr_post(
struct ast_cdr *cdr)
00418 {
00419
char *chan;
00420
struct ast_cdr_beitem *i;
00421
if (cdr) {
00422 chan = !ast_strlen_zero(cdr->
channel) ? cdr->
channel :
"<unknown>";
00423
if (cdr->
posted)
00424
ast_log(
LOG_WARNING,
"CDR on channel '%s' already posted\n", chan);
00425
if (!cdr->
end.tv_sec && !cdr->
end.tv_usec)
00426
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks end\n", chan);
00427
if (!cdr->
start.tv_sec && !cdr->
start.tv_usec)
00428
ast_log(
LOG_WARNING,
"CDR on channel '%s' lacks start\n", chan);
00429 cdr->
duration = cdr->
end.tv_sec - cdr->
start.tv_sec + (cdr->
end.tv_usec - cdr->
start.tv_usec) / 1000000;
00430
if (cdr->
answer.tv_sec || cdr->
answer.tv_usec) {
00431 cdr->
billsec = cdr->
end.tv_sec - cdr->
answer.tv_sec + (cdr->
end.tv_usec - cdr->
answer.tv_usec) / 1000000;
00432 }
else
00433 cdr->
billsec = 0;
00434 cdr->
posted = 1;
00435
ast_mutex_lock(&cdrlock);
00436 i = bes;
00437
while(i) {
00438 i->be(cdr);
00439 i = i->next;
00440 }
00441
ast_mutex_unlock(&cdrlock);
00442 }
00443 }
00444
00445 void ast_cdr_reset(
struct ast_cdr *cdr,
int post)
00446 {
00447
if (cdr) {
00448
00449
if (post) {
00450
ast_cdr_end(cdr);
00451
ast_cdr_post(cdr);
00452 }
00453
00454 cdr->
posted = 0;
00455 memset(&cdr->
start, 0,
sizeof(cdr->
start));
00456 memset(&cdr->
end, 0,
sizeof(cdr->
end));
00457 memset(&cdr->
answer, 0,
sizeof(cdr->
answer));
00458 cdr->
billsec = 0;
00459 cdr->
duration = 0;
00460
ast_cdr_start(cdr);
00461 cdr->
disposition =
AST_CDR_NOANSWER;
00462 }
00463 }