Sat Apr 26 2014 22:02:01

Asterisk developer's documentation


cel.h File Reference

Call Event Logging API. More...

#include "asterisk/event.h"
Include dependency graph for cel.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_cel_event_record
 Helper struct for getting the fields out of a CEL event. More...

Defines

#define AST_CEL_EVENT_RECORD_VERSION   2
 struct ABI version

Enumerations

enum  ast_cel_ama_flag {
  AST_CEL_AMA_FLAG_NONE, AST_CEL_AMA_FLAG_OMIT, AST_CEL_AMA_FLAG_BILLING, AST_CEL_AMA_FLAG_DOCUMENTATION,
  AST_CEL_AMA_FLAG_TOTAL
}
 AMA Flags. More...
enum  ast_cel_event_type {
  AST_CEL_CHANNEL_START = 1, AST_CEL_CHANNEL_END = 2, AST_CEL_HANGUP = 3, AST_CEL_ANSWER = 4,
  AST_CEL_APP_START = 5, AST_CEL_APP_END = 6, AST_CEL_BRIDGE_START = 7, AST_CEL_BRIDGE_END = 8,
  AST_CEL_CONF_START = 9, AST_CEL_CONF_END = 10, AST_CEL_PARK_START = 11, AST_CEL_PARK_END = 12,
  AST_CEL_BLINDTRANSFER = 13, AST_CEL_ATTENDEDTRANSFER = 14, AST_CEL_TRANSFER = 15, AST_CEL_HOOKFLASH = 16,
  AST_CEL_3WAY_START = 17, AST_CEL_3WAY_END = 18, AST_CEL_CONF_ENTER = 19, AST_CEL_CONF_EXIT = 20,
  AST_CEL_USER_DEFINED = 21, AST_CEL_LINKEDID_END = 22, AST_CEL_BRIDGE_UPDATE = 23, AST_CEL_PICKUP = 24,
  AST_CEL_FORWARD = 25
}
 CEL event types. More...

Functions

struct ast_cel * ast_cel_alloc (void)
 Allocate a CEL record.
unsigned int ast_cel_check_enabled (void)
 Check to see if CEL is enabled.
void ast_cel_check_retire_linkedid (struct ast_channel *chan)
 Check and potentially retire a Linked ID.
void ast_cel_destroy (struct ast_cel *cel)
 Destroy a CEL record.
struct ast_channelast_cel_fabricate_channel_from_event (const struct ast_event *event)
 Create a fake channel from data in a CEL event.
int ast_cel_fill_record (const struct ast_event *event, struct ast_cel_event_record *r)
 Fill in an ast_cel_event_record from a CEL event.
const char * ast_cel_get_ama_flag_name (enum ast_cel_ama_flag flag)
 Convert AMA flag to printable string.
const char * ast_cel_get_type_name (enum ast_cel_event_type type)
 Get the name of a CEL event type.
int ast_cel_linkedid_ref (const char *linkedid)
 Inform CEL that a new linkedid is being used.
int ast_cel_report_event (struct ast_channel *chan, enum ast_cel_event_type event_type, const char *userdefevname, const char *extra, struct ast_channel *peer2)
 Report a channel event.
enum ast_cel_event_type ast_cel_str_to_event_type (const char *name)
 Get the event type from a string.

Detailed Description

Call Event Logging API.

Todo:
TODO: There some event types that have been defined here, but are not yet used anywhere in the code. It would be really awesome if someone went through and had Asterisk generate these events where it is appropriate to do so. The defined, but unused events are: CONF_ENTER, CONF_EXIT, CONF_START, CONF_END, 3WAY_START, 3WAY_END, TRANSFER, and HOOKFLASH.

Definition in file cel.h.


Define Documentation

struct ABI version

Note:
This must be incremented when the struct changes.

Definition at line 253 of file cel.h.

Referenced by ast_cel_fabricate_channel_from_event(), and ast_cel_fill_record().


Enumeration Type Documentation

