00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 377881 $")
00037
00038 #include "asterisk/_private.h"
00039
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/cel.h"
00043 #include "asterisk/logger.h"
00044 #include "asterisk/linkedlists.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/config.h"
00047 #include "asterisk/cli.h"
00048 #include "asterisk/astobj2.h"
00049
00050
00051 static unsigned char cel_enabled;
00052
00053
00054 #define CEL_ENABLED_DEFAULT 0
00055
00056
00057
00058
00059
00060
00061 static int64_t eventset;
00062
00063
00064
00065
00066
00067 #define CEL_MAX_EVENT_IDS 64
00068
00069
00070
00071
00072 #define CEL_DEFAULT_EVENTS 0
00073
00074
00075
00076
00077 #define NUM_APP_BUCKETS 97
00078
00079
00080
00081
00082
00083
00084
00085
00086 static struct ao2_container *appset;
00087 static struct ao2_container *linkedids;
00088
00089
00090
00091
00092 static char cel_dateformat[256];
00093
00094
00095
00096
00097 static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
00098 [0] = "ALL",
00099 [AST_CEL_CHANNEL_START] = "CHAN_START",
00100 [AST_CEL_CHANNEL_END] = "CHAN_END",
00101 [AST_CEL_ANSWER] = "ANSWER",
00102 [AST_CEL_HANGUP] = "HANGUP",
00103 [AST_CEL_APP_START] = "APP_START",
00104 [AST_CEL_APP_END] = "APP_END",
00105 [AST_CEL_BRIDGE_START] = "BRIDGE_START",
00106 [AST_CEL_BRIDGE_END] = "BRIDGE_END",
00107 [AST_CEL_BRIDGE_UPDATE] = "BRIDGE_UPDATE",
00108 [AST_CEL_CONF_START] = "CONF_START",
00109 [AST_CEL_CONF_END] = "CONF_END",
00110 [AST_CEL_PARK_START] = "PARK_START",
00111 [AST_CEL_PARK_END] = "PARK_END",
00112 [AST_CEL_TRANSFER] = "TRANSFER",
00113 [AST_CEL_USER_DEFINED] = "USER_DEFINED",
00114 [AST_CEL_CONF_ENTER] = "CONF_ENTER",
00115 [AST_CEL_CONF_EXIT] = "CONF_EXIT",
00116 [AST_CEL_BLINDTRANSFER] = "BLINDTRANSFER",
00117 [AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
00118 [AST_CEL_PICKUP] = "PICKUP",
00119 [AST_CEL_FORWARD] = "FORWARD",
00120 [AST_CEL_3WAY_START] = "3WAY_START",
00121 [AST_CEL_3WAY_END] = "3WAY_END",
00122 [AST_CEL_HOOKFLASH] = "HOOKFLASH",
00123 [AST_CEL_LINKEDID_END] = "LINKEDID_END",
00124 };
00125
00126
00127
00128
00129 static const char * const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] = {
00130 [AST_CEL_AMA_FLAG_NONE] = "NONE",
00131 [AST_CEL_AMA_FLAG_OMIT] = "OMIT",
00132 [AST_CEL_AMA_FLAG_BILLING] = "BILLING",
00133 [AST_CEL_AMA_FLAG_DOCUMENTATION] = "DOCUMENTATION",
00134 };
00135
00136 unsigned int ast_cel_check_enabled(void)
00137 {
00138 return cel_enabled;
00139 }
00140
00141 static int print_app(void *obj, void *arg, int flags)
00142 {
00143 struct ast_cli_args *a = arg;
00144
00145 ast_cli(a->fd, "CEL Tracking Application: %s\n", (const char *) obj);
00146
00147 return 0;
00148 }
00149
00150 static void print_cel_sub(const struct ast_event *event, void *data)
00151 {
00152 struct ast_cli_args *a = data;
00153
00154 ast_cli(a->fd, "CEL Event Subscriber: %s\n",
00155 ast_event_get_ie_str(event, AST_EVENT_IE_DESCRIPTION));
00156 }
00157
00158 static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00159 {
00160 unsigned int i;
00161 struct ast_event_sub *sub;
00162
00163 switch (cmd) {
00164 case CLI_INIT:
00165 e->command = "cel show status";
00166 e->usage =
00167 "Usage: cel show status\n"
00168 " Displays the Channel Event Logging system status.\n";
00169 return NULL;
00170 case CLI_GENERATE:
00171 return NULL;
00172 case CLI_HANDLER:
00173 break;
00174 }
00175
00176 if (a->argc > 3) {
00177 return CLI_SHOWUSAGE;
00178 }
00179
00180 ast_cli(a->fd, "CEL Logging: %s\n", cel_enabled ? "Enabled" : "Disabled");
00181
00182 if (!cel_enabled) {
00183 return CLI_SUCCESS;
00184 }
00185
00186 for (i = 0; i < (sizeof(eventset) * 8); i++) {
00187 const char *name;
00188
00189 if (!(eventset & ((int64_t) 1 << i))) {
00190 continue;
00191 }
00192
00193 name = ast_cel_get_type_name(i);
00194 if (strcasecmp(name, "Unknown")) {
00195 ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
00196 }
00197 }
00198
00199 ao2_callback(appset, OBJ_NODATA, print_app, a);
00200
00201 if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
00202 return CLI_FAILURE;
00203 }
00204 ast_event_sub_append_ie_uint(sub, AST_EVENT_IE_EVENTTYPE, AST_EVENT_CEL);
00205 ast_event_report_subs(sub);
00206 ast_event_sub_destroy(sub);
00207 sub = NULL;
00208
00209 return CLI_SUCCESS;
00210 }
00211
00212 static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status");
00213
00214 enum ast_cel_event_type ast_cel_str_to_event_type(const char *name)
00215 {
00216 unsigned int i;
00217
00218 for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
00219 if (!cel_event_types[i]) {
00220 continue;
00221 }
00222
00223 if (!strcasecmp(name, cel_event_types[i])) {
00224 return i;
00225 }
00226 }
00227
00228 return -1;
00229 }
00230
00231 static int ast_cel_track_event(enum ast_cel_event_type et)
00232 {
00233 return (eventset & ((int64_t) 1 << et));
00234 }
00235
00236 static void parse_events(const char *val)
00237 {
00238 char *events = ast_strdupa(val);
00239 char *cur_event;
00240
00241 while ((cur_event = strsep(&events, ","))) {
00242 enum ast_cel_event_type event_type;
00243
00244 cur_event = ast_strip(cur_event);
00245 if (ast_strlen_zero(cur_event)) {
00246 continue;
00247 }
00248
00249 event_type = ast_cel_str_to_event_type(cur_event);
00250
00251 if (event_type == 0) {
00252
00253 eventset = (int64_t) -1;
00254 } else if (event_type == -1) {
00255 ast_log(LOG_WARNING, "Unknown event name '%s'\n",
00256 cur_event);
00257 } else {
00258 eventset |= ((int64_t) 1 << event_type);
00259 }
00260 }
00261 }
00262
00263 static void parse_apps(const char *val)
00264 {
00265 char *apps = ast_strdupa(val);
00266 char *cur_app;
00267
00268 if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) {
00269 ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n");
00270 return;
00271 }
00272
00273 while ((cur_app = strsep(&apps, ","))) {
00274 char *app;
00275
00276 cur_app = ast_strip(cur_app);
00277 if (ast_strlen_zero(cur_app)) {
00278 continue;
00279 }
00280
00281 if (!(app = ao2_alloc(strlen(cur_app) + 1, NULL))) {
00282 continue;
00283 }
00284 strcpy(app, cur_app);
00285
00286 ao2_link(appset, app);
00287 ao2_ref(app, -1);
00288 app = NULL;
00289 }
00290 }
00291
00292 AST_MUTEX_DEFINE_STATIC(reload_lock);
00293
00294 static int do_reload(void)
00295 {
00296 struct ast_config *config;
00297 const char *enabled_value;
00298 const char *val;
00299 int res = 0;
00300 struct ast_flags config_flags = { 0, };
00301 const char *s;
00302
00303 ast_mutex_lock(&reload_lock);
00304
00305
00306 cel_enabled = CEL_ENABLED_DEFAULT;
00307 eventset = CEL_DEFAULT_EVENTS;
00308 *cel_dateformat = '\0';
00309 ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00310
00311 config = ast_config_load2("cel.conf", "cel", config_flags);
00312
00313 if (config == CONFIG_STATUS_FILEMISSING) {
00314 config = NULL;
00315 goto return_cleanup;
00316 }
00317
00318 if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00319 cel_enabled = ast_true(enabled_value);
00320 }
00321
00322 if (!cel_enabled) {
00323 goto return_cleanup;
00324 }
00325
00326
00327 if ((s = ast_variable_retrieve(config, "general", "dateformat"))) {
00328 ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat));
00329 }
00330
00331 if ((val = ast_variable_retrieve(config, "general", "events"))) {
00332 parse_events(val);
00333 }
00334
00335 if ((val = ast_variable_retrieve(config, "general", "apps"))) {
00336 parse_apps(val);
00337 }
00338
00339 return_cleanup:
00340 ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis");
00341
00342 ast_mutex_unlock(&reload_lock);
00343
00344 if (config) {
00345 ast_config_destroy(config);
00346 }
00347
00348 return res;
00349 }
00350
00351 const char *ast_cel_get_type_name(enum ast_cel_event_type type)
00352 {
00353 return S_OR(cel_event_types[type], "Unknown");
00354 }
00355
00356 const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag)
00357 {
00358 if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
00359 ast_log(LOG_WARNING, "Invalid AMA flag: %d\n", flag);
00360 return "Unknown";
00361 }
00362
00363 return S_OR(cel_ama_flags[flag], "Unknown");
00364 }
00365
00366
00367
00368 void ast_cel_check_retire_linkedid(struct ast_channel *chan)
00369 {
00370 const char *linkedid = chan->linkedid;
00371 char *lid;
00372
00373
00374
00375 if (ast_strlen_zero(linkedid) || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
00376 return;
00377 }
00378
00379 if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) {
00380 ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
00381 return;
00382 }
00383
00384
00385
00386 if (ao2_ref(lid, -1) == 3) {
00387 ao2_unlink(linkedids, lid);
00388 ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
00389 }
00390 ao2_ref(lid, -1);
00391 }
00392
00393
00394
00395
00396 static const struct ast_datastore_info fabricated_channel_datastore = {
00397 .type = "CEL fabricated channel",
00398 .destroy = ast_free_ptr,
00399 };
00400
00401 struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event)
00402 {
00403 struct varshead *headp;
00404 struct ast_var_t *newvariable;
00405 char timebuf[30];
00406 struct ast_channel *tchan;
00407 struct ast_cel_event_record record = {
00408 .version = AST_CEL_EVENT_RECORD_VERSION,
00409 };
00410 struct ast_datastore *datastore;
00411 char *app_data;
00412
00413
00414 if (!(tchan = ast_dummy_channel_alloc())) {
00415 return NULL;
00416 }
00417
00418 headp = &tchan->varshead;
00419
00420
00421 if (ast_cel_fill_record(event, &record)) {
00422 ast_channel_unref(tchan);
00423 return NULL;
00424 }
00425
00426
00427 if ((newvariable = ast_var_assign("eventtype", record.event_name))) {
00428 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00429 }
00430
00431 if (ast_strlen_zero(cel_dateformat)) {
00432 snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
00433 (long) record.event_time.tv_usec);
00434 } else {
00435 struct ast_tm tm;
00436 ast_localtime(&record.event_time, &tm, NULL);
00437 ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
00438 }
00439
00440 if ((newvariable = ast_var_assign("eventtime", timebuf))) {
00441 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00442 }
00443
00444 if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
00445 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00446 }
00447 if ((newvariable = ast_var_assign("eventextra", record.extra))) {
00448 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00449 }
00450
00451 tchan->caller.id.name.valid = 1;
00452 tchan->caller.id.name.str = ast_strdup(record.caller_id_name);
00453 tchan->caller.id.number.valid = 1;
00454 tchan->caller.id.number.str = ast_strdup(record.caller_id_num);
00455 tchan->caller.ani.number.valid = 1;
00456 tchan->caller.ani.number.str = ast_strdup(record.caller_id_ani);
00457 tchan->redirecting.from.number.valid = 1;
00458 tchan->redirecting.from.number.str = ast_strdup(record.caller_id_rdnis);
00459 tchan->dialed.number.str = ast_strdup(record.caller_id_dnid);
00460
00461 ast_copy_string(tchan->exten, record.extension, sizeof(tchan->exten));
00462 ast_copy_string(tchan->context, record.context, sizeof(tchan->context));
00463 ast_string_field_set(tchan, name, record.channel_name);
00464 ast_string_field_set(tchan, uniqueid, record.unique_id);
00465 ast_string_field_set(tchan, linkedid, record.linked_id);
00466 ast_string_field_set(tchan, accountcode, record.account_code);
00467 ast_string_field_set(tchan, peeraccount, record.peer_account);
00468 ast_string_field_set(tchan, userfield, record.user_field);
00469
00470 if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
00471 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00472 }
00473
00474 tchan->amaflags = record.amaflag;
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
00492 ast_channel_unref(tchan);
00493 return NULL;
00494 }
00495
00496 if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
00497 ast_datastore_free(datastore);
00498 ast_channel_unref(tchan);
00499 return NULL;
00500 }
00501
00502 tchan->appl = strcpy(app_data, record.application_name);
00503 tchan->data = strcpy(app_data + strlen(record.application_name) + 1,
00504 record.application_data);
00505
00506 datastore->data = app_data;
00507 ast_channel_datastore_add(tchan, datastore);
00508
00509 return tchan;
00510 }
00511
00512 int ast_cel_linkedid_ref(const char *linkedid)
00513 {
00514 char *lid;
00515
00516 if (ast_strlen_zero(linkedid)) {
00517 ast_log(LOG_ERROR, "The linkedid should never be empty\n");
00518 return -1;
00519 }
00520
00521 if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) {
00522 if (!(lid = ao2_alloc(strlen(linkedid) + 1, NULL))) {
00523 return -1;
00524 }
00525 strcpy(lid, linkedid);
00526 if (!ao2_link(linkedids, lid)) {
00527 ao2_ref(lid, -1);
00528 return -1;
00529 }
00530
00531 }
00532
00533
00534 return 0;
00535 }
00536
00537 int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
00538 const char *userdefevname, const char *extra, struct ast_channel *peer2)
00539 {
00540 struct timeval eventtime;
00541 struct ast_event *ev;
00542 const char *peername = "";
00543 struct ast_channel *peer;
00544
00545
00546
00547
00548 ast_mutex_lock(&reload_lock);
00549
00550
00551
00552 if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && chan->linkedid) {
00553 if (ast_cel_linkedid_ref(chan->linkedid)) {
00554 ast_mutex_unlock(&reload_lock);
00555 return -1;
00556 }
00557 }
00558
00559 if (!cel_enabled || !ast_cel_track_event(event_type)) {
00560 ast_mutex_unlock(&reload_lock);
00561 return 0;
00562 }
00563
00564 if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
00565 char *app;
00566 if (!(app = ao2_find(appset, (char *) chan->appl, OBJ_POINTER))) {
00567 ast_mutex_unlock(&reload_lock);
00568 return 0;
00569 }
00570 ao2_ref(app, -1);
00571 }
00572
00573 ast_mutex_unlock(&reload_lock);
00574
00575 ast_channel_lock(chan);
00576 peer = ast_bridged_channel(chan);
00577 if (peer) {
00578 ast_channel_ref(peer);
00579 }
00580 ast_channel_unlock(chan);
00581
00582 if (peer) {
00583 ast_channel_lock(peer);
00584 peername = ast_strdupa(peer->name);
00585 ast_channel_unlock(peer);
00586 } else if (peer2) {
00587 ast_channel_lock(peer2);
00588 peername = ast_strdupa(peer2->name);
00589 ast_channel_unlock(peer2);
00590 }
00591
00592 if (!userdefevname) {
00593 userdefevname = "";
00594 }
00595
00596 if (!extra) {
00597 extra = "";
00598 }
00599
00600 eventtime = ast_tvnow();
00601
00602 ast_channel_lock(chan);
00603
00604 ev = ast_event_new(AST_EVENT_CEL,
00605 AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
00606 AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
00607 AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
00608 AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
00609 AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
00610 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""),
00611 AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
00612 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
00613 AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
00614 S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, ""),
00615 AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
00616 S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, ""),
00617 AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
00618 S_OR(chan->dialed.number.str, ""),
00619 AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, chan->exten,
00620 AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, chan->context,
00621 AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, chan->name,
00622 AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->appl, ""),
00623 AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->data, ""),
00624 AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, chan->amaflags,
00625 AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, chan->accountcode,
00626 AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, chan->peeraccount,
00627 AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, chan->uniqueid,
00628 AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, chan->linkedid,
00629 AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, chan->userfield,
00630 AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
00631 AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
00632 AST_EVENT_IE_END);
00633
00634 ast_channel_unlock(chan);
00635
00636 if (peer) {
00637 peer = ast_channel_unref(peer);
00638 }
00639
00640 if (ev && ast_event_queue(ev)) {
00641 ast_event_destroy(ev);
00642 return -1;
00643 }
00644
00645 return 0;
00646 }
00647
00648 int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
00649 {
00650 if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
00651 ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
00652 "Please ensure all modules were compiled for "
00653 "this version of Asterisk.\n");
00654 return -1;
00655 }
00656
00657 r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
00658
00659 r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
00660 r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
00661
00662 r->user_defined_name = "";
00663
00664 if (r->event_type == AST_CEL_USER_DEFINED) {
00665 r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
00666 r->event_name = r->user_defined_name;
00667 } else {
00668 r->event_name = ast_cel_get_type_name(r->event_type);
00669 }
00670
00671 r->caller_id_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
00672 r->caller_id_num = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
00673 r->caller_id_ani = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
00674 r->caller_id_rdnis = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
00675 r->caller_id_dnid = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
00676 r->extension = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
00677 r->context = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
00678 r->channel_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
00679 r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
00680 r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
00681 r->account_code = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00682 r->peer_account = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00683 r->unique_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
00684 r->linked_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
00685 r->amaflag = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
00686 r->user_field = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
00687 r->peer = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
00688 r->extra = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
00689
00690 return 0;
00691 }
00692
00693 static int app_hash(const void *obj, const int flags)
00694 {
00695 return ast_str_case_hash((const char *) obj);
00696 }
00697
00698 static int app_cmp(void *obj, void *arg, int flags)
00699 {
00700 const char *app1 = obj, *app2 = arg;
00701
00702 return !strcasecmp(app1, app2) ? CMP_MATCH | CMP_STOP : 0;
00703 }
00704
00705 #define lid_hash app_hash
00706 #define lid_cmp app_cmp
00707
00708 static void ast_cel_engine_term(void)
00709 {
00710 if (appset) {
00711 ao2_ref(appset, -1);
00712 appset = NULL;
00713 }
00714 if (linkedids) {
00715 ao2_ref(linkedids, -1);
00716 linkedids = NULL;
00717 }
00718 ast_cli_unregister(&cli_status);
00719 }
00720
00721 int ast_cel_engine_init(void)
00722 {
00723 if (!(appset = ao2_container_alloc(NUM_APP_BUCKETS, app_hash, app_cmp))) {
00724 return -1;
00725 }
00726 if (!(linkedids = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp))) {
00727 ao2_ref(appset, -1);
00728 return -1;
00729 }
00730
00731 if (do_reload() || ast_cli_register(&cli_status)) {
00732 ao2_ref(appset, -1);
00733 appset = NULL;
00734 ao2_ref(linkedids, -1);
00735 linkedids = NULL;
00736 return -1;
00737 }
00738
00739 ast_register_atexit(ast_cel_engine_term);
00740
00741 return 0;
00742 }
00743
00744 int ast_cel_engine_reload(void)
00745 {
00746 return do_reload();
00747 }
00748