German language improvements (bug #1606)
[asterisk/asterisk.git] / cdr.c
diff --git a/cdr.c b/cdr.c
index ee65417..67acf10 100755 (executable)
--- a/cdr.c
+++ b/cdr.c
 #include <asterisk/cdr.h>
 #include <asterisk/logger.h>
 #include <asterisk/callerid.h>
+#include <asterisk/causes.h>
+#include <asterisk/options.h>
+#include <asterisk/utils.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
 #include <pthread.h>
 
 int ast_default_amaflags = AST_CDR_DOCUMENTATION;
 char ast_default_accountcode[20] = "";
 
-static pthread_mutex_t cdrlock = AST_MUTEX_INITIALIZER;
+static ast_mutex_t cdrlock = AST_MUTEX_INITIALIZER;
 
 static struct ast_cdr_beitem {
        char name[20];
@@ -51,14 +55,14 @@ int ast_cdr_register(char *name, char *desc, ast_cdrbe be)
                ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
                return -1;
        }
-       ast_pthread_mutex_lock(&cdrlock);
+       ast_mutex_lock(&cdrlock);
        i = bes;
        while(i) {
                if (!strcasecmp(name, i->name))
                        break;
                i = i->next;
        }
-       ast_pthread_mutex_unlock(&cdrlock);
+       ast_mutex_unlock(&cdrlock);
        if (i) {
                ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
                return -1;
@@ -70,17 +74,17 @@ int ast_cdr_register(char *name, char *desc, ast_cdrbe be)
        strncpy(i->name, name, sizeof(i->name) - 1);
        strncpy(i->desc, desc, sizeof(i->desc) - 1);
        i->be = be;
-       ast_pthread_mutex_lock(&cdrlock);
+       ast_mutex_lock(&cdrlock);
        i->next = bes;
        bes = i;
-       ast_pthread_mutex_unlock(&cdrlock);
+       ast_mutex_unlock(&cdrlock);
        return 0;
 }
 
 void ast_cdr_unregister(char *name)
 {
        struct ast_cdr_beitem *i, *prev = NULL;
-       ast_pthread_mutex_lock(&cdrlock);
+       ast_mutex_lock(&cdrlock);
        i = bes;
        while(i) {
                if (!strcasecmp(name, i->name)) {
@@ -92,7 +96,9 @@ void ast_cdr_unregister(char *name)
                }
                i = i->next;
        }
-       ast_pthread_mutex_unlock(&cdrlock);
+       if (option_verbose > 1)
+               ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s' CDR backend\n", name);
+       ast_mutex_unlock(&cdrlock);
        if (i) 
                free(i);
 }
@@ -101,7 +107,7 @@ void ast_cdr_free(struct ast_cdr *cdr)
 {
        char *chan; 
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (!cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' not posted\n", chan);
                if (!cdr->end.tv_sec && !cdr->end.tv_usec)
@@ -126,7 +132,7 @@ void ast_cdr_start(struct ast_cdr *cdr)
 {
        char *chan; 
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                if (cdr->start.tv_sec || cdr->start.tv_usec)
@@ -139,7 +145,7 @@ void ast_cdr_answer(struct ast_cdr *cdr)
 {
        char *chan; 
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                if (cdr->disposition < AST_CDR_ANSWERED)
@@ -154,7 +160,7 @@ void ast_cdr_busy(struct ast_cdr *cdr)
 {
        char *chan; 
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                if (cdr->disposition < AST_CDR_BUSY)
@@ -162,11 +168,46 @@ void ast_cdr_busy(struct ast_cdr *cdr)
        }
 }
 
+void ast_cdr_failed(struct ast_cdr *cdr)
+{
+       char *chan; 
+       if (cdr) {
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
+               if (cdr->posted)
+                       ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
+                       cdr->disposition = AST_CDR_FAILED;
+       }
+}
+
+int ast_cdr_disposition(struct ast_cdr *cdr, int cause)
+{
+       int res = 0;
+       if (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, "We don't handle that cause yet\n");
+               }
+       }
+       return res;
+}
+
 void ast_cdr_setdestchan(struct ast_cdr *cdr, char *chann)
 {
        char *chan; 
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                strncpy(cdr->dstchannel, chann, sizeof(cdr->dstchannel) - 1);
@@ -177,7 +218,7 @@ void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
 {
        char *chan; 
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                if (!app)
@@ -189,14 +230,37 @@ void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
        }
 }
 
+int ast_cdr_setcid(struct ast_cdr *cdr, struct ast_channel *c)
+{
+       char tmp[AST_MAX_EXTENSION] = "";
+       char *num, *name;
+       if (cdr) {
+               /* Grab source from ANI or normal Caller*ID */
+               if (c->ani)
+                       strncpy(tmp, c->ani, sizeof(tmp) - 1);
+               else if (c->callerid)
+                       strncpy(tmp, c->callerid, sizeof(tmp) - 1);
+               if (c->callerid)
+                       strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1);
+               name = NULL;
+               num = NULL;
+               ast_callerid_parse(tmp, &name, &num);
+               if (num) {
+                       ast_shrink_phone_number(num);
+                       strncpy(cdr->src, num, sizeof(cdr->src) - 1);
+               }
+       }
+       return 0;
+}
+
 int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
 {
        char *chan;
        char *num, *name;
-       char tmp[AST_MAX_EXTENSION];
+       char tmp[AST_MAX_EXTENSION] = "";
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
-               if (strlen(cdr->channel)) 
+               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);
                /* Grab source from ANI or normal Caller*ID */
@@ -214,7 +278,7 @@ int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
                        strncpy(cdr->src, num, sizeof(cdr->src) - 1);
                }
                
-               if (c->state == AST_STATE_UP)
+               if (c->_state == AST_STATE_UP)
                        cdr->disposition = AST_CDR_ANSWERED;
                else
                        cdr->disposition = AST_CDR_NOANSWER;
@@ -226,6 +290,8 @@ int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *c)
                /* Destination information */
                strncpy(cdr->dst, c->exten, sizeof(cdr->dst) - 1);
                strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1);
+               /* Unique call identifier */
+               strncpy(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid) - 1);
        }
        return 0;
 }
@@ -234,7 +300,7 @@ void ast_cdr_end(struct ast_cdr *cdr)
 {
        char *chan;
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                if (!cdr->start.tv_sec && !cdr->start.tv_usec)
@@ -249,6 +315,8 @@ char *ast_cdr_disp2str(int disposition)
        switch (disposition) {
        case AST_CDR_NOANSWER:
                return "NO ANSWER";
+       case AST_CDR_FAILED:
+               return "FAILED";                
        case AST_CDR_BUSY:
                return "BUSY";          
        case AST_CDR_ANSWERED:
@@ -271,6 +339,68 @@ char *ast_cdr_flags2str(int flag)
        return "Unknown";
 }
 
+int ast_cdr_setaccount(struct ast_channel *chan, char *account)
+{
+       struct ast_cdr *cdr = chan->cdr;
+
+       strncpy(chan->accountcode, account, sizeof(chan->accountcode) - 1);
+       if (cdr)
+               strncpy(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode) - 1);
+       return 0;
+}
+
+int ast_cdr_setuserfield(struct ast_channel *chan, char *userfield)
+{
+       struct ast_cdr *cdr = chan->cdr;
+
+       if (cdr)
+               strncpy(cdr->userfield, userfield, sizeof(cdr->userfield) - 1);
+       return 0;
+}
+
+int ast_cdr_appenduserfield(struct ast_channel *chan, char *userfield)
+{
+       struct ast_cdr *cdr = chan->cdr;
+
+       if (cdr)
+       {
+               int len = strlen(cdr->userfield);
+               strncpy(cdr->userfield+len, userfield, sizeof(cdr->userfield) - len - 1);
+       }
+       return 0;
+}
+
+int ast_cdr_update(struct ast_channel *c)
+{
+       struct ast_cdr *cdr = c->cdr;
+       char *name, *num;
+       char tmp[AST_MAX_EXTENSION] = "";
+       /* Grab source from ANI or normal Caller*ID */
+       if (cdr) {
+               if (c->ani)
+                       strncpy(tmp, c->ani, sizeof(tmp) - 1);
+               else if (c->callerid && !ast_strlen_zero(c->callerid))
+                       strncpy(tmp, c->callerid, sizeof(tmp) - 1);
+               if (c->callerid && !ast_strlen_zero(c->callerid))
+                       strncpy(cdr->clid, c->callerid, sizeof(cdr->clid) - 1);
+               else
+                       strcpy(cdr->clid, "");
+               name = NULL;
+               num = NULL;
+               ast_callerid_parse(tmp, &name, &num);
+               if (num) {
+                       ast_shrink_phone_number(num);
+                       strncpy(cdr->src, num, sizeof(cdr->src) - 1);
+               }
+               /* Copy account code et-al */   
+               strncpy(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode) - 1);
+               /* Destination information */
+               strncpy(cdr->dst, c->exten, sizeof(cdr->dst) - 1);
+               strncpy(cdr->dcontext, c->context, sizeof(cdr->dcontext) - 1);
+       }
+       return 0;
+}
+
 int ast_cdr_amaflags2int(char *flag)
 {
        if (!strcasecmp(flag, "default"))
@@ -289,7 +419,7 @@ void ast_cdr_post(struct ast_cdr *cdr)
        char *chan;
        struct ast_cdr_beitem *i;
        if (cdr) {
-               chan = strlen(cdr->channel) ? cdr->channel : "<unknown>";
+               chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
                if (cdr->posted)
                        ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
                if (!cdr->end.tv_sec && !cdr->end.tv_usec)
@@ -302,12 +432,32 @@ void ast_cdr_post(struct ast_cdr *cdr)
                } else
                        cdr->billsec = 0;
                cdr->posted = 1;
-               ast_pthread_mutex_lock(&cdrlock);
+               ast_mutex_lock(&cdrlock);
                i = bes;
                while(i) {
                        i->be(cdr);
                        i = i->next;
                }
-               ast_pthread_mutex_unlock(&cdrlock);
+               ast_mutex_unlock(&cdrlock);
+       }
+}
+
+void ast_cdr_reset(struct ast_cdr *cdr, int post)
+{
+       if (cdr) {
+               /* Post if requested */
+               if (post) {
+                       ast_cdr_end(cdr);
+                       ast_cdr_post(cdr);
+               }
+               /* Reset to initial state */
+               cdr->posted = 0;
+               memset(&cdr->start, 0, sizeof(cdr->start));
+               memset(&cdr->end, 0, sizeof(cdr->end));
+               memset(&cdr->answer, 0, sizeof(cdr->answer));
+               cdr->billsec = 0;
+               cdr->duration = 0;
+               ast_cdr_start(cdr);
+               cdr->disposition = AST_CDR_NOANSWER;
        }
 }