Thu Apr 28 2011 17:15:37

Asterisk developer's documentation


cdr.h File Reference

Call Detail Record API. More...

#include <sys/time.h>
#include "asterisk/channel.h"
#include "asterisk/utils.h"
Include dependency graph for cdr.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_cdr
 Responsible for call detail data. More...

Defines

#define AST_MAX_ACCOUNT_CODE   20
#define AST_MAX_USER_FIELD   256
CDR Flags
#define AST_CDR_FLAG_KEEP_VARS   (1 << 0)
#define AST_CDR_FLAG_POSTED   (1 << 1)
#define AST_CDR_FLAG_LOCKED   (1 << 2)
#define AST_CDR_FLAG_CHILD   (1 << 3)
#define AST_CDR_FLAG_POST_DISABLED   (1 << 4)
#define AST_CDR_FLAG_BRIDGED   (1 << 5)
#define AST_CDR_FLAG_MAIN   (1 << 6)
#define AST_CDR_FLAG_ENABLE   (1 << 7)
#define AST_CDR_FLAG_ANSLOCKED   (1 << 8)
#define AST_CDR_FLAG_DONT_TOUCH   (1 << 9)
#define AST_CDR_FLAG_POST_ENABLE   (1 << 10)
#define AST_CDR_FLAG_DIALED   (1 << 11)
#define AST_CDR_FLAG_ORIGINATED   (1 << 12)
CDR Flags - Disposition
#define AST_CDR_NOANSWER   0
#define AST_CDR_NULL   (1 << 0)
#define AST_CDR_FAILED   (1 << 1)
#define AST_CDR_BUSY   (1 << 2)
#define AST_CDR_ANSWERED   (1 << 3)
CDR AMA Flags
#define AST_CDR_OMIT   (1)
#define AST_CDR_BILLING   (2)
#define AST_CDR_DOCUMENTATION   (3)

Typedefs

typedef int(* ast_cdrbe )(struct ast_cdr *cdr)
 CDR backend callback.

Functions

struct ast_cdrast_cdr_alloc (void)
 Allocate a CDR record.
int ast_cdr_amaflags2int (const char *flag)
 Convert a string to a detail record AMA flag.
void ast_cdr_answer (struct ast_cdr *cdr)
 Answer a call.
struct ast_cdrast_cdr_append (struct ast_cdr *cdr, struct ast_cdr *newcdr)
int ast_cdr_appenduserfield (struct ast_channel *chan, const char *userfield)
 Append to CDR user field for channel (stored in CDR)
void ast_cdr_busy (struct ast_cdr *cdr)
 Busy a call.
int ast_cdr_copy_vars (struct ast_cdr *to_cdr, struct ast_cdr *from_cdr)
void ast_cdr_detach (struct ast_cdr *cdr)
 Detaches the detail record for posting (and freeing) either now or at a later time in bulk with other records during batch mode operation.
void ast_cdr_discard (struct ast_cdr *cdr)
 Discard and free a CDR record.
char * ast_cdr_disp2str (int disposition)
 Disposition to a string.
int ast_cdr_disposition (struct ast_cdr *cdr, int cause)
 Save the result of the call based on the AST_CAUSE_*.
struct ast_cdrast_cdr_dup (struct ast_cdr *cdr)
 Duplicate a record.
void ast_cdr_end (struct ast_cdr *cdr)
 End a call.
int ast_cdr_engine_init (void)
 Load the configuration file cdr.conf and possibly start the CDR scheduling thread.
int ast_cdr_engine_reload (void)
 Reload the configuration file cdr.conf and start/stop CDR scheduling thread.
void ast_cdr_engine_term (void)
void ast_cdr_failed (struct ast_cdr *cdr)
 Fail a call.
char * ast_cdr_flags2str (int flags)
void ast_cdr_free (struct ast_cdr *cdr)
 Free a CDR record.
void ast_cdr_free_vars (struct ast_cdr *cdr, int recur)
void ast_cdr_getvar (struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw)
int ast_cdr_init (struct ast_cdr *cdr, struct ast_channel *chan)
 Initialize based on a channel.
int ast_cdr_isset_unanswered (void)
void ast_cdr_merge (struct ast_cdr *to, struct ast_cdr *from)
 Move the non-null data from the "from" cdr to the "to" cdr.
void ast_cdr_noanswer (struct ast_cdr *cdr)
 A call wasn't answered.
int ast_cdr_register (const char *name, const char *desc, ast_cdrbe be)
 Register a CDR handling engine.
void ast_cdr_reset (struct ast_cdr *cdr, struct ast_flags *flags)
 Reset the detail record, optionally posting it first.
int ast_cdr_serialize_variables (struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
int ast_cdr_setaccount (struct ast_channel *chan, const char *account)
 Set account code, will generate AMI event.
int ast_cdr_setamaflags (struct ast_channel *chan, const char *amaflags)
 Set AMA flags for channel.
void ast_cdr_setanswer (struct ast_cdr *cdr, struct timeval t)
 Set the answer time for a call.
void ast_cdr_setapp (struct ast_cdr *cdr, const char *app, const char *data)
 Set the last executed application.
int ast_cdr_setcid (struct ast_cdr *cdr, struct ast_channel *chan)
 Initialize based on a channel.
void ast_cdr_setdestchan (struct ast_cdr *cdr, const char *chan)
 Set the destination channel, if there was one.
void ast_cdr_setdisposition (struct ast_cdr *cdr, long int disposition)
 Set the disposition for a call.
int ast_cdr_setuserfield (struct ast_channel *chan, const char *userfield)
 Set CDR user field for channel (stored in CDR)
int ast_cdr_setvar (struct ast_cdr *cdr, const char *name, const char *value, int recur)
void ast_cdr_specialized_reset (struct ast_cdr *cdr, struct ast_flags *flags)
void ast_cdr_start (struct ast_cdr *cdr)
 Start a call.
void ast_cdr_submit_batch (int shutdown)
 Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.
void ast_cdr_unregister (const char *name)
 Unregister a CDR handling engine.
int ast_cdr_update (struct ast_channel *chan)
int check_cdr_enabled (void)
 Return TRUE if CDR subsystem is enabled.

Variables

char ast_default_accountcode [AST_MAX_ACCOUNT_CODE]
int ast_default_amaflags

Detailed Description

Call Detail Record API.

Definition in file cdr.h.


Define Documentation

#define AST_CDR_ANSWERED   (1 << 3)
#define AST_CDR_BILLING   (2)

Definition at line 57 of file cdr.h.

Referenced by ast_cdr_amaflags2int(), and ast_cdr_flags2str().

#define AST_CDR_BUSY   (1 << 2)

Definition at line 50 of file cdr.h.

Referenced by ast_cdr_busy(), and ast_cdr_disp2str().

#define AST_CDR_DOCUMENTATION   (3)

Definition at line 58 of file cdr.h.

Referenced by ast_cdr_amaflags2int(), ast_cdr_flags2str(), and ast_cdr_merge().

#define AST_CDR_FAILED   (1 << 1)

Definition at line 49 of file cdr.h.

Referenced by ast_cdr_disp2str(), ast_cdr_end(), and ast_cdr_failed().

#define AST_CDR_FLAG_ANSLOCKED   (1 << 8)

Definition at line 38 of file cdr.h.

Referenced by ast_cdr_answer(), ast_cdr_fork(), and ast_cdr_setanswer().

#define AST_CDR_FLAG_BRIDGED   (1 << 5)

Definition at line 35 of file cdr.h.

Referenced by ast_bridge_call(), and ast_hangup().

#define AST_CDR_FLAG_CHILD   (1 << 3)

Definition at line 33 of file cdr.h.

Referenced by ast_cdr_fork(), and ast_cdr_merge().

#define AST_CDR_FLAG_DIALED   (1 << 11)

Definition at line 41 of file cdr.h.

Referenced by ast_bridge_call(), ast_call(), ast_hangup(), dial_exec_full(), and post_cdr().

#define AST_CDR_FLAG_DONT_TOUCH   (1 << 9)

Definition at line 39 of file cdr.h.

Referenced by ast_cdr_answer(), ast_cdr_end(), ast_cdr_fork(), ast_cdr_setanswer(), and ast_cdr_setvar().

#define AST_CDR_FLAG_ENABLE   (1 << 7)

Definition at line 37 of file cdr.h.

#define AST_CDR_FLAG_KEEP_VARS   (1 << 0)

Definition at line 30 of file cdr.h.

Referenced by ast_cdr_fork(), ast_cdr_merge(), ast_cdr_reset(), and forkcdr_exec().

#define AST_CDR_FLAG_MAIN   (1 << 6)

Definition at line 36 of file cdr.h.

Referenced by ast_bridge_call().

#define AST_CDR_FLAG_ORIGINATED   (1 << 12)

Definition at line 42 of file cdr.h.

Referenced by __ast_request_and_dial(), ast_call_forward(), and post_cdr().

#define AST_CDR_FLAG_POST_ENABLE   (1 << 10)

Definition at line 40 of file cdr.h.

Referenced by ast_cdr_reset().

#define AST_CDR_FLAG_POSTED   (1 << 1)

Definition at line 31 of file cdr.h.

Referenced by ast_cdr_merge(), ast_cdr_reset(), check_post(), disa_exec(), and post_cdr().

#define AST_CDR_NOANSWER   0

Definition at line 47 of file cdr.h.

Referenced by ast_cdr_disp2str(), ast_cdr_init(), ast_cdr_merge(), ast_cdr_noanswer(), and ast_cdr_reset().

#define AST_CDR_NULL   (1 << 0)

Definition at line 48 of file cdr.h.

Referenced by ast_bridge_call(), ast_cdr_disp2str(), ast_cdr_specialized_reset(), and ast_hangup().

#define AST_CDR_OMIT   (1)

Definition at line 56 of file cdr.h.

Referenced by ast_cdr_amaflags2int(), and ast_cdr_flags2str().

#define AST_MAX_ACCOUNT_CODE   20

Definition at line 62 of file cdr.h.

#define AST_MAX_USER_FIELD   256

Definition at line 61 of file cdr.h.

Referenced by tds_log().


Typedef Documentation

typedef int(* ast_cdrbe)(struct ast_cdr *cdr)

CDR backend callback.

Warning:
CDR backends should NOT attempt to access the channel associated with a CDR record. This channel is not guaranteed to exist when the CDR backend is invoked.

Definition at line 129 of file cdr.h.


Function Documentation

struct ast_cdr* ast_cdr_alloc ( void  ) [read]

Allocate a CDR record.

Return values:
amalloc'd ast_cdr structure
NULLon error (malloc failure)

Definition at line 460 of file cdr.c.

References ast_calloc, ast_log(), and LOG_ERROR.

Referenced by __agent_start_monitoring(), __ast_channel_alloc_ap(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_dup(), builtin_blindtransfer(), clear_caller(), findmeexec(), and start_monitor_exec().

{
   struct ast_cdr *x;
   x = ast_calloc(1, sizeof(*x));
   if (!x)
      ast_log(LOG_ERROR,"Allocation Failure for a CDR!\n");
   return x;
}
int ast_cdr_amaflags2int ( const char *  flag)

Convert a string to a detail record AMA flag.

Parameters:
flagstring form of flag Converts the string form of the flag to the binary form.
Returns:
the binary form of the flag

Definition at line 1021 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by ast_cdr_setamaflags(), build_device(), build_gateway(), build_peer(), build_user(), config_parse_variables(), process_dahdi(), and set_config().

{
   if (!strcasecmp(flag, "default"))
      return 0;
   if (!strcasecmp(flag, "omit"))
      return AST_CDR_OMIT;
   if (!strcasecmp(flag, "billing"))
      return AST_CDR_BILLING;
   if (!strcasecmp(flag, "documentation"))
      return AST_CDR_DOCUMENTATION;
   return -1;
}
void ast_cdr_answer ( struct ast_cdr cdr)

Answer a call.

Parameters:
cdrthe cdr you wish to associate with the call Starts all CDR stuff necessary for doing CDR when answering a call
Note:
NULL argument is just fine.

Definition at line 695 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), ast_tvzero(), check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_bridge_call(), and ast_raw_answer().

{

   for (; cdr; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED)) 
         continue;
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      if (cdr->disposition < AST_CDR_ANSWERED)
         cdr->disposition = AST_CDR_ANSWERED;
      if (ast_tvzero(cdr->answer))
         cdr->answer = ast_tvnow();
   }
}
struct ast_cdr* ast_cdr_append ( struct ast_cdr cdr,
struct ast_cdr newcdr 
) [read]

Definition at line 1134 of file cdr.c.

References ast_cdr::next.

Referenced by ast_cdr_fork(), ast_cdr_merge(), and attempt_transfer().

{
   struct ast_cdr *ret;

   if (cdr) {
      ret = cdr;

      while (cdr->next)
         cdr = cdr->next;
      cdr->next = newcdr;
   } else {
      ret = newcdr;
   }

   return ret;
}
int ast_cdr_appenduserfield ( struct ast_channel chan,
const char *  userfield 
)

Append to CDR user field for channel (stored in CDR)

Definition at line 987 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, len(), ast_cdr::next, and ast_cdr::userfield.

{
   struct ast_cdr *cdr = chan->cdr;

   for ( ; cdr ; cdr = cdr->next) {
      int len = strlen(cdr->userfield);

      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         ast_copy_string(cdr->userfield + len, userfield, sizeof(cdr->userfield) - len);
   }

   return 0;
}
void ast_cdr_busy ( struct ast_cdr cdr)

Busy a call.

Parameters:
cdrthe cdr you wish to associate with the call Marks the channel disposition as "BUSY" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing

Definition at line 711 of file cdr.c.

References AST_CDR_BUSY, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_cdr_disposition(), handle_cause(), pbx_builtin_busy(), ring_entry(), and wait_for_answer().

{

   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         cdr->disposition = AST_CDR_BUSY;
      }
   }
}
int ast_cdr_copy_vars ( struct ast_cdr to_cdr,
struct ast_cdr from_cdr 
)

Definition at line 344 of file cdr.c.

References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_assign(), ast_var_name(), ast_var_value(), val, var, and ast_cdr::varshead.

Referenced by ast_cdr_dup().

{
   struct ast_var_t *variables, *newvariable = NULL;
   struct varshead *headpa, *headpb;
   const char *var, *val;
   int x = 0;

   if (!to_cdr || !from_cdr) /* don't die if one of the pointers is null */
      return 0;

   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)) {
         newvariable = ast_var_assign(var, val);
         AST_LIST_INSERT_HEAD(headpb, newvariable, entries);
         x++;
      }
   }

   return x;
}
void ast_cdr_detach ( struct ast_cdr cdr)

Detaches the detail record for posting (and freeing) either now or at a later time in bulk with other records during batch mode operation.

Parameters:
cdrWhich CDR to detach from the channel thread Prevents the channel thread from blocking on the CDR handling Returns nothing

Definition at line 1239 of file cdr.c.

References ast_calloc, AST_CDR_FLAG_POST_DISABLED, ast_cdr_free(), ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, batch, batchmode, batchsize, ast_cdr_batch_item::cdr, cdr_batch_lock, enabled, ast_cdr_batch::head, init_batch(), ast_cdr_batch_item::next, post_cdr(), ast_cdr_batch::size, submit_unscheduled_batch(), and ast_cdr_batch::tail.

Referenced by ast_bridge_call(), ast_cdr_reset(), ast_hangup(), and ast_pbx_outgoing_cdr_failed().

{
   struct ast_cdr_batch_item *newtail;
   int curr;

   if (!cdr)
      return;

   /* maybe they disabled CDR stuff completely, so just drop it */
   if (!enabled) {
      ast_debug(1, "Dropping CDR !\n");
      ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
      ast_cdr_free(cdr);
      return;
   }

   /* post stuff immediately if we are not in batch mode, this is legacy behaviour */
   if (!batchmode) {
      post_cdr(cdr);
      ast_cdr_free(cdr);
      return;
   }

   /* otherwise, each CDR gets put into a batch list (at the end) */
   ast_debug(1, "CDR detaching from this thread\n");

   /* we'll need a new tail for every CDR */
   if (!(newtail = ast_calloc(1, sizeof(*newtail)))) {
      post_cdr(cdr);
      ast_cdr_free(cdr);
      return;
   }

   /* don't traverse a whole list (just keep track of the tail) */
   ast_mutex_lock(&cdr_batch_lock);
   if (!batch)
      init_batch();
   if (!batch->head) {
      /* new batch is empty, so point the head at the new tail */
      batch->head = newtail;
   } else {
      /* already got a batch with something in it, so just append a new tail */
      batch->tail->next = newtail;
   }
   newtail->cdr = cdr;
   batch->tail = newtail;
   curr = batch->size++;
   ast_mutex_unlock(&cdr_batch_lock);

   /* if we have enough stuff to post, then do it */
   if (curr >= (batchsize - 1))
      submit_unscheduled_batch();
}
void ast_cdr_discard ( struct ast_cdr cdr)

Discard and free a CDR record.

Parameters:
cdrast_cdr structure to free Returns nothing -- same as free, but no checks or complaints

Definition at line 449 of file cdr.c.

References ast_cdr_free_vars(), ast_free, and ast_cdr::next.

Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_merge(), and ast_channel_free().

{
   while (cdr) {
      struct ast_cdr *next = cdr->next;

      ast_cdr_free_vars(cdr, 0);
      ast_free(cdr);
      cdr = next;
   }
}
char* ast_cdr_disp2str ( int  disposition)

Disposition to a string.

Parameters:
dispositioninput binary form Converts the binary form of a disposition to string form.
Returns:
a pointer to the string form

Definition at line 910 of file cdr.c.

References AST_CDR_ANSWERED, AST_CDR_BUSY, AST_CDR_FAILED, AST_CDR_NOANSWER, and AST_CDR_NULL.

Referenced by ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), execute_cb(), manager_log(), and tds_log().

{
   switch (disposition) {
   case AST_CDR_NULL:
      return "NO ANSWER"; /* by default, for backward compatibility */
   case AST_CDR_NOANSWER:
      return "NO ANSWER";
   case AST_CDR_FAILED:
      return "FAILED";     
   case AST_CDR_BUSY:
      return "BUSY";    
   case AST_CDR_ANSWERED:
      return "ANSWERED";
   }
   return "UNKNOWN";
}
int ast_cdr_disposition ( struct ast_cdr cdr,
int  cause 
)

Save the result of the call based on the AST_CAUSE_*.

Parameters:
cdrthe cdr you wish to associate with the call
causethe AST_CAUSE_* Returns nothing

Definition at line 751 of file cdr.c.

References AST_CAUSE_BUSY, AST_CAUSE_NO_ANSWER, AST_CAUSE_NORMAL, ast_cdr_busy(), ast_cdr_noanswer(), and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), clear_caller(), and findmeexec().

{
   int res = 0;

   for (; cdr; cdr = cdr->next) {
      switch (cause) {  /* handle all the non failure, busy cases, return 0 not to set disposition,
                     return -1 to set disposition to FAILED */
      case AST_CAUSE_BUSY:
         ast_cdr_busy(cdr);
         break;
      case AST_CAUSE_NO_ANSWER:
         ast_cdr_noanswer(cdr);
         break;
      case AST_CAUSE_NORMAL:
         break;
      default:
         res = -1;
      }
   }
   return res;
}
struct ast_cdr* ast_cdr_dup ( struct ast_cdr cdr) [read]

Duplicate a record.

Return values:
amalloc'd ast_cdr structure,
NULLon error (malloc failure)

Duplicate a CDR record

Returns:
Pointer to new CDR record

Definition at line 176 of file cdr.c.

References ast_cdr_alloc(), ast_cdr_copy_vars(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_async_goto(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_merge(), and ast_cdr_reset().

{
   struct ast_cdr *newcdr;
   
   if (!cdr) /* don't die if we get a null cdr pointer */
      return NULL;
   newcdr = ast_cdr_alloc();
   if (!newcdr)
      return NULL;

   memcpy(newcdr, cdr, sizeof(*newcdr));
   /* The varshead is unusable, volatile even, after the memcpy so we take care of that here */
   memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
   ast_cdr_copy_vars(newcdr, cdr);
   newcdr->next = NULL;

   return newcdr;
}
void ast_cdr_end ( struct ast_cdr cdr)

End a call.

Parameters:
cdrthe cdr you have associated the call with Registers the end of call time in the cdr structure. Returns nothing

Definition at line 884 of file cdr.c.

References ast_cdr::answer, AST_CDR_ANSWERED, AST_CDR_FAILED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_log(), AST_OPT_FLAG_INITIATED_SECONDS, ast_options, ast_test_flag, ast_tvnow(), ast_tvzero(), ast_cdr::billsec, ast_cdr::channel, check_post(), ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, LOG_WARNING, ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_fork(), ast_cdr_reset(), ast_hangup(), ast_pbx_outgoing_cdr_failed(), clear_caller(), and findmeexec().

{
   for ( ; cdr ; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      if (ast_tvzero(cdr->end))
         cdr->end = ast_tvnow();
      if (ast_tvzero(cdr->start)) {
         ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", S_OR(cdr->channel, "<unknown>"));
         cdr->disposition = AST_CDR_FAILED;
      } else
         cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec;
      if (ast_tvzero(cdr->answer)) {
         if (cdr->disposition == AST_CDR_ANSWERED) {
            ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
            cdr->disposition = AST_CDR_FAILED;
         }
      } else {
         cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
         if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
            cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
      }
   }
}
int ast_cdr_engine_init ( void  )

Load the configuration file cdr.conf and possibly start the CDR scheduling thread.

Definition at line 1532 of file cdr.c.

References ast_cli_register(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), cdr_batch_lock, cli_status, do_reload(), init_batch(), LOG_ERROR, and sched_context_create().

Referenced by main().

{
   int res;

   sched = sched_context_create();
   if (!sched) {
      ast_log(LOG_ERROR, "Unable to create schedule context.\n");
      return -1;
   }

   ast_cli_register(&cli_status);

   res = do_reload(0);
   if (res) {
      ast_mutex_lock(&cdr_batch_lock);
      res = init_batch();
      ast_mutex_unlock(&cdr_batch_lock);
   }

   return res;
}
int ast_cdr_engine_reload ( void  )

Reload the configuration file cdr.conf and start/stop CDR scheduling thread.

Definition at line 1561 of file cdr.c.

References do_reload().

{
   return do_reload(1);
}
void ast_cdr_engine_term ( void  )

Submit any remaining CDRs and prepare for shutdown

Definition at line 1556 of file cdr.c.

References ast_cdr_submit_batch(), and batchsafeshutdown.

Referenced by do_reload(), and quit_handler().

void ast_cdr_failed ( struct ast_cdr cdr)

Fail a call.

Parameters:
cdrthe cdr you wish to associate with the call Marks the channel disposition as "FAILED" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application. Returns nothing

Definition at line 722 of file cdr.c.

References AST_CDR_FAILED, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by __ast_request_and_dial(), ast_pbx_outgoing_app(), ast_pbx_outgoing_cdr_failed(), ast_pbx_outgoing_exten(), clear_caller(), findmeexec(), handle_cause(), try_calling(), and wait_for_answer().

{
   for (; cdr; cdr = cdr->next) {
      check_post(cdr);
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         if (cdr->disposition < AST_CDR_FAILED)
            cdr->disposition = AST_CDR_FAILED;
      }
   }
}
char* ast_cdr_flags2str ( int  flag)

Flags to a string

Parameters:
flagsbinary flag Converts binary flags to string flags Returns string with flag name

Converts AMA flag to printable string

Definition at line 928 of file cdr.c.

References AST_CDR_BILLING, AST_CDR_DOCUMENTATION, and AST_CDR_OMIT.

Referenced by _sip_show_peer(), _skinny_show_line(), ast_cdr_getvar(), build_csv_record(), build_radius_record(), csv_log(), manager_log(), sip_show_user(), and tds_log().

{
   switch (flag) {
   case AST_CDR_OMIT:
      return "OMIT";
   case AST_CDR_BILLING:
      return "BILLING";
   case AST_CDR_DOCUMENTATION:
      return "DOCUMENTATION";
   }
   return "Unknown";
}
void ast_cdr_free ( struct ast_cdr cdr)

Free a CDR record.

Parameters:
cdrast_cdr structure to free Returns nothing

Definition at line 436 of file cdr.c.

References ast_cdr_free_vars(), ast_free, and ast_cdr::next.

Referenced by ast_cdr_detach(), and do_batch_backend_process().

{

   while (cdr) {
      struct ast_cdr *next = cdr->next;

      ast_cdr_free_vars(cdr, 0);
      ast_free(cdr);
      cdr = next;
   }
}
void ast_cdr_free_vars ( struct ast_cdr cdr,
int  recur 
)

Definition at line 415 of file cdr.c.

References AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_discard(), ast_cdr_fork(), ast_cdr_free(), and ast_cdr_reset().

{

   /* clear variables */
   for (; cdr; cdr = recur ? cdr->next : NULL) {
      struct ast_var_t *vardata;
      struct varshead *headp = &cdr->varshead;
      while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
         ast_var_delete(vardata);
   }
}
void ast_cdr_getvar ( struct ast_cdr cdr,
const char *  name,
char **  ret,
char *  workspace,
int  workspacelen,
int  recur,
int  raw 
)

CDR channel variable retrieval

Definition at line 227 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr_getvar_internal(), ast_copy_string(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_cdr::billsec, cdr_get_tv(), ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.

Referenced by ast_cdr_serialize_variables(), cdr_handler(), cdr_read(), odbc_log(), and pgsql_log().

{
   const char *fmt = "%Y-%m-%d %T";
   const char *varbuf;

   if (!cdr)  /* don't die if the cdr is null */
      return;

   *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_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"))
      cdr_get_tv(cdr->start, raw ? NULL : fmt, workspace, workspacelen);
   else if (!strcasecmp(name, "answer"))
      cdr_get_tv(cdr->answer, raw ? NULL : fmt, workspace, workspacelen);
   else if (!strcasecmp(name, "end"))
      cdr_get_tv(cdr->end, raw ? NULL : fmt, workspace, workspacelen);
   else if (!strcasecmp(name, "duration"))
      snprintf(workspace, workspacelen, "%ld", cdr->duration ? cdr->duration : (long)ast_tvdiff_ms(ast_tvnow(), cdr->start) / 1000);
   else if (!strcasecmp(name, "billsec"))
      snprintf(workspace, workspacelen, "%ld", cdr->billsec || cdr->answer.tv_sec == 0 ? cdr->billsec : (long)ast_tvdiff_ms(ast_tvnow(), cdr->answer) / 1000);
   else if (!strcasecmp(name, "disposition")) {
      if (raw) {
         snprintf(workspace, workspacelen, "%ld", cdr->disposition);
      } else {
         ast_copy_string(workspace, ast_cdr_disp2str(cdr->disposition), workspacelen);
      }
   } else if (!strcasecmp(name, "amaflags")) {
      if (raw) {
         snprintf(workspace, workspacelen, "%ld", cdr->amaflags);
      } else {
         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);
   else
      workspace[0] = '\0';

   if (!ast_strlen_zero(workspace))
      *ret = workspace;
}
int ast_cdr_init ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdrCall Detail Record to use for channel
chanChannel to bind CDR with Initializes a CDR and associates it with a particular channel
Returns:
0 by default

Definition at line 849 of file cdr.c.

References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::amaflags, AST_CDR_ANSWERED, AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_copy_string(), ast_default_amaflags, AST_STATE_UP, ast_test_flag, chan, ast_cdr::channel, ast_channel::context, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::name, ast_cdr::next, S_OR, set_one_cid(), ast_channel::uniqueid, and ast_cdr::uniqueid.

Referenced by __ast_channel_alloc_ap(), __ast_request_and_dial(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

{
   char *chan;

   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         chan = S_OR(cdr->channel, "<unknown>");
         ast_copy_string(cdr->channel, c->name, sizeof(cdr->channel));
         set_one_cid(cdr, c);

         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 */
         ast_copy_string(cdr->dst, S_OR(c->macroexten,c->exten), sizeof(cdr->dst));
         ast_copy_string(cdr->dcontext, S_OR(c->macrocontext,c->context), sizeof(cdr->dcontext));
         /* Unique call identifier */
         ast_copy_string(cdr->uniqueid, c->uniqueid, sizeof(cdr->uniqueid));
      }
   }
   return 0;
}
int ast_cdr_isset_unanswered ( void  )

Definition at line 168 of file cdr.c.

References unanswered.

Referenced by ring_entry(), and try_calling().

{
   return unanswered;
}
void ast_cdr_merge ( struct ast_cdr to,
struct ast_cdr from 
)

Move the non-null data from the "from" cdr to the "to" cdr.

Parameters:
tothe cdr to get the goodies
fromthe cdr to give the goodies

Definition at line 504 of file cdr.c.

References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, ast_cdr_append(), ast_cdr_discard(), AST_CDR_DOCUMENTATION, ast_cdr_dup(), AST_CDR_FLAG_CHILD, AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POSTED, AST_CDR_NOANSWER, ast_copy_string(), ast_log(), ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tv(), ast_tvcmp(), ast_tvzero(), ast_cdr::billsec, cdr_merge_vars(), ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, ast_cdr::next, ast_cdr::src, ast_cdr::start, and ast_cdr::userfield.

{
   struct ast_cdr *zcdr;
   struct ast_cdr *lto = NULL;
   struct ast_cdr *lfrom = NULL;
   int discard_from = 0;
   
   if (!to || !from)
      return;

   /* don't merge into locked CDR's -- it's bad business */
   if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
      zcdr = to; /* safety valve? */
      while (to->next) {
         lto = to;
         to = to->next;
      }
      
      if (ast_test_flag(to, AST_CDR_FLAG_LOCKED)) {
         ast_log(LOG_WARNING, "Merging into locked CDR... no choice.");
         to = zcdr; /* safety-- if all there are is locked CDR's, then.... ?? */
         lto = NULL;
      }
   }

   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED)) {
      struct ast_cdr *llfrom = NULL;
      discard_from = 1;
      if (lto) {
         /* insert the from stuff after lto */
         lto->next = from;
         lfrom = from;
         while (lfrom && lfrom->next) {
            if (!lfrom->next->next)
               llfrom = lfrom;
            lfrom = lfrom->next; 
         }
         /* rip off the last entry and put a copy of the to at the end */
         llfrom->next = to;
         from = lfrom;
      } else {
         /* save copy of the current *to cdr */
         struct ast_cdr tcdr;
         memcpy(&tcdr, to, sizeof(tcdr));
         /* copy in the locked from cdr */
         memcpy(to, from, sizeof(*to));
         lfrom = from;
         while (lfrom && lfrom->next) {
            if (!lfrom->next->next)
               llfrom = lfrom;
            lfrom = lfrom->next; 
         }
         from->next = NULL;
         /* rip off the last entry and put a copy of the to at the end */
         if (llfrom == from)
            to = to->next = ast_cdr_dup(&tcdr);
         else
            to = llfrom->next = ast_cdr_dup(&tcdr);
         from = lfrom;
      }
   }
   
   if (!ast_tvzero(from->start)) {
      if (!ast_tvzero(to->start)) {
         if (ast_tvcmp(to->start, from->start) > 0 ) {
            to->start = from->start; /* use the earliest time */
            from->start = ast_tv(0,0); /* we actively "steal" these values */
         }
         /* else nothing to do */
      } else {
         to->start = from->start;
         from->start = ast_tv(0,0); /* we actively "steal" these values */
      }
   }
   if (!ast_tvzero(from->answer)) {
      if (!ast_tvzero(to->answer)) {
         if (ast_tvcmp(to->answer, from->answer) > 0 ) {
            to->answer = from->answer; /* use the earliest time */
            from->answer = ast_tv(0,0); /* we actively "steal" these values */
         }
         /* we got the earliest answer time, so we'll settle for that? */
      } else {
         to->answer = from->answer;
         from->answer = ast_tv(0,0); /* we actively "steal" these values */
      }
   }
   if (!ast_tvzero(from->end)) {
      if (!ast_tvzero(to->end)) {
         if (ast_tvcmp(to->end, from->end) < 0 ) {
            to->end = from->end; /* use the latest time */
            from->end = ast_tv(0,0); /* we actively "steal" these values */
            to->duration = to->end.tv_sec - to->start.tv_sec;  /* don't forget to update the duration, billsec, when we set end */
            to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
         }
         /* else, nothing to do */
      } else {
         to->end = from->end;
         from->end = ast_tv(0,0); /* we actively "steal" these values */
         to->duration = to->end.tv_sec - to->start.tv_sec;
         to->billsec = ast_tvzero(to->answer) ? 0 : to->end.tv_sec - to->answer.tv_sec;
      }
   }
   if (to->disposition < from->disposition) {
      to->disposition = from->disposition;
      from->disposition = AST_CDR_NOANSWER;
   }
   if (ast_strlen_zero(to->lastapp) && !ast_strlen_zero(from->lastapp)) {
      ast_copy_string(to->lastapp, from->lastapp, sizeof(to->lastapp));
      from->lastapp[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->lastdata) && !ast_strlen_zero(from->lastdata)) {
      ast_copy_string(to->lastdata, from->lastdata, sizeof(to->lastdata));
      from->lastdata[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->dcontext) && !ast_strlen_zero(from->dcontext)) {
      ast_copy_string(to->dcontext, from->dcontext, sizeof(to->dcontext));
      from->dcontext[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->dstchannel) && !ast_strlen_zero(from->dstchannel)) {
      ast_copy_string(to->dstchannel, from->dstchannel, sizeof(to->dstchannel));
      from->dstchannel[0] = 0; /* theft */
   }
   if (!ast_strlen_zero(from->channel) && (ast_strlen_zero(to->channel) || !strncasecmp(from->channel, "Agent/", 6))) {
      ast_copy_string(to->channel, from->channel, sizeof(to->channel));
      from->channel[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->src) && !ast_strlen_zero(from->src)) {
      ast_copy_string(to->src, from->src, sizeof(to->src));
      from->src[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->clid) && !ast_strlen_zero(from->clid)) {
      ast_copy_string(to->clid, from->clid, sizeof(to->clid));
      from->clid[0] = 0; /* theft */
   }
   if (ast_strlen_zero(to->dst) && !ast_strlen_zero(from->dst)) {
      ast_copy_string(to->dst, from->dst, sizeof(to->dst));
      from->dst[0] = 0; /* theft */
   }
   if (!to->amaflags)
      to->amaflags = AST_CDR_DOCUMENTATION;
   if (!from->amaflags)
      from->amaflags = AST_CDR_DOCUMENTATION; /* make sure both amaflags are set to something (DOC is default) */
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (to->amaflags == AST_CDR_DOCUMENTATION && from->amaflags != AST_CDR_DOCUMENTATION)) {
      to->amaflags = from->amaflags;
   }
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->accountcode) && !ast_strlen_zero(from->accountcode))) {
      ast_copy_string(to->accountcode, from->accountcode, sizeof(to->accountcode));
   }
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED) || (ast_strlen_zero(to->userfield) && !ast_strlen_zero(from->userfield))) {
      ast_copy_string(to->userfield, from->userfield, sizeof(to->userfield));
   }
   /* flags, varsead, ? */
   cdr_merge_vars(from, to);

   if (ast_test_flag(from, AST_CDR_FLAG_KEEP_VARS))
      ast_set_flag(to, AST_CDR_FLAG_KEEP_VARS);
   if (ast_test_flag(from, AST_CDR_FLAG_POSTED))
      ast_set_flag(to, AST_CDR_FLAG_POSTED);
   if (ast_test_flag(from, AST_CDR_FLAG_LOCKED))
      ast_set_flag(to, AST_CDR_FLAG_LOCKED);
   if (ast_test_flag(from, AST_CDR_FLAG_CHILD))
      ast_set_flag(to, AST_CDR_FLAG_CHILD);
   if (ast_test_flag(from, AST_CDR_FLAG_POST_DISABLED))
      ast_set_flag(to, AST_CDR_FLAG_POST_DISABLED);

   /* last, but not least, we need to merge any forked CDRs to the 'to' cdr */
   while (from->next) {
      /* just rip 'em off the 'from' and insert them on the 'to' */
      zcdr = from->next;
      from->next = zcdr->next;
      zcdr->next = NULL;
      /* zcdr is now ripped from the current list; */
      ast_cdr_append(to, zcdr);
   }
   if (discard_from)
      ast_cdr_discard(from);
}
void ast_cdr_noanswer ( struct ast_cdr cdr)

A call wasn't answered.

Parameters:
cdrthe cdr you wish to associate with the call Marks the channel disposition as "NO ANSWER" Will skip CDR's in chain with ANS_LOCK bit set. (see forkCDR() application.

Definition at line 734 of file cdr.c.

References AST_CDR_FLAG_LOCKED, AST_CDR_NOANSWER, ast_strlen_zero(), ast_test_flag, chan, ast_cdr::channel, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by ast_cdr_disposition(), handle_cause(), and wait_for_answer().

{
   char *chan; 

   while (cdr) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
         check_post(cdr);
         cdr->disposition = AST_CDR_NOANSWER;
      }
      cdr = cdr->next;
   }
}
int ast_cdr_register ( const char *  name,
const char *  desc,
ast_cdrbe  be 
)

Register a CDR handling engine.

Parameters:
namename associated with the particular CDR handler
descdescription of the CDR handler
befunction pointer to a CDR handler Used to register a Call Detail Record handler.
Return values:
0on success.
-1on error

Register a CDR driver. Each registered CDR driver generates a CDR

Returns:
0 on success, -1 on failure

Definition at line 116 of file cdr.c.

References ast_calloc, ast_copy_string(), ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_cdr_beitem::be, ast_cdr_beitem::desc, LOG_WARNING, and ast_cdr_beitem::name.

Referenced by config_module(), load_config(), load_module(), odbc_load_module(), and unload_module().

{
   struct ast_cdr_beitem *i = NULL;

   if (!name)
      return -1;

   if (!be) {
      ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
      return -1;
   }

   AST_RWLIST_WRLOCK(&be_list);
   AST_RWLIST_TRAVERSE(&be_list, i, list) {
      if (!strcasecmp(name, i->name)) {
         ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
         AST_RWLIST_UNLOCK(&be_list);
         return -1;
      }
   }

   if (!(i = ast_calloc(1, sizeof(*i))))  
      return -1;

   i->be = be;
   ast_copy_string(i->name, name, sizeof(i->name));
   ast_copy_string(i->desc, desc, sizeof(i->desc));

   AST_RWLIST_INSERT_HEAD(&be_list, i, list);
   AST_RWLIST_UNLOCK(&be_list);

   return 0;
}
void ast_cdr_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record, optionally posting it first.

Parameters:
cdrwhich cdr to act upon
flags|AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's

Definition at line 1067 of file cdr.c.

References ast_cdr::answer, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_KEEP_VARS, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, AST_CDR_FLAG_POST_ENABLE, AST_CDR_FLAG_POSTED, ast_cdr_free_vars(), AST_CDR_NOANSWER, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, ast_cdr::next, and ast_cdr::start.

Referenced by ast_cdr_fork(), dial_exec_full(), disa_exec(), and pbx_builtin_resetcdr().

{
   struct ast_cdr *duplicate;
   struct ast_flags flags = { 0 };

   if (_flags)
      ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);

   for ( ; cdr ; cdr = cdr->next) {
      /* Detach if post is requested */
      if (ast_test_flag(&flags, AST_CDR_FLAG_LOCKED) || !ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         if (ast_test_flag(&flags, AST_CDR_FLAG_POSTED)) {
            ast_cdr_end(cdr);
            if ((duplicate = ast_cdr_dup(cdr))) {
               ast_cdr_detach(duplicate);
            }
            ast_set_flag(cdr, AST_CDR_FLAG_POSTED);
         }

         /* enable CDR only */
         if (ast_test_flag(&flags, AST_CDR_FLAG_POST_ENABLE)) {
            ast_clear_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
            continue;
         }

         /* clear variables */
         if (!ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
            ast_cdr_free_vars(cdr, 0);
         }

         /* Reset to initial state */
         ast_clear_flag(cdr, AST_FLAGS_ALL); 
         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;
      }
   }
}
int ast_cdr_serialize_variables ( struct ast_cdr cdr,
struct ast_str **  buf,
char  delim,
char  sep,
int  recur 
)

Definition at line 370 of file cdr.c.

References ast_cdr_getvar(), AST_LIST_TRAVERSE, ast_log(), ast_str_append(), ast_str_reset(), ast_var_name(), ast_var_value(), cdr_readonly_vars, ast_var_t::entries, LOG_ERROR, ast_cdr::next, S_OR, total, var, and ast_cdr::varshead.

Referenced by handle_showchan().

{
   struct ast_var_t *variables;
   const char *var;
   char *tmp;
   char workspace[256];
   int total = 0, x = 0, i;

   ast_str_reset(*buf);

   for (; cdr; cdr = recur ? cdr->next : NULL) {
      if (++x > 1)
         ast_str_append(buf, 0, "\n");

      AST_LIST_TRAVERSE(&cdr->varshead, variables, entries) {
         if (!(var = ast_var_name(variables))) {
            continue;
         }

         if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, var, delim, S_OR(ast_var_value(variables), ""), sep) < 0) {
            ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
            break;
         }

         total++;
      }

      for (i = 0; cdr_readonly_vars[i]; i++) {
         workspace[0] = 0; /* null out the workspace, because the cdr_get_tv() won't write anything if time is NULL, so you get old vals */
         ast_cdr_getvar(cdr, cdr_readonly_vars[i], &tmp, workspace, sizeof(workspace), 0, 0);
         if (!tmp)
            continue;
         
         if (ast_str_append(buf, 0, "level %d: %s%c%s%c", x, cdr_readonly_vars[i], delim, tmp, sep) < 0) {
            ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
            break;
         } else
            total++;
      }
   }

   return total;
}
int ast_cdr_setaccount ( struct ast_channel chan,
const char *  account 
)

Set account code, will generate AMI event.

Definition at line 941 of file cdr.c.

References ast_cdr::accountcode, accountcode, ast_channel::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, buf, ast_channel::cdr, EVENT_FLAG_CALL, manager_event, ast_channel::name, ast_cdr::next, and ast_channel::uniqueid.

Referenced by __ast_request_and_dial(), ast_bridge_call(), ast_call_forward(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), auth_exec(), cdr_write(), and rpt_call().

{
   struct ast_cdr *cdr = chan->cdr;
   char buf[BUFSIZ/2] = "";
   if (!ast_strlen_zero(chan->accountcode))
      ast_copy_string(buf, chan->accountcode, sizeof(buf));

   ast_string_field_set(chan, accountcode, account);
   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         ast_copy_string(cdr->accountcode, chan->accountcode, sizeof(cdr->accountcode));
      }
   }

   /* Signal change of account code to manager */
   manager_event(EVENT_FLAG_CALL, "NewAccountCode", "Channel: %s\r\nUniqueid: %s\r\nAccountCode: %s\r\nOldAccountCode: %s\r\n", chan->name, chan->uniqueid, chan->accountcode, buf);
   return 0;
}
int ast_cdr_setamaflags ( struct ast_channel chan,
const char *  amaflags 
)

Set AMA flags for channel.

Definition at line 960 of file cdr.c.

References ast_cdr::amaflags, ast_cdr_amaflags2int(), AST_CDR_FLAG_LOCKED, ast_test_flag, ast_channel::cdr, and ast_cdr::next.

Referenced by cdr_write(), and pbx_builtin_setamaflags().

{
   struct ast_cdr *cdr;
   int newflag = ast_cdr_amaflags2int(flag);
   if (newflag) {
      for (cdr = chan->cdr; cdr; cdr = cdr->next) {
         if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
            cdr->amaflags = newflag;
         }
      }
   }

   return 0;
}
void ast_cdr_setanswer ( struct ast_cdr cdr,
struct timeval  t 
)

Set the answer time for a call.

Parameters:
cdrthe cdr you wish to associate with the call
tthe answer time Starts all CDR stuff necessary for doing CDR when answering a call NULL argument is just fine.

Definition at line 795 of file cdr.c.

References ast_cdr::answer, AST_CDR_FLAG_ANSLOCKED, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), and ast_cdr::next.

Referenced by ast_bridge_call().

{

   for (; cdr; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_ANSLOCKED))
         continue;
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      cdr->answer = t;
   }
}
void ast_cdr_setapp ( struct ast_cdr cdr,
const char *  app,
const char *  data 
)

Set the last executed application.

Parameters:
cdrwhich cdr to act upon
appthe name of the app you wish to change it to
datathe data you want in the data field of app you set it to Changes the value of the last executed app Returns nothing

Definition at line 783 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, check_post(), ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::next, and S_OR.

Referenced by __ast_request_and_dial(), agi_handle_command(), clear_caller(), findmeexec(), and pbx_exec().

{

   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         ast_copy_string(cdr->lastapp, S_OR(app, ""), sizeof(cdr->lastapp));
         ast_copy_string(cdr->lastdata, S_OR(data, ""), sizeof(cdr->lastdata));
      }
   }
}
int ast_cdr_setcid ( struct ast_cdr cdr,
struct ast_channel chan 
)

Initialize based on a channel.

Parameters:
cdrCall Detail Record to use for channel
chanChannel to bind CDR with Initializes a CDR and associates it with a particular channel
Returns:
0 by default

Definition at line 840 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_cdr::next, and set_one_cid().

Referenced by ast_bridge_call(), ast_set_callerid(), and callerid_write().

{
   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         set_one_cid(cdr, c);
   }
   return 0;
}
void ast_cdr_setdestchan ( struct ast_cdr cdr,
const char *  chan 
)

Set the destination channel, if there was one.

Parameters:
cdrWhich cdr it's applied to
chanChannel to which dest will be Sets the destination channel the CDR is applied to Returns nothing

Definition at line 773 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, check_post(), ast_cdr::dstchannel, and ast_cdr::next.

Referenced by dial_exec_full(), park_exec_full(), ring_entry(), and try_calling().

{
   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         check_post(cdr);
         ast_copy_string(cdr->dstchannel, chann, sizeof(cdr->dstchannel));
      }
   }
}
void ast_cdr_setdisposition ( struct ast_cdr cdr,
long int  disposition 
)

Set the disposition for a call.

Parameters:
cdrthe cdr you wish to associate with the call
dispositionthe new disposition Set the disposition on a call. NULL argument is just fine.

Definition at line 808 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, check_post(), ast_cdr::disposition, and ast_cdr::next.

Referenced by ast_bridge_call().

{

   for (; cdr; cdr = cdr->next) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      check_post(cdr);
      cdr->disposition = disposition;
   }
}
int ast_cdr_setuserfield ( struct ast_channel chan,
const char *  userfield 
)

Set CDR user field for channel (stored in CDR)

Definition at line 975 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_cdr::next, and ast_cdr::userfield.

Referenced by __agent_start_monitoring(), cdr_write(), handle_request_info(), and start_monitor_exec().

{
   struct ast_cdr *cdr = chan->cdr;

   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) 
         ast_copy_string(cdr->userfield, userfield, sizeof(cdr->userfield));
   }

   return 0;
}
int ast_cdr_setvar ( struct ast_cdr cdr,
const char *  name,
const char *  value,
int  recur 
)

Set a CDR channel variable

Note:
You can't set the CDR variables that belong to the actual CDR record, like "billsec".

Definition at line 300 of file cdr.c.

References AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_test_flag, ast_var_assign(), ast_var_delete(), ast_var_name(), cdr_readonly_vars, LOG_ERROR, ast_cdr::next, and ast_cdr::varshead.

Referenced by ast_cdr_fork(), cdr_write(), and set_one_cid().

{
   struct ast_var_t *newvariable;
   struct varshead *headp;
   int x;
   
   if (!cdr)  /* don't die if the cdr is null */
      return -1;
   
   for (x = 0; cdr_readonly_vars[x]; x++) {
      if (!strcasecmp(name, cdr_readonly_vars[x])) {
         ast_log(LOG_ERROR, "Attempt to set the '%s' read-only variable!.\n", name);
         return -1;
      }
   }

   if (!cdr) {
      ast_log(LOG_ERROR, "Attempt to set a variable on a nonexistent CDR record.\n");
      return -1;
   }

   for (; cdr; cdr = recur ? cdr->next : NULL) {
      if (ast_test_flag(cdr, AST_CDR_FLAG_DONT_TOUCH) && ast_test_flag(cdr, AST_CDR_FLAG_LOCKED))
         continue;
      headp = &cdr->varshead;
      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_CURRENT(entries);
            ast_var_delete(newvariable);
            break;
         }
      }
      AST_LIST_TRAVERSE_SAFE_END;
      
      if (value) {
         newvariable = ast_var_assign(name, value);
         AST_LIST_INSERT_HEAD(headp, newvariable, entries);
      }
   }

   return 0;
}
void ast_cdr_specialized_reset ( struct ast_cdr cdr,
struct ast_flags flags 
)

Reset the detail record times, flags

Parameters:
cdrwhich cdr to act upon
flags|AST_CDR_FLAG_POSTED whether or not to post the cdr first before resetting it |AST_CDR_FLAG_LOCKED whether or not to reset locked CDR's

Definition at line 1110 of file cdr.c.

References ast_cdr::answer, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_start(), ast_clear_flag, ast_copy_flags, AST_FLAGS_ALL, ast_set_flag, ast_test_flag, ast_cdr::billsec, ast_cdr::disposition, ast_cdr::duration, ast_cdr::end, and ast_cdr::start.

Referenced by ast_bridge_call().

{
   struct ast_flags flags = { 0 };

   if (_flags)
      ast_copy_flags(&flags, _flags, AST_FLAGS_ALL);
   
   /* Reset to initial state */
   if (ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED)) { /* But do NOT lose the NoCDR() setting */
      ast_clear_flag(cdr, AST_FLAGS_ALL); 
      ast_set_flag(cdr, AST_CDR_FLAG_POST_DISABLED);
   } else {
      ast_clear_flag(cdr, AST_FLAGS_ALL); 
   }
   
   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_NULL;
}
void ast_cdr_start ( struct ast_cdr cdr)

Start a call.

Parameters:
cdrthe cdr you wish to associate with the call Starts all CDR stuff necessary for monitoring a call Returns nothing

Definition at line 682 of file cdr.c.

References AST_CDR_FLAG_LOCKED, ast_test_flag, ast_tvnow(), chan, ast_cdr::channel, check_post(), ast_cdr::next, S_OR, and ast_cdr::start.

Referenced by __ast_channel_alloc_ap(), __ast_request_and_dial(), ast_bridge_call(), ast_cdr_reset(), ast_cdr_specialized_reset(), ast_pbx_outgoing_cdr_failed(), builtin_blindtransfer(), clear_caller(), and findmeexec().

{
   char *chan; 

   for (; cdr; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         chan = S_OR(cdr->channel, "<unknown>");
         check_post(cdr);
         cdr->start = ast_tvnow();
      }
   }
}
void ast_cdr_submit_batch ( int  shutdown)

Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines.

Parameters:
shutdownWhether or not we are shutting down Blocks the asterisk shutdown procedures until the CDR data is submitted. Returns nothing

Definition at line 1188 of file cdr.c.

References ast_debug, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, AST_PTHREADT_NULL, batch, batchscheduleronly, cdr_batch_lock, do_batch_backend_process(), ast_cdr_batch::head, LOG_WARNING, and reset_batch().

Referenced by ast_cdr_engine_term(), and submit_scheduled_batch().

{
   struct ast_cdr_batch_item *oldbatchitems = NULL;
   pthread_t batch_post_thread = AST_PTHREADT_NULL;

   /* if there's no batch, or no CDRs in the batch, then there's nothing to do */
   if (!batch || !batch->head)
      return;

   /* move the old CDRs aside, and prepare a new CDR batch */
   ast_mutex_lock(&cdr_batch_lock);
   oldbatchitems = batch->head;
   reset_batch();
   ast_mutex_unlock(&cdr_batch_lock);

   /* if configured, spawn a new thread to post these CDRs,
      also try to save as much as possible if we are shutting down safely */
   if (batchscheduleronly || do_shutdown) {
      ast_debug(1, "CDR single-threaded batch processing begins now\n");
      do_batch_backend_process(oldbatchitems);
   } else {
      if (ast_pthread_create_detached_background(&batch_post_thread, NULL, do_batch_backend_process, oldbatchitems)) {
         ast_log(LOG_WARNING, "CDR processing thread could not detach, now trying in this thread\n");
         do_batch_backend_process(oldbatchitems);
      } else {
         ast_debug(1, "CDR multi-threaded batch processing begins now\n");
      }
   }
}
void ast_cdr_unregister ( const char *  name)

Unregister a CDR handling engine.

Parameters:
namename of CDR handler to unregister Unregisters a CDR by it's name

unregister a CDR driver

Definition at line 151 of file cdr.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, and ast_cdr_beitem::name.

Referenced by load_config(), reload(), tds_unload_module(), and unload_module().

{
   struct ast_cdr_beitem *i = NULL;

   AST_RWLIST_WRLOCK(&be_list);
   AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
      if (!strcasecmp(name, i->name)) {
         AST_RWLIST_REMOVE_CURRENT(list);
         ast_verb(2, "Unregistered '%s' CDR backend\n", name);
         ast_free(i);
         break;
      }
   }
   AST_RWLIST_TRAVERSE_SAFE_END;
   AST_RWLIST_UNLOCK(&be_list);
}
int ast_cdr_update ( struct ast_channel chan)

Update CDR on a channel

Definition at line 1001 of file cdr.c.

References ast_channel::accountcode, ast_cdr::accountcode, AST_CDR_FLAG_LOCKED, ast_copy_string(), ast_test_flag, ast_channel::cdr, ast_channel::context, ast_cdr::dcontext, ast_cdr::dst, ast_channel::exten, ast_channel::macrocontext, ast_channel::macroexten, ast_cdr::next, S_OR, and set_one_cid().

Referenced by __ast_pbx_run(), __ast_request_and_dial(), ast_bridge_call(), cb_events(), clear_caller(), findmeexec(), and local_call().

{
   struct ast_cdr *cdr = c->cdr;

   for ( ; cdr ; cdr = cdr->next) {
      if (!ast_test_flag(cdr, AST_CDR_FLAG_LOCKED)) {
         set_one_cid(cdr, c);

         /* Copy account code et-al */ 
         ast_copy_string(cdr->accountcode, c->accountcode, sizeof(cdr->accountcode));
         
         /* Destination information */ /* XXX privilege macro* ? */
         ast_copy_string(cdr->dst, S_OR(c->macroexten, c->exten), sizeof(cdr->dst));
         ast_copy_string(cdr->dcontext, S_OR(c->macrocontext, c->context), sizeof(cdr->dcontext));
      }
   }

   return 0;
}
int check_cdr_enabled ( void  )

Return TRUE if CDR subsystem is enabled.

Definition at line 108 of file cdr.c.

References enabled.

Referenced by action_coresettings(), and handle_show_settings().

{
   return enabled;
}

Variable Documentation

char ast_default_accountcode[AST_MAX_ACCOUNT_CODE]

Definition at line 55 of file cdr.c.

Referenced by __ast_channel_alloc_ap().

Default AMA flag for billing records (CDR's)

Definition at line 54 of file cdr.c.

Referenced by __ast_channel_alloc_ap(), ast_bridge_call(), and ast_cdr_init().