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 <unistd.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <pthread.h>
00026
00027 int ast_default_amaflags = AST_CDR_DOCUMENTATION;
00028 char ast_default_accountcode[20] = "";
00029
00030 static ast_mutex_t cdrlock = AST_MUTEX_INITIALIZER;
00031
00032 static struct ast_cdr_beitem {
00033 char name[20];
00034 char desc[80];
00035 ast_cdrbe be;
00036 struct ast_cdr_beitem *next;
00037 } *bes = NULL;
00038
00039
00040
00041
00042
00043
00044
00045
00046 int ast_cdr_register(char *name, char *desc, ast_cdrbe be)
00047 {
00048 struct ast_cdr_beitem *i;
00049 if (!name)
00050 return -1;
00051 if (!be) {
00052 ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
00053 return -1;
00054 }
00055 ast_mutex_lock(&cdrlock);
00056 i = bes;
00057 while(i) {
00058 if (!strcasecmp(name, i->name))
00059 break;
00060 i = i->next;
00061 }
00062 ast_mutex_unlock(&cdrlock);
00063 if (i) {
00064 ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
00065 return -1;
00066 }
00067 i = malloc(sizeof(struct ast_cdr_beitem));
00068 if (!i)
00069 return -1;
00070 memset(i, 0, sizeof(struct ast_cdr_beitem));
00071 strncpy(i->name, name, sizeof(i->name) - 1);
00072 strncpy(i->desc, desc, sizeof(i->desc) - 1);
00073 i->be = be;
00074 ast_mutex_lock(&cdrlock);
00075 i->next = bes;
00076 bes = i;
00077 ast_mutex_unlock(&cdrlock);
00078 return 0;
00079 }
00080
00081 void ast_cdr_unregister(char *name)
00082 {
00083 struct ast_cdr_beitem *i, *prev = NULL;
00084 ast_mutex_lock(&cdrlock);
00085 i = bes;
00086 while(i) {
00087 if (!strcasecmp(name, i->name)) {
00088 if (prev)
00089 prev->next = i->next;
00090 else
00091 bes = i->next;
00092 break;
00093 }
00094 i = i->next;
00095 }
00096 ast_mutex_unlock(&cdrlock);
00097 if (i)
00098 free(i);
00099 }
00100
00101 void ast_cdr_free(struct ast_cdr *cdr)
00102 {
00103 char *chan;
00104 if (cdr) {
00105 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00106 if (!cdr->posted)
00107 ast_log(LOG_WARNING, "CDR on channel '%s' not posted\n", chan);
00108 if (!cdr->end.tv_sec && !cdr->end.tv_usec)
00109 ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
00110 if (!cdr->start.tv_sec && !cdr->start.tv_usec)
00111 ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
00112 free(cdr);
00113 }
00114 }
00115
00116 struct ast_cdr *ast_cdr_alloc(void)
00117 {
00118 struct ast_cdr *cdr;
00119 cdr = malloc(sizeof(struct ast_cdr));
00120 if (cdr) {
00121 memset(cdr, 0, sizeof(struct ast_cdr));
00122 }
00123 return cdr;
00124 }
00125
00126 void ast_cdr_start(struct ast_cdr *cdr)
00127 {
00128 char *chan;
00129 if (cdr) {
00130 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00131 if (cdr->posted)
00132 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00133 if (cdr->start.tv_sec || cdr->start.tv_usec)
00134 ast_log(LOG_WARNING, "CDR on channel '%s' already started\n", chan);
00135 gettimeofday(&cdr->start, NULL);
00136 }
00137 }
00138
00139 void ast_cdr_answer(struct ast_cdr *cdr)
00140 {
00141 char *chan;
00142 if (cdr) {
00143 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00144 if (cdr->posted)
00145 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00146 if (cdr->disposition < AST_CDR_ANSWERED)
00147 cdr->disposition = AST_CDR_ANSWERED;
00148 if (!cdr->answer.tv_sec && !cdr->answer.tv_usec) {
00149 gettimeofday(&cdr->answer, NULL);
00150 }
00151 }
00152 }
00153
00154 void ast_cdr_busy(struct ast_cdr *cdr)
00155 {
00156 char *chan;
00157 if (cdr) {
00158 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00159 if (cdr->posted)
00160 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00161 if (cdr->disposition < AST_CDR_BUSY)
00162 cdr->disposition = AST_CDR_BUSY;
00163 }
00164 }
00165
00166 void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann)
00167 {
00168 char *chan;
00169 if (cdr) {
00170 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00171 if (cdr->posted)
00172 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00173 strncpy(cdr->dstchannel, chann, sizeof(cdr->dstchannel) - 1);
00174 }
00175 }
00176
00177 void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
00178 {
00179 char *chan;
00180 if (cdr) {
00181 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00182 if (cdr->posted)
00183 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00184 if (!app)
00185 app = "";
00186 strncpy(cdr->lastapp, app, sizeof(cdr->lastapp) - 1);
00187 if (!data)
00188 data = "";
00189 strncpy(cdr->lastdata, data, sizeof(cdr->lastdata) - 1);
00190 }
00191 }
00192
00193 int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
00194 {
00195 char tmp[AST_MAX_EXTENSION] = "";
00196 char *num, *name;
00197 if (cdr) {
00198
00199 if (c->ani)
00200 strncpy(tmp, c->ani, sizeof(tmp) - 1);
00201 else if (c->callerid)
00202 strncpy(tmp, c->callerid, sizeof(tmp) - 1);
00203 if (c->callerid)
00204 strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1);
00205 name = NULL;
00206 num = NULL;
00207 ast_callerid_parse(tmp, &name, &num);
00208 if (num) {
00209 ast_shrink_phone_number(num);
00210 strncpy(cdr->src, num, sizeof(cdr->src) - 1);
00211 }
00212 }
00213 return 0;
00214 }
00215
00216 int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
00217 {
00218 char *chan;
00219 char *num, *name;
00220 char tmp[AST_MAX_EXTENSION] = "";
00221 if (cdr) {
00222 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00223 if (strlen(cdr->channel))
00224 ast_log(LOG_WARNING, "CDR already initialized on '%s'\n", chan);
00225 strncpy(cdr->channel, c->name, sizeof(cdr->channel) - 1);
00226
00227 if (c->ani)
00228 strncpy(tmp, c->ani, sizeof(tmp) - 1);
00229 else if (c->callerid)
00230 strncpy(tmp, c->callerid, sizeof(tmp) - 1);
00231 if (c->callerid)
00232 strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1);
00233 name = NULL;
00234 num = NULL;
00235 ast_callerid_parse(tmp, &name, &num);
00236 if (num) {
00237 ast_shrink_phone_number(num);
00238 strncpy(cdr->src, num, sizeof(cdr->src) - 1);
00239 }
00240
00241 if (c->_state == AST_STATE_UP)
00242 cdr->disposition = AST_CDR_ANSWERED;
00243 else
00244 cdr->disposition = AST_CDR_NOANSWER;
00245 if (c->amaflags)
00246 cdr->amaflags = c->amaflags;
00247 else
00248 cdr->amaflags = ast_default_amaflags;
00249 strncpy(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode) - 1);
00250
00251 strncpy(cdr->dst, c->exten, sizeof(cdr->dst) - 1);
00252 strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1);
00253
00254 strncpy(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid) - 1);
00255 }
00256 return 0;
00257 }
00258
00259 void ast_cdr_end(struct ast_cdr *cdr)
00260 {
00261 char *chan;
00262 if (cdr) {
00263 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00264 if (cdr->posted)
00265 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00266 if (!cdr->start.tv_sec && !cdr->start.tv_usec)
00267 ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", chan);
00268 if (!cdr->end.tv_sec && !cdr->end.tv_usec)
00269 gettimeofday(&cdr->end, NULL);
00270 }
00271 }
00272
00273 char *ast_cdr_disp2str(int disposition)
00274 {
00275 switch (disposition) {
00276 case AST_CDR_NOANSWER:
00277 return "NO ANSWER";
00278 case AST_CDR_BUSY:
00279 return "BUSY";
00280 case AST_CDR_ANSWERED:
00281 return "ANSWERED";
00282 default:
00283 return "UNKNOWN";
00284 }
00285 }
00286
00287 char *ast_cdr_flags2str(int flag)
00288 {
00289 switch(flag) {
00290 case AST_CDR_OMIT:
00291 return "OMIT";
00292 case AST_CDR_BILLING:
00293 return "BILLING";
00294 case AST_CDR_DOCUMENTATION:
00295 return "DOCUMENTATION";
00296 }
00297 return "Unknown";
00298 }
00299
00300 int ast_cdr_setaccount(struct ast_channel *chan, char *account)
00301 {
00302 struct ast_cdr *cdr = chan->cdr;
00303
00304 strncpy(chan->accountcode, account, sizeof(chan->accountcode) - 1);
00305 if (cdr)
00306 strncpy(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode) - 1);
00307 return 0;
00308 }
00309
00310 int ast_cdr_update(struct ast_channel *c)
00311 {
00312 struct ast_cdr *cdr = c->cdr;
00313 char *name, *num;
00314 char tmp[AST_MAX_EXTENSION] = "";
00315
00316 if (c->ani)
00317 strncpy(tmp, c->ani, sizeof(tmp) - 1);
00318 else if (c->callerid)
00319 strncpy(tmp, c->callerid, sizeof(tmp) - 1);
00320 if (c->callerid)
00321 strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1);
00322 else
00323 strcpy(cdr->clid, "");
00324 name = NULL;
00325 num = NULL;
00326 ast_callerid_parse(tmp, &name, &num);
00327 if (num) {
00328 ast_shrink_phone_number(num);
00329 strncpy(cdr->src, num, sizeof(cdr->src) - 1);
00330 }
00331
00332 strncpy(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode) - 1);
00333
00334 strncpy(cdr->dst, c->exten, sizeof(cdr->dst) - 1);
00335 strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1);
00336 return 0;
00337 }
00338
00339 int ast_cdr_amaflags2int(char *flag)
00340 {
00341 if (!strcasecmp(flag, "default"))
00342 return 0;
00343 if (!strcasecmp(flag, "omit"))
00344 return AST_CDR_OMIT;
00345 if (!strcasecmp(flag, "billing"))
00346 return AST_CDR_BILLING;
00347 if (!strcasecmp(flag, "documentation"))
00348 return AST_CDR_DOCUMENTATION;
00349 return -1;
00350 }
00351
00352 void ast_cdr_post(struct ast_cdr *cdr)
00353 {
00354 char *chan;
00355 struct ast_cdr_beitem *i;
00356 if (cdr) {
00357 chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
00358 if (cdr->posted)
00359 ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
00360 if (!cdr->end.tv_sec && !cdr->end.tv_usec)
00361 ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
00362 if (!cdr->start.tv_sec && !cdr->start.tv_usec)
00363 ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
00364 cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec + (cdr->end.tv_usec - cdr->start.tv_usec) / 1000000;
00365 if (cdr->answer.tv_sec || cdr->answer.tv_usec) {
00366 cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec + (cdr->end.tv_usec - cdr->answer.tv_usec) / 1000000;
00367 } else
00368 cdr->billsec = 0;
00369 cdr->posted = 1;
00370 ast_mutex_lock(&cdrlock);
00371 i = bes;
00372 while(i) {
00373 i->be(cdr);
00374 i = i->next;
00375 }
00376 ast_mutex_unlock(&cdrlock);
00377 }
00378 }
00379
00380 void ast_cdr_reset(struct ast_cdr *cdr, int post)
00381 {
00382
00383 if (post) {
00384 ast_cdr_end(cdr);
00385 ast_cdr_post(cdr);
00386 }
00387
00388 cdr->posted = 0;
00389 memset(&cdr->start, 0, sizeof(cdr->start));
00390 memset(&cdr->end, 0, sizeof(cdr->end));
00391 memset(&cdr->answer, 0, sizeof(cdr->answer));
00392 cdr->billsec = 0;
00393 cdr->duration = 0;
00394 ast_cdr_start(cdr);
00395 cdr->disposition = AST_CDR_NOANSWER;
00396 }