AMA Flags.

Note:
This must much up with the AST_CDR_* defines for AMA flags.
Enumerator:
AST_CEL_AMA_FLAG_NONE 
AST_CEL_AMA_FLAG_OMIT 
AST_CEL_AMA_FLAG_BILLING 
AST_CEL_AMA_FLAG_DOCUMENTATION 
AST_CEL_AMA_FLAG_TOTAL 

Must be final entry.

Definition at line 43 of file cel.h.

CEL event types.

Enumerator:
AST_CEL_CHANNEL_START 

channel birth

AST_CEL_CHANNEL_END 

channel end

AST_CEL_HANGUP 

hangup terminates connection

AST_CEL_ANSWER 

A ringing phone is answered.

AST_CEL_APP_START 

an app starts

AST_CEL_APP_END 

an app ends

AST_CEL_BRIDGE_START 

a bridge is established

AST_CEL_BRIDGE_END 

a bridge is torn down

AST_CEL_CONF_START 

a conference is started

AST_CEL_CONF_END 

a conference is ended

AST_CEL_PARK_START 

a channel is parked

AST_CEL_PARK_END 

channel out of the park

AST_CEL_BLINDTRANSFER 

a transfer occurs

AST_CEL_ATTENDEDTRANSFER 

a transfer occurs

AST_CEL_TRANSFER 

a transfer occurs

AST_CEL_HOOKFLASH 

a 3-way conference, usually part of a transfer

AST_CEL_3WAY_START 

a 3-way conference, usually part of a transfer

AST_CEL_3WAY_END 

a 3-way conference, usually part of a transfer

AST_CEL_CONF_ENTER 

channel enters a conference

AST_CEL_CONF_EXIT 

channel exits a conference

AST_CEL_USER_DEFINED 

a user-defined event, the event name field should be set

AST_CEL_LINKEDID_END 

the last channel with the given linkedid is retired

AST_CEL_BRIDGE_UPDATE 

a masquerade happened to alter the participants on a bridge

AST_CEL_PICKUP 

a directed pickup was performed on this channel

AST_CEL_FORWARD 

this call was forwarded somewhere else

Definition at line 55 of file cel.h.

                        {
   /*! \brief channel birth */
   AST_CEL_CHANNEL_START = 1,
   /*! \brief channel end */
   AST_CEL_CHANNEL_END = 2,
   /*! \brief hangup terminates connection */
   AST_CEL_HANGUP = 3,
   /*! \brief A ringing phone is answered */
   AST_CEL_ANSWER = 4,
   /*! \brief an app starts */
   AST_CEL_APP_START = 5,
   /*! \brief an app ends */
   AST_CEL_APP_END = 6,
   /*! \brief a bridge is established */
   AST_CEL_BRIDGE_START = 7,
   /*! \brief a bridge is torn down */
   AST_CEL_BRIDGE_END = 8,
   /*! \brief a conference is started */
   AST_CEL_CONF_START = 9,
   /*! \brief a conference is ended */
   AST_CEL_CONF_END = 10,
   /*! \brief a channel is parked */
   AST_CEL_PARK_START = 11,
   /*! \brief channel out of the park */
   AST_CEL_PARK_END = 12,
   /*! \brief a transfer occurs */
   AST_CEL_BLINDTRANSFER = 13,
   /*! \brief a transfer occurs */
   AST_CEL_ATTENDEDTRANSFER = 14,
   /*! \brief a transfer occurs */
   AST_CEL_TRANSFER = 15,
   /*! \brief a 3-way conference, usually part of a transfer */
   AST_CEL_HOOKFLASH = 16,
   /*! \brief a 3-way conference, usually part of a transfer */
   AST_CEL_3WAY_START = 17,
   /*! \brief a 3-way conference, usually part of a transfer */
   AST_CEL_3WAY_END = 18,
   /*! \brief channel enters a conference */
   AST_CEL_CONF_ENTER = 19,
   /*! \brief channel exits a conference */
   AST_CEL_CONF_EXIT = 20,
   /*! \brief a user-defined event, the event name field should be set  */
   AST_CEL_USER_DEFINED = 21,
   /*! \brief the last channel with the given linkedid is retired  */
   AST_CEL_LINKEDID_END = 22,
   /*! \brief a masquerade happened to alter the participants on a bridge  */
   AST_CEL_BRIDGE_UPDATE = 23,
   /*! \brief a directed pickup was performed on this channel  */
   AST_CEL_PICKUP = 24,
   /*! \brief this call was forwarded somewhere else  */
   AST_CEL_FORWARD = 25,
};

Function Documentation

struct ast_cel* ast_cel_alloc ( void  ) [read]

Allocate a CEL record.

Since:
1.8
Note:
The CEL record must be destroyed with ast_cel_destroy().
Return values:
non-NULLan allocated ast_cel structure
NULLerror
unsigned int ast_cel_check_enabled ( void  )

Check to see if CEL is enabled.

Since:
1.8
Return values:
zeronot enabled
non-zeroenabled

Definition at line 164 of file cel.c.

References cel_enabled.

{
   return cel_enabled;
}
void ast_cel_check_retire_linkedid ( struct ast_channel chan)

Check and potentially retire a Linked ID.

Parameters:
chanchannel that is being destroyed or its linkedid is changing
Since:
1.8

If at least one CEL backend is looking for CEL_LINKEDID_END events, this function will check if the given channel is the last active channel with that linkedid, and if it is, emit a CEL_LINKEDID_END event.

Returns:
nothing

Definition at line 429 of file cel.c.

References ao2_find, ao2_ref, ao2_unlink, AST_CEL_LINKEDID_END, ast_cel_report_event(), ast_cel_track_event(), ast_channel_linkedid(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), cel_linkedid::count, LOG_ERROR, OBJ_KEY, and reload_lock.

Referenced by ast_channel_change_linkedid(), and ast_channel_destructor().

{
   const char *linkedid = ast_channel_linkedid(chan);
   struct cel_linkedid *lid;

   if (ast_strlen_zero(linkedid)) {
      return;
   }

   /* Get the lock in case any CEL events are still in flight when we shutdown. */
   ast_mutex_lock(&reload_lock);

   if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)
      || !linkedids) {
      /*
       * CEL is disabled or we are not tracking linkedids
       * or the CEL module is shutdown.
       */
      ast_mutex_unlock(&reload_lock);
      return;
   }

   lid = ao2_find(linkedids, (void *) linkedid, OBJ_KEY);
   if (!lid) {
      ast_mutex_unlock(&reload_lock);

      /*
       * The user may have done a reload to start tracking linkedids
       * when a call was already in progress.  This is an unusual kind
       * of change to make after starting Asterisk.
       */
      ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
      return;
   }

   if (!--lid->count) {
      /* No channels use this linkedid anymore. */
      ao2_unlink(linkedids, lid);
      ast_mutex_unlock(&reload_lock);

      ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
   } else {
      ast_mutex_unlock(&reload_lock);
   }
   ao2_ref(lid, -1);
}
void ast_cel_destroy ( struct ast_cel *  cel)

Destroy a CEL record.

Parameters:
celthe record to destroy
Since:
1.8
Returns:
nothing.
struct ast_channel* ast_cel_fabricate_channel_from_event ( const struct ast_event event) [read]

Create a fake channel from data in a CEL event.

Note:
This function creates a fake channel containing the serialized channel data in the given cel event. It should be released with ast_channel_unref() but could be released with ast_channel_release().
Parameters:
eventthe CEL event
Since:
1.8
Returns:
a channel with the data filled in, or NULL on error
Todo:
This function is very expensive, especially given that some CEL backends use it on every CEL event. This function really needs to go away at some point.

Definition at line 484 of file cel.c.

References ast_cel_event_record::account_code, ast_cel_event_record::amaflag, ast_party_caller::ani, ast_cel_event_record::application_data, ast_cel_event_record::application_name, AST_CEL_EVENT_RECORD_VERSION, ast_cel_fill_record(), AST_CEL_USER_DEFINED, ast_channel_amaflags_set(), ast_channel_appl_set(), ast_channel_caller(), ast_channel_context_set(), ast_channel_data_set(), ast_channel_datastore_add(), ast_channel_dialed(), ast_channel_exten_set(), ast_channel_linkedid_set(), ast_channel_name_set(), ast_channel_redirecting(), ast_channel_unref, ast_channel_varshead(), ast_datastore_alloc(), ast_datastore_free(), ast_dummy_channel_alloc(), AST_LIST_INSERT_HEAD, ast_localtime(), ast_malloc, ast_strdup, ast_strftime(), ast_strlen_zero(), ast_var_assign(), ast_cel_event_record::caller_id_ani, ast_cel_event_record::caller_id_dnid, ast_cel_event_record::caller_id_name, ast_cel_event_record::caller_id_num, ast_cel_event_record::caller_id_rdnis, ast_cel_event_record::channel_name, ast_cel_event_record::context, ast_datastore::data, ast_cel_event_record::event_name, ast_cel_event_record::event_time, ast_cel_event_record::event_type, ast_cel_event_record::extension, ast_cel_event_record::extra, ast_party_redirecting::from, ast_party_caller::id, ast_cel_event_record::linked_id, ast_party_id::name, ast_party_id::number, ast_party_dialed::number, ast_cel_event_record::peer, ast_cel_event_record::peer_account, ast_party_name::str, ast_party_number::str, ast_party_dialed::str, ast_cel_event_record::unique_id, ast_cel_event_record::user_defined_name, ast_cel_event_record::user_field, ast_party_name::valid, ast_party_number::valid, and ast_cel_event_record::version.

{
   struct varshead *headp;
   struct ast_var_t *newvariable;
   const char *mixed_name;
   char timebuf[30];
   struct ast_channel *tchan;
   struct ast_cel_event_record record = {
      .version = AST_CEL_EVENT_RECORD_VERSION,
   };
   struct ast_datastore *datastore;
   char *app_data;

   /* do not call ast_channel_alloc because this is not really a real channel */
   if (!(tchan = ast_dummy_channel_alloc())) {
      return NULL;
   }

   headp = ast_channel_varshead(tchan);

   /* first, get the variables from the event */
   if (ast_cel_fill_record(event, &record)) {
      ast_channel_unref(tchan);
      return NULL;
   }

   /* next, fill the channel with their data */
   mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
      ? record.user_defined_name : record.event_name;
   if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
      AST_LIST_INSERT_HEAD(headp, newvariable, entries);
   }

   if (ast_strlen_zero(cel_dateformat)) {
      snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
            (long) record.event_time.tv_usec);
   } else {
      struct ast_tm tm;
      ast_localtime(&record.event_time, &tm, NULL);
      ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
   }

   if ((newvariable = ast_var_assign("eventtime", timebuf))) {
      AST_LIST_INSERT_HEAD(headp, newvariable, entries);
   }

   if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
      AST_LIST_INSERT_HEAD(headp, newvariable, entries);
   }
   if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
      AST_LIST_INSERT_HEAD(headp, newvariable, entries);
   }
   if ((newvariable = ast_var_assign("eventextra", record.extra))) {
      AST_LIST_INSERT_HEAD(headp, newvariable, entries);
   }

   ast_channel_caller(tchan)->id.name.valid = 1;
   ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name);
   ast_channel_caller(tchan)->id.number.valid = 1;
   ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num);
   ast_channel_caller(tchan)->ani.number.valid = 1;
   ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani);
   ast_channel_redirecting(tchan)->from.number.valid = 1;
   ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis);
   ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid);

   ast_channel_exten_set(tchan, record.extension);
   ast_channel_context_set(tchan, record.context);
   ast_channel_name_set(tchan, record.channel_name);
   ast_channel_uniqueid_set(tchan, record.unique_id);
   ast_channel_linkedid_set(tchan, record.linked_id);
   ast_channel_accountcode_set(tchan, record.account_code);
   ast_channel_peeraccount_set(tchan, record.peer_account);
   ast_channel_userfield_set(tchan, record.user_field);

   if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
      AST_LIST_INSERT_HEAD(headp, newvariable, entries);
   }

   ast_channel_amaflags_set(tchan, record.amaflag);

   /* We need to store an 'application name' and 'application
    * data' on the channel for logging purposes, but the channel
    * structure only provides a place to store pointers, and it
    * expects these pointers to be pointing to data that does not
    * need to be freed. This means that the channel's destructor
    * does not attempt to free any storage that these pointers
    * point to. However, we can't provide data in that form directly for
    * these structure members. In order to ensure that these data
    * elements have a lifetime that matches the channel's
    * lifetime, we'll put them in a datastore attached to the
    * channel, and set's the channel's pointers to point into the
    * datastore.  The datastore will then be automatically destroyed
    * when the channel is destroyed.
    */

   if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
      ast_channel_unref(tchan);
      return NULL;
   }

   if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
      ast_datastore_free(datastore);
      ast_channel_unref(tchan);
      return NULL;
   }

   ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
   ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
      record.application_data));

   datastore->data = app_data;
   ast_channel_datastore_add(tchan, datastore);

   return tchan;
}
int ast_cel_fill_record ( const struct ast_event event,
struct ast_cel_event_record r 
)

Fill in an ast_cel_event_record from a CEL event.

Parameters:
[in]eventthe CEL event
[out]rthe ast_cel_event_record to fill in
Since:
1.8
Return values:
0success
non-zerofailure

Definition at line 765 of file cel.c.

References ast_cel_event_record::account_code, ast_cel_event_record::amaflag, ast_cel_event_record::application_data, ast_cel_event_record::application_name, AST_CEL_EVENT_RECORD_VERSION, ast_cel_get_type_name(), AST_CEL_USER_DEFINED, ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_CEL_USERFIELD, ast_log(), ast_cel_event_record::caller_id_ani, ast_cel_event_record::caller_id_dnid, ast_cel_event_record::caller_id_name, ast_cel_event_record::caller_id_num, ast_cel_event_record::caller_id_rdnis, ast_cel_event_record::channel_name, ast_cel_event_record::context, ast_cel_event_record::event_name, ast_cel_event_record::event_time, ast_cel_event_record::event_type, ast_cel_event_record::extension, ast_cel_event_record::extra, ast_cel_event_record::linked_id, LOG_ERROR, ast_cel_event_record::peer, ast_cel_event_record::peer_account, S_OR, ast_cel_event_record::unique_id, ast_cel_event_record::user_defined_name, ast_cel_event_record::user_field, and ast_cel_event_record::version.

Referenced by ast_cel_fabricate_channel_from_event().

{
   if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
      ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record.  "
            "Please ensure all modules were compiled for "
            "this version of Asterisk.\n");
      return -1;
   }

   r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);

   r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
   r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);

   r->event_name = ast_cel_get_type_name(r->event_type);
   if (r->event_type == AST_CEL_USER_DEFINED) {
      r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
   } else {
      r->user_defined_name = "";
   }

   r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
   r->caller_id_num    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
   r->caller_id_ani    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
   r->caller_id_rdnis  = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
   r->caller_id_dnid   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
   r->extension        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
   r->context          = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
   r->channel_name     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
   r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
   r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
   r->account_code     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
   r->peer_account     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
   r->unique_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
   r->linked_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
   r->amaflag          = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
   r->user_field       = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
   r->peer             = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
   r->extra            = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");

   return 0;
}
const char* ast_cel_get_ama_flag_name ( enum ast_cel_ama_flag  flag)

Convert AMA flag to printable string.

Parameters:
[in]flagthe flag to convert to a string
Since:
1.8
Returns:
the string representation of the flag

Definition at line 417 of file cel.c.

References ARRAY_LEN, ast_log(), LOG_WARNING, and S_OR.

{
   if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
      ast_log(LOG_WARNING, "Invalid AMA flag: %d\n", flag);
      return "Unknown";
   }

   return S_OR(cel_ama_flags[flag], "Unknown");
}
const char* ast_cel_get_type_name ( enum ast_cel_event_type  type)

Get the name of a CEL event type.

Parameters:
typethe type to get the name of
Since:
1.8
Returns:
the string representation of the type

Definition at line 412 of file cel.c.

References S_OR.

Referenced by ast_cel_fill_record(), and handle_cli_status().

{
   return S_OR(cel_event_types[type], "Unknown");
}
int ast_cel_linkedid_ref ( const char *  linkedid)

Inform CEL that a new linkedid is being used.

Since:
11
Return values:
-1error
0success

Definition at line 601 of file cel.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_find, ao2_link, ao2_ref, AST_CEL_LINKEDID_END, ast_cel_track_event(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), cel_linkedid::count, cel_linkedid::id, LOG_ERROR, OBJ_KEY, and reload_lock.

Referenced by ast_cel_report_event(), and ast_channel_change_linkedid().

{
   struct cel_linkedid *lid;

   if (ast_strlen_zero(linkedid)) {
      ast_log(LOG_ERROR, "The linkedid should never be empty\n");
      return -1;
   }

   /* Get the lock in case any CEL events are still in flight when we shutdown. */
   ast_mutex_lock(&reload_lock);

   if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
      /* CEL is disabled or we are not tracking linkedids. */
      ast_mutex_unlock(&reload_lock);
      return 0;
   }
   if (!linkedids) {
      /* The CEL module is shutdown.  Abort. */
      ast_mutex_unlock(&reload_lock);
      return -1;
   }

   lid = ao2_find(linkedids, (void *) linkedid, OBJ_KEY);
   if (!lid) {
      /*
       * Changes to the lid->count member are protected by the
       * reload_lock so the lid object does not need its own lock.
       */
      lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
         AO2_ALLOC_OPT_LOCK_NOLOCK);
      if (!lid) {
         ast_mutex_unlock(&reload_lock);
         return -1;
      }
      strcpy(lid->id, linkedid);/* Safe */

      ao2_link(linkedids, lid);
   }
   ++lid->count;
   ast_mutex_unlock(&reload_lock);
   ao2_ref(lid, -1);

   return 0;
}
int ast_cel_report_event ( struct ast_channel chan,
enum ast_cel_event_type  event_type,
const char *  userdefevname,
const char *  extra,
struct ast_channel peer2 
)

Report a channel event.

Parameters:
chanThis argument is required. This is the primary channel associated with this channel event.
event_typeThis is the type of call event being reported.
userdefevnameThis is an optional custom name for the call event.
extraThis is an optional opaque field that will go into the "CEL_EXTRA" information element of the call event.
peer2All CEL events contain a "peer name" information element. The first place the code will look to get a peer name is from the bridged channel to chan. If chan has no bridged channel and peer2 is specified, then the name of peer2 will go into the "peer name" field. If neither are available, the peer name field will be blank.
Since:
1.8
Precondition:
chan and peer2 are both unlocked
Return values:
0success
non-zerofailure

Definition at line 647 of file cel.c.

References ao2_find, ao2_ref, app, ast_bridged_channel(), AST_CEL_APP_END, AST_CEL_APP_START, AST_CEL_CHANNEL_START, AST_CEL_LINKEDID_END, ast_cel_linkedid_ref(), ast_cel_track_event(), ast_channel_accountcode(), ast_channel_amaflags(), ast_channel_appl(), ast_channel_caller(), ast_channel_context(), ast_channel_data(), ast_channel_dialed(), ast_channel_exten(), ast_channel_linkedid(), ast_channel_lock, ast_channel_name(), ast_channel_peeraccount(), ast_channel_redirecting(), ast_channel_ref, ast_channel_uniqueid(), ast_channel_unlock, ast_channel_unref, ast_channel_userfield(), AST_EVENT_CEL, ast_event_destroy(), AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, ast_event_new(), ast_event_queue(), ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), ast_channel::linkedid, name, OBJ_POINTER, reload_lock, S_COR, and S_OR.

Referenced by __ast_channel_alloc_ap(), __ast_read(), analog_attempt_transfer(), ast_bridge_call(), ast_cel_check_retire_linkedid(), ast_channel_destructor(), ast_do_masquerade(), ast_do_pickup(), ast_hangup(), ast_raw_answer(), builtin_atxfer(), builtin_blindtransfer(), celgenuserevent_exec(), do_forward(), handle_request_refer(), local_attended_transfer(), manage_parked_call(), park_call_full(), parked_call_exec(), pbx_exec(), and wait_for_answer().

{
   struct timeval eventtime;
   struct ast_event *ev;
   const char *peername = "";
   struct ast_channel *peer;
   char *linkedid = ast_strdupa(ast_channel_linkedid(chan));

   /* Make sure a reload is not occurring while we're checking to see if this
    * is an event that we care about.  We could lose an important event in this
    * process otherwise. */
   ast_mutex_lock(&reload_lock);

   if (!appset) {
      /* The CEL module is shutdown.  Abort. */
      ast_mutex_unlock(&reload_lock);
      return -1;
   }

   /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
    * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
   if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
      if (ast_cel_linkedid_ref(linkedid)) {
         ast_mutex_unlock(&reload_lock);
         return -1;
      }
   }

   if (!cel_enabled || !ast_cel_track_event(event_type)) {
      ast_mutex_unlock(&reload_lock);
      return 0;
   }

   if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
      char *app;
      if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
         ast_mutex_unlock(&reload_lock);
         return 0;
      }
      ao2_ref(app, -1);
   }

   ast_mutex_unlock(&reload_lock);

   ast_channel_lock(chan);
   peer = ast_bridged_channel(chan);
   if (peer) {
      ast_channel_ref(peer);
   }
   ast_channel_unlock(chan);

   if (peer) {
      ast_channel_lock(peer);
      peername = ast_strdupa(ast_channel_name(peer));
      ast_channel_unlock(peer);
   } else if (peer2) {
      ast_channel_lock(peer2);
      peername = ast_strdupa(ast_channel_name(peer2));
      ast_channel_unlock(peer2);
   }

   if (!userdefevname) {
      userdefevname = "";
   }

   if (!extra) {
      extra = "";
   }

   eventtime = ast_tvnow();

   ast_channel_lock(chan);

   ev = ast_event_new(AST_EVENT_CEL,
      AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
      AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
      AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
      AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
      AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
         S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
      AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
         S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
      AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
         S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
      AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
         S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
      AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
         S_OR(ast_channel_dialed(chan)->number.str, ""),
      AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
      AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
      AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
      AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
      AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
      AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
      AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
      AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
      AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
      AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
      AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
      AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
      AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
      AST_EVENT_IE_END);

   ast_channel_unlock(chan);

   if (peer) {
      peer = ast_channel_unref(peer);
   }

   if (ev && ast_event_queue(ev)) {
      ast_event_destroy(ev);
      return -1;
   }

   return 0;
}
enum ast_cel_event_type ast_cel_str_to_event_type ( const char *  name)

Get the event type from a string.

Parameters:
namethe event type name as a string
Since:
1.8
Returns:
the ast_cel_event_type given by the string

Definition at line 254 of file cel.c.

References ARRAY_LEN.

Referenced by parse_events().

{
   unsigned int i;

   for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
      if (!cel_event_types[i]) {
         continue;
      }

      if (!strcasecmp(name, cel_event_types[i])) {
         return i;
      }
   }

   return -1;
}