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: 406418 $")
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 const char cel_conf_file[] = "cel.conf";
00052
00053
00054 static unsigned char cel_enabled;
00055
00056
00057 #define CEL_ENABLED_DEFAULT 0
00058
00059
00060
00061
00062
00063
00064 static int64_t eventset;
00065
00066
00067
00068
00069
00070 #define CEL_MAX_EVENT_IDS 64
00071
00072
00073
00074
00075 #define CEL_DEFAULT_EVENTS 0
00076
00077
00078
00079
00080 #define NUM_APP_BUCKETS 97
00081
00082
00083
00084
00085
00086
00087
00088 AST_MUTEX_DEFINE_STATIC(reload_lock);
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 static struct ao2_container *appset;
00101
00102 struct cel_linkedid {
00103
00104 unsigned int count;
00105
00106 char id[0];
00107 };
00108
00109
00110
00111
00112
00113
00114
00115 static struct ao2_container *linkedids;
00116
00117
00118
00119
00120 static char cel_dateformat[256];
00121
00122
00123
00124
00125 static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
00126 [0] = "ALL",
00127 [AST_CEL_CHANNEL_START] = "CHAN_START",
00128 [AST_CEL_CHANNEL_END] = "CHAN_END",
00129 [AST_CEL_ANSWER] = "ANSWER",
00130 [AST_CEL_HANGUP] = "HANGUP",
00131 [AST_CEL_APP_START] = "APP_START",
00132 [AST_CEL_APP_END] = "APP_END",
00133 [AST_CEL_BRIDGE_START] = "BRIDGE_START",
00134 [AST_CEL_BRIDGE_END] = "BRIDGE_END",
00135 [AST_CEL_BRIDGE_UPDATE] = "BRIDGE_UPDATE",
00136 [AST_CEL_CONF_START] = "CONF_START",
00137 [AST_CEL_CONF_END] = "CONF_END",
00138 [AST_CEL_PARK_START] = "PARK_START",
00139 [AST_CEL_PARK_END] = "PARK_END",
00140 [AST_CEL_TRANSFER] = "TRANSFER",
00141 [AST_CEL_USER_DEFINED] = "USER_DEFINED",
00142 [AST_CEL_CONF_ENTER] = "CONF_ENTER",
00143 [AST_CEL_CONF_EXIT] = "CONF_EXIT",
00144 [AST_CEL_BLINDTRANSFER] = "BLINDTRANSFER",
00145 [AST_CEL_ATTENDEDTRANSFER] = "ATTENDEDTRANSFER",
00146 [AST_CEL_PICKUP] = "PICKUP",
00147 [AST_CEL_FORWARD] = "FORWARD",
00148 [AST_CEL_3WAY_START] = "3WAY_START",
00149 [AST_CEL_3WAY_END] = "3WAY_END",
00150 [AST_CEL_HOOKFLASH] = "HOOKFLASH",
00151 [AST_CEL_LINKEDID_END] = "LINKEDID_END",
00152 };
00153
00154
00155
00156
00157 static const char * const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] = {
00158 [AST_CEL_AMA_FLAG_NONE] = "NONE",
00159 [AST_CEL_AMA_FLAG_OMIT] = "OMIT",
00160 [AST_CEL_AMA_FLAG_BILLING] = "BILLING",
00161 [AST_CEL_AMA_FLAG_DOCUMENTATION] = "DOCUMENTATION",
00162 };
00163
00164 unsigned int ast_cel_check_enabled(void)
00165 {
00166 return cel_enabled;
00167 }
00168
00169 static void print_cel_sub(const struct ast_event *event, void *data)
00170 {
00171 struct ast_cli_args *a = data;
00172
00173 ast_cli(a->fd, "CEL Event Subscriber: %s\n",
00174 ast_event_get_ie_str(event, AST_EVENT_IE_DESCRIPTION));
00175 }
00176
00177 static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00178 {
00179 unsigned int i;
00180 struct ast_event_sub *sub;
00181
00182 switch (cmd) {
00183 case CLI_INIT:
00184 e->command = "cel show status";
00185 e->usage =
00186 "Usage: cel show status\n"
00187 " Displays the Channel Event Logging system status.\n";
00188 return NULL;
00189 case CLI_GENERATE:
00190 return NULL;
00191 case CLI_HANDLER:
00192 break;
00193 }
00194
00195 if (a->argc > 3) {
00196 return CLI_SHOWUSAGE;
00197 }
00198
00199 ast_cli(a->fd, "CEL Logging: %s\n", cel_enabled ? "Enabled" : "Disabled");
00200
00201 if (!cel_enabled) {
00202 return CLI_SUCCESS;
00203 }
00204
00205 for (i = 0; i < (sizeof(eventset) * 8); i++) {
00206 const char *name;
00207
00208 if (!(eventset & ((int64_t) 1 << i))) {
00209 continue;
00210 }
00211
00212 name = ast_cel_get_type_name(i);
00213 if (strcasecmp(name, "Unknown")) {
00214 ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
00215 }
00216 }
00217
00218
00219 ast_mutex_lock(&reload_lock);
00220 if (appset) {
00221 struct ao2_iterator iter;
00222 char *app;
00223
00224 iter = ao2_iterator_init(appset, 0);
00225 for (;;) {
00226 app = ao2_iterator_next(&iter);
00227 if (!app) {
00228 break;
00229 }
00230 ast_mutex_unlock(&reload_lock);
00231
00232 ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
00233
00234 ao2_ref(app, -1);
00235 ast_mutex_lock(&reload_lock);
00236 }
00237 ao2_iterator_destroy(&iter);
00238 }
00239 ast_mutex_unlock(&reload_lock);
00240
00241 if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
00242 return CLI_FAILURE;
00243 }
00244 ast_event_sub_append_ie_uint(sub, AST_EVENT_IE_EVENTTYPE, AST_EVENT_CEL);
00245 ast_event_report_subs(sub);
00246 ast_event_sub_destroy(sub);
00247 sub = NULL;
00248
00249 return CLI_SUCCESS;
00250 }
00251
00252 static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status");
00253
00254 enum ast_cel_event_type ast_cel_str_to_event_type(const char *name)
00255 {
00256 unsigned int i;
00257
00258 for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
00259 if (!cel_event_types[i]) {
00260 continue;
00261 }
00262
00263 if (!strcasecmp(name, cel_event_types[i])) {
00264 return i;
00265 }
00266 }
00267
00268 return -1;
00269 }
00270
00271 static int ast_cel_track_event(enum ast_cel_event_type et)
00272 {
00273 return (eventset & ((int64_t) 1 << et));
00274 }
00275
00276 static void parse_events(const char *val)
00277 {
00278 char *events = ast_strdupa(val);
00279 char *cur_event;
00280
00281 while ((cur_event = strsep(&events, ","))) {
00282 enum ast_cel_event_type event_type;
00283
00284 cur_event = ast_strip(cur_event);
00285 if (ast_strlen_zero(cur_event)) {
00286 continue;
00287 }
00288
00289 event_type = ast_cel_str_to_event_type(cur_event);
00290
00291 if (event_type == 0) {
00292
00293 eventset = (int64_t) -1;
00294 } else if (event_type == -1) {
00295 ast_log(LOG_WARNING, "Unknown event name '%s'\n",
00296 cur_event);
00297 } else {
00298 eventset |= ((int64_t) 1 << event_type);
00299 }
00300 }
00301 }
00302
00303 static void parse_apps(const char *val)
00304 {
00305 char *apps = ast_strdupa(val);
00306 char *cur_app;
00307
00308 if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) {
00309 ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n");
00310 return;
00311 }
00312
00313 while ((cur_app = strsep(&apps, ","))) {
00314 char *app;
00315
00316 cur_app = ast_strip(cur_app);
00317 if (ast_strlen_zero(cur_app)) {
00318 continue;
00319 }
00320
00321
00322 app = ao2_alloc_options(strlen(cur_app) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
00323 if (!app) {
00324 continue;
00325 }
00326 strcpy(app, cur_app);
00327
00328 ao2_link(appset, app);
00329 ao2_ref(app, -1);
00330 app = NULL;
00331 }
00332 }
00333
00334 static void set_defaults(void)
00335 {
00336 cel_enabled = CEL_ENABLED_DEFAULT;
00337 eventset = CEL_DEFAULT_EVENTS;
00338 *cel_dateformat = '\0';
00339 ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00340 }
00341
00342 static int do_reload(int is_reload)
00343 {
00344 struct ast_config *config;
00345 const char *enabled_value;
00346 const char *val;
00347 int res = 0;
00348 struct ast_flags config_flags = { 0, };
00349 const char *s;
00350
00351 ast_mutex_lock(&reload_lock);
00352
00353 if (!is_reload) {
00354
00355 set_defaults();
00356 }
00357
00358
00359
00360
00361
00362 config = ast_config_load2(cel_conf_file, "cel", config_flags);
00363 if (!config || config == CONFIG_STATUS_FILEINVALID) {
00364 ast_log(LOG_WARNING, "Could not load %s\n", cel_conf_file);
00365 config = NULL;
00366 goto return_cleanup;
00367 }
00368 if (config == CONFIG_STATUS_FILEUNCHANGED) {
00369
00370 config = NULL;
00371 goto return_cleanup;
00372 }
00373
00374 if (is_reload) {
00375
00376 set_defaults();
00377 }
00378
00379 if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00380 cel_enabled = ast_true(enabled_value);
00381 }
00382
00383 if (!cel_enabled) {
00384 goto return_cleanup;
00385 }
00386
00387
00388 if ((s = ast_variable_retrieve(config, "general", "dateformat"))) {
00389 ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat));
00390 }
00391
00392 if ((val = ast_variable_retrieve(config, "general", "events"))) {
00393 parse_events(val);
00394 }
00395
00396 if ((val = ast_variable_retrieve(config, "general", "apps"))) {
00397 parse_apps(val);
00398 }
00399
00400 return_cleanup:
00401 ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis");
00402
00403 ast_mutex_unlock(&reload_lock);
00404
00405 if (config) {
00406 ast_config_destroy(config);
00407 }
00408
00409 return res;
00410 }
00411
00412 const char *ast_cel_get_type_name(enum ast_cel_event_type type)
00413 {
00414 return S_OR(cel_event_types[type], "Unknown");
00415 }
00416
00417 const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag)
00418 {
00419 if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
00420 ast_log(LOG_WARNING, "Invalid AMA flag: %d\n", flag);
00421 return "Unknown";
00422 }
00423
00424 return S_OR(cel_ama_flags[flag], "Unknown");
00425 }
00426
00427
00428
00429 void ast_cel_check_retire_linkedid(struct ast_channel *chan)
00430 {
00431 const char *linkedid = ast_channel_linkedid(chan);
00432 struct cel_linkedid *lid;
00433
00434 if (ast_strlen_zero(linkedid)) {
00435 return;
00436 }
00437
00438
00439 ast_mutex_lock(&reload_lock);
00440
00441 if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)
00442 || !linkedids) {
00443
00444
00445
00446
00447 ast_mutex_unlock(&reload_lock);
00448 return;
00449 }
00450
00451 lid = ao2_find(linkedids, (void *) linkedid, OBJ_KEY);
00452 if (!lid) {
00453 ast_mutex_unlock(&reload_lock);
00454
00455
00456
00457
00458
00459
00460 ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
00461 return;
00462 }
00463
00464 if (!--lid->count) {
00465
00466 ao2_unlink(linkedids, lid);
00467 ast_mutex_unlock(&reload_lock);
00468
00469 ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
00470 } else {
00471 ast_mutex_unlock(&reload_lock);
00472 }
00473 ao2_ref(lid, -1);
00474 }
00475
00476
00477
00478
00479 static const struct ast_datastore_info fabricated_channel_datastore = {
00480 .type = "CEL fabricated channel",
00481 .destroy = ast_free_ptr,
00482 };
00483
00484 struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event)
00485 {
00486 struct varshead *headp;
00487 struct ast_var_t *newvariable;
00488 const char *mixed_name;
00489 char timebuf[30];
00490 struct ast_channel *tchan;
00491 struct ast_cel_event_record record = {
00492 .version = AST_CEL_EVENT_RECORD_VERSION,
00493 };
00494 struct ast_datastore *datastore;
00495 char *app_data;
00496
00497
00498 if (!(tchan = ast_dummy_channel_alloc())) {
00499 return NULL;
00500 }
00501
00502 headp = ast_channel_varshead(tchan);
00503
00504
00505 if (ast_cel_fill_record(event, &record)) {
00506 ast_channel_unref(tchan);
00507 return NULL;
00508 }
00509
00510
00511 mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
00512 ? record.user_defined_name : record.event_name;
00513 if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
00514 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00515 }
00516
00517 if (ast_strlen_zero(cel_dateformat)) {
00518 snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
00519 (long) record.event_time.tv_usec);
00520 } else {
00521 struct ast_tm tm;
00522 ast_localtime(&record.event_time, &tm, NULL);
00523 ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
00524 }
00525
00526 if ((newvariable = ast_var_assign("eventtime", timebuf))) {
00527 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00528 }
00529
00530 if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
00531 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00532 }
00533 if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
00534 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00535 }
00536 if ((newvariable = ast_var_assign("eventextra", record.extra))) {
00537 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00538 }
00539
00540 ast_channel_caller(tchan)->id.name.valid = 1;
00541 ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name);
00542 ast_channel_caller(tchan)->id.number.valid = 1;
00543 ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num);
00544 ast_channel_caller(tchan)->ani.number.valid = 1;
00545 ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani);
00546 ast_channel_redirecting(tchan)->from.number.valid = 1;
00547 ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis);
00548 ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid);
00549
00550 ast_channel_exten_set(tchan, record.extension);
00551 ast_channel_context_set(tchan, record.context);
00552 ast_channel_name_set(tchan, record.channel_name);
00553 ast_channel_uniqueid_set(tchan, record.unique_id);
00554 ast_channel_linkedid_set(tchan, record.linked_id);
00555 ast_channel_accountcode_set(tchan, record.account_code);
00556 ast_channel_peeraccount_set(tchan, record.peer_account);
00557 ast_channel_userfield_set(tchan, record.user_field);
00558
00559 if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
00560 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00561 }
00562
00563 ast_channel_amaflags_set(tchan, record.amaflag);
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
00581 ast_channel_unref(tchan);
00582 return NULL;
00583 }
00584
00585 if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
00586 ast_datastore_free(datastore);
00587 ast_channel_unref(tchan);
00588 return NULL;
00589 }
00590
00591 ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
00592 ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
00593 record.application_data));
00594
00595 datastore->data = app_data;
00596 ast_channel_datastore_add(tchan, datastore);
00597
00598 return tchan;
00599 }
00600
00601 int ast_cel_linkedid_ref(const char *linkedid)
00602 {
00603 struct cel_linkedid *lid;
00604
00605 if (ast_strlen_zero(linkedid)) {
00606 ast_log(LOG_ERROR, "The linkedid should never be empty\n");
00607 return -1;
00608 }
00609
00610
00611 ast_mutex_lock(&reload_lock);
00612
00613 if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
00614
00615 ast_mutex_unlock(&reload_lock);
00616 return 0;
00617 }
00618 if (!linkedids) {
00619
00620 ast_mutex_unlock(&reload_lock);
00621 return -1;
00622 }
00623
00624 lid = ao2_find(linkedids, (void *) linkedid, OBJ_KEY);
00625 if (!lid) {
00626
00627
00628
00629
00630 lid = ao2_alloc_options(sizeof(*lid) + strlen(linkedid) + 1, NULL,
00631 AO2_ALLOC_OPT_LOCK_NOLOCK);
00632 if (!lid) {
00633 ast_mutex_unlock(&reload_lock);
00634 return -1;
00635 }
00636 strcpy(lid->id, linkedid);
00637
00638 ao2_link(linkedids, lid);
00639 }
00640 ++lid->count;
00641 ast_mutex_unlock(&reload_lock);
00642 ao2_ref(lid, -1);
00643
00644 return 0;
00645 }
00646
00647 int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
00648 const char *userdefevname, const char *extra, struct ast_channel *peer2)
00649 {
00650 struct timeval eventtime;
00651 struct ast_event *ev;
00652 const char *peername = "";
00653 struct ast_channel *peer;
00654 char *linkedid = ast_strdupa(ast_channel_linkedid(chan));
00655
00656
00657
00658
00659 ast_mutex_lock(&reload_lock);
00660
00661 if (!appset) {
00662
00663 ast_mutex_unlock(&reload_lock);
00664 return -1;
00665 }
00666
00667
00668
00669 if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
00670 if (ast_cel_linkedid_ref(linkedid)) {
00671 ast_mutex_unlock(&reload_lock);
00672 return -1;
00673 }
00674 }
00675
00676 if (!cel_enabled || !ast_cel_track_event(event_type)) {
00677 ast_mutex_unlock(&reload_lock);
00678 return 0;
00679 }
00680
00681 if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
00682 char *app;
00683 if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
00684 ast_mutex_unlock(&reload_lock);
00685 return 0;
00686 }
00687 ao2_ref(app, -1);
00688 }
00689
00690 ast_mutex_unlock(&reload_lock);
00691
00692 ast_channel_lock(chan);
00693 peer = ast_bridged_channel(chan);
00694 if (peer) {
00695 ast_channel_ref(peer);
00696 }
00697 ast_channel_unlock(chan);
00698
00699 if (peer) {
00700 ast_channel_lock(peer);
00701 peername = ast_strdupa(ast_channel_name(peer));
00702 ast_channel_unlock(peer);
00703 } else if (peer2) {
00704 ast_channel_lock(peer2);
00705 peername = ast_strdupa(ast_channel_name(peer2));
00706 ast_channel_unlock(peer2);
00707 }
00708
00709 if (!userdefevname) {
00710 userdefevname = "";
00711 }
00712
00713 if (!extra) {
00714 extra = "";
00715 }
00716
00717 eventtime = ast_tvnow();
00718
00719 ast_channel_lock(chan);
00720
00721 ev = ast_event_new(AST_EVENT_CEL,
00722 AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
00723 AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
00724 AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
00725 AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
00726 AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
00727 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
00728 AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
00729 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
00730 AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
00731 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
00732 AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
00733 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
00734 AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
00735 S_OR(ast_channel_dialed(chan)->number.str, ""),
00736 AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
00737 AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
00738 AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
00739 AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
00740 AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
00741 AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
00742 AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
00743 AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
00744 AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
00745 AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
00746 AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
00747 AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
00748 AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
00749 AST_EVENT_IE_END);
00750
00751 ast_channel_unlock(chan);
00752
00753 if (peer) {
00754 peer = ast_channel_unref(peer);
00755 }
00756
00757 if (ev && ast_event_queue(ev)) {
00758 ast_event_destroy(ev);
00759 return -1;
00760 }
00761
00762 return 0;
00763 }
00764
00765 int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
00766 {
00767 if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
00768 ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
00769 "Please ensure all modules were compiled for "
00770 "this version of Asterisk.\n");
00771 return -1;
00772 }
00773
00774 r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
00775
00776 r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
00777 r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
00778
00779 r->event_name = ast_cel_get_type_name(r->event_type);
00780 if (r->event_type == AST_CEL_USER_DEFINED) {
00781 r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
00782 } else {
00783 r->user_defined_name = "";
00784 }
00785
00786 r->caller_id_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
00787 r->caller_id_num = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
00788 r->caller_id_ani = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
00789 r->caller_id_rdnis = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
00790 r->caller_id_dnid = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
00791 r->extension = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
00792 r->context = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
00793 r->channel_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
00794 r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
00795 r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
00796 r->account_code = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00797 r->peer_account = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00798 r->unique_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
00799 r->linked_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
00800 r->amaflag = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
00801 r->user_field = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
00802 r->peer = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
00803 r->extra = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
00804
00805 return 0;
00806 }
00807
00808 static int app_hash(const void *obj, const int flags)
00809 {
00810 return ast_str_case_hash((const char *) obj);
00811 }
00812
00813 static int app_cmp(void *obj, void *arg, int flags)
00814 {
00815 const char *app1 = obj;
00816 const char *app2 = arg;
00817
00818 return !strcasecmp(app1, app2) ? CMP_MATCH : 0;
00819 }
00820
00821 static int lid_hash(const void *obj, const int flags)
00822 {
00823 const struct cel_linkedid *lid = obj;
00824 const char *key = obj;
00825
00826 switch (flags & (OBJ_POINTER | OBJ_KEY)) {
00827 case OBJ_POINTER:
00828 default:
00829 key = lid->id;
00830 break;
00831 case OBJ_KEY:
00832 break;
00833 }
00834
00835 return ast_str_case_hash(key);
00836 }
00837
00838 static int lid_cmp(void *obj, void *arg, int flags)
00839 {
00840 struct cel_linkedid *lid1 = obj;
00841 struct cel_linkedid *lid2 = arg;
00842 const char *key = arg;
00843
00844 switch (flags & (OBJ_POINTER | OBJ_KEY)) {
00845 case OBJ_POINTER:
00846 default:
00847 key = lid2->id;
00848 break;
00849 case OBJ_KEY:
00850 break;
00851 }
00852
00853 return !strcasecmp(lid1->id, key) ? CMP_MATCH : 0;
00854 }
00855
00856 static void ast_cel_engine_term(void)
00857 {
00858
00859 ast_mutex_lock(&reload_lock);
00860
00861 ao2_cleanup(appset);
00862 appset = NULL;
00863 ao2_cleanup(linkedids);
00864 linkedids = NULL;
00865
00866 ast_mutex_unlock(&reload_lock);
00867
00868 ast_cli_unregister(&cli_status);
00869 }
00870
00871 int ast_cel_engine_init(void)
00872 {
00873
00874
00875
00876
00877
00878 appset = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, NUM_APP_BUCKETS,
00879 app_hash, app_cmp);
00880 if (!appset) {
00881 return -1;
00882 }
00883 linkedids = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, NUM_APP_BUCKETS,
00884 lid_hash, lid_cmp);
00885 if (!linkedids) {
00886 ast_cel_engine_term();
00887 return -1;
00888 }
00889
00890 if (do_reload(0) || ast_cli_register(&cli_status)) {
00891 ast_cel_engine_term();
00892 return -1;
00893 }
00894
00895 ast_register_atexit(ast_cel_engine_term);
00896
00897 return 0;
00898 }
00899
00900 int ast_cel_engine_reload(void)
00901 {
00902 return do_reload(1);
00903 }
00904