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: 413586 $")
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 const char *id;
00105
00106 unsigned int count;
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(strlen(cur_app) + 1, NULL);
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: %u\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 = chan->linkedid;
00432 struct cel_linkedid *lid;
00433 struct cel_linkedid find_lid;
00434
00435 if (ast_strlen_zero(linkedid)) {
00436 return;
00437 }
00438
00439
00440 ast_mutex_lock(&reload_lock);
00441
00442 if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)
00443 || !linkedids) {
00444
00445
00446
00447
00448 ast_mutex_unlock(&reload_lock);
00449 return;
00450 }
00451
00452 find_lid.id = linkedid;
00453 lid = ao2_find(linkedids, &find_lid, OBJ_POINTER);
00454 if (!lid) {
00455 ast_mutex_unlock(&reload_lock);
00456
00457
00458
00459
00460
00461
00462 ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
00463 return;
00464 }
00465
00466 if (!--lid->count) {
00467
00468 ao2_unlink(linkedids, lid);
00469 ast_mutex_unlock(&reload_lock);
00470
00471 ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
00472 } else {
00473 ast_mutex_unlock(&reload_lock);
00474 }
00475 ao2_ref(lid, -1);
00476 }
00477
00478
00479
00480
00481 static const struct ast_datastore_info fabricated_channel_datastore = {
00482 .type = "CEL fabricated channel",
00483 .destroy = ast_free_ptr,
00484 };
00485
00486 struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event)
00487 {
00488 struct varshead *headp;
00489 struct ast_var_t *newvariable;
00490 char timebuf[30];
00491 struct ast_channel *tchan;
00492 struct ast_cel_event_record record = {
00493 .version = AST_CEL_EVENT_RECORD_VERSION,
00494 };
00495 struct ast_datastore *datastore;
00496 char *app_data;
00497
00498
00499 if (!(tchan = ast_dummy_channel_alloc())) {
00500 return NULL;
00501 }
00502
00503 headp = &tchan->varshead;
00504
00505
00506 if (ast_cel_fill_record(event, &record)) {
00507 ast_channel_unref(tchan);
00508 return NULL;
00509 }
00510
00511
00512 if ((newvariable = ast_var_assign("eventtype", record.event_name))) {
00513 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00514 }
00515
00516 if (ast_strlen_zero(cel_dateformat)) {
00517 snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
00518 (long) record.event_time.tv_usec);
00519 } else {
00520 struct ast_tm tm;
00521 ast_localtime(&record.event_time, &tm, NULL);
00522 ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
00523 }
00524
00525 if ((newvariable = ast_var_assign("eventtime", timebuf))) {
00526 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00527 }
00528
00529 if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
00530 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00531 }
00532 if ((newvariable = ast_var_assign("eventextra", record.extra))) {
00533 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00534 }
00535
00536 tchan->caller.id.name.valid = 1;
00537 tchan->caller.id.name.str = ast_strdup(record.caller_id_name);
00538 tchan->caller.id.number.valid = 1;
00539 tchan->caller.id.number.str = ast_strdup(record.caller_id_num);
00540 tchan->caller.ani.number.valid = 1;
00541 tchan->caller.ani.number.str = ast_strdup(record.caller_id_ani);
00542 tchan->redirecting.from.number.valid = 1;
00543 tchan->redirecting.from.number.str = ast_strdup(record.caller_id_rdnis);
00544 tchan->dialed.number.str = ast_strdup(record.caller_id_dnid);
00545
00546 ast_copy_string(tchan->exten, record.extension, sizeof(tchan->exten));
00547 ast_copy_string(tchan->context, record.context, sizeof(tchan->context));
00548 ast_string_field_set(tchan, name, record.channel_name);
00549 ast_string_field_set(tchan, uniqueid, record.unique_id);
00550 ast_string_field_set(tchan, linkedid, record.linked_id);
00551 ast_string_field_set(tchan, accountcode, record.account_code);
00552 ast_string_field_set(tchan, peeraccount, record.peer_account);
00553 ast_string_field_set(tchan, userfield, record.user_field);
00554
00555 if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
00556 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00557 }
00558
00559 tchan->amaflags = record.amaflag;
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
00577 ast_channel_unref(tchan);
00578 return NULL;
00579 }
00580
00581 if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
00582 ast_datastore_free(datastore);
00583 ast_channel_unref(tchan);
00584 return NULL;
00585 }
00586
00587 tchan->appl = strcpy(app_data, record.application_name);
00588 tchan->data = strcpy(app_data + strlen(record.application_name) + 1,
00589 record.application_data);
00590
00591 datastore->data = app_data;
00592 ast_channel_datastore_add(tchan, datastore);
00593
00594 return tchan;
00595 }
00596
00597 int ast_cel_linkedid_ref(const char *linkedid)
00598 {
00599 struct cel_linkedid *lid;
00600 struct cel_linkedid find_lid;
00601
00602 if (ast_strlen_zero(linkedid)) {
00603 ast_log(LOG_ERROR, "The linkedid should never be empty\n");
00604 return -1;
00605 }
00606
00607
00608 ast_mutex_lock(&reload_lock);
00609
00610 if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
00611
00612 ast_mutex_unlock(&reload_lock);
00613 return 0;
00614 }
00615 if (!linkedids) {
00616
00617 ast_mutex_unlock(&reload_lock);
00618 return -1;
00619 }
00620
00621 find_lid.id = linkedid;
00622 lid = ao2_find(linkedids, &find_lid, OBJ_POINTER);
00623 if (!lid) {
00624
00625
00626
00627
00628 lid = ao2_alloc(sizeof(*lid) + strlen(linkedid) + 1, NULL);
00629 if (!lid) {
00630 ast_mutex_unlock(&reload_lock);
00631 return -1;
00632 }
00633 lid->id = (char *) (lid + 1);
00634 strcpy((char *) lid->id, linkedid);
00635
00636 ao2_link(linkedids, lid);
00637 }
00638 ++lid->count;
00639 ast_mutex_unlock(&reload_lock);
00640 ao2_ref(lid, -1);
00641
00642 return 0;
00643 }
00644
00645 int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
00646 const char *userdefevname, const char *extra, struct ast_channel *peer2)
00647 {
00648 struct timeval eventtime;
00649 struct ast_event *ev;
00650 const char *peername = "";
00651 struct ast_channel *peer;
00652
00653
00654
00655
00656 ast_mutex_lock(&reload_lock);
00657
00658 if (!appset) {
00659
00660 ast_mutex_unlock(&reload_lock);
00661 return -1;
00662 }
00663
00664
00665
00666 if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && chan->linkedid) {
00667 if (ast_cel_linkedid_ref(chan->linkedid)) {
00668 ast_mutex_unlock(&reload_lock);
00669 return -1;
00670 }
00671 }
00672
00673 if (!cel_enabled || !ast_cel_track_event(event_type)) {
00674 ast_mutex_unlock(&reload_lock);
00675 return 0;
00676 }
00677
00678 if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
00679 char *app;
00680 if (!(app = ao2_find(appset, (char *) chan->appl, OBJ_POINTER))) {
00681 ast_mutex_unlock(&reload_lock);
00682 return 0;
00683 }
00684 ao2_ref(app, -1);
00685 }
00686
00687 ast_mutex_unlock(&reload_lock);
00688
00689 ast_channel_lock(chan);
00690 peer = ast_bridged_channel(chan);
00691 if (peer) {
00692 ast_channel_ref(peer);
00693 }
00694 ast_channel_unlock(chan);
00695
00696 if (peer) {
00697 ast_channel_lock(peer);
00698 peername = ast_strdupa(peer->name);
00699 ast_channel_unlock(peer);
00700 } else if (peer2) {
00701 ast_channel_lock(peer2);
00702 peername = ast_strdupa(peer2->name);
00703 ast_channel_unlock(peer2);
00704 }
00705
00706 if (!userdefevname) {
00707 userdefevname = "";
00708 }
00709
00710 if (!extra) {
00711 extra = "";
00712 }
00713
00714 eventtime = ast_tvnow();
00715
00716 ast_channel_lock(chan);
00717
00718 ev = ast_event_new(AST_EVENT_CEL,
00719 AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
00720 AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
00721 AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
00722 AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
00723 AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
00724 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""),
00725 AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
00726 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
00727 AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
00728 S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, ""),
00729 AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
00730 S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, ""),
00731 AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
00732 S_OR(chan->dialed.number.str, ""),
00733 AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, chan->exten,
00734 AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, chan->context,
00735 AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, chan->name,
00736 AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->appl, ""),
00737 AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->data, ""),
00738 AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, chan->amaflags,
00739 AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, chan->accountcode,
00740 AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, chan->peeraccount,
00741 AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, chan->uniqueid,
00742 AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, chan->linkedid,
00743 AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, chan->userfield,
00744 AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
00745 AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
00746 AST_EVENT_IE_END);
00747
00748 ast_channel_unlock(chan);
00749
00750 if (peer) {
00751 peer = ast_channel_unref(peer);
00752 }
00753
00754 if (ev && ast_event_queue(ev)) {
00755 ast_event_destroy(ev);
00756 return -1;
00757 }
00758
00759 return 0;
00760 }
00761
00762 int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
00763 {
00764 if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
00765 ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record. "
00766 "Please ensure all modules were compiled for "
00767 "this version of Asterisk.\n");
00768 return -1;
00769 }
00770
00771 r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
00772
00773 r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
00774 r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
00775
00776 r->user_defined_name = "";
00777
00778 if (r->event_type == AST_CEL_USER_DEFINED) {
00779 r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
00780 r->event_name = r->user_defined_name;
00781 } else {
00782 r->event_name = ast_cel_get_type_name(r->event_type);
00783 }
00784
00785 r->caller_id_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
00786 r->caller_id_num = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
00787 r->caller_id_ani = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
00788 r->caller_id_rdnis = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
00789 r->caller_id_dnid = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
00790 r->extension = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
00791 r->context = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
00792 r->channel_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
00793 r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
00794 r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
00795 r->account_code = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00796 r->peer_account = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00797 r->unique_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
00798 r->linked_id = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
00799 r->amaflag = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
00800 r->user_field = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
00801 r->peer = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
00802 r->extra = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
00803
00804 return 0;
00805 }
00806
00807 static int app_hash(const void *obj, const int flags)
00808 {
00809 return ast_str_case_hash((const char *) obj);
00810 }
00811
00812 static int app_cmp(void *obj, void *arg, int flags)
00813 {
00814 const char *app1 = obj;
00815 const char *app2 = arg;
00816
00817 return !strcasecmp(app1, app2) ? CMP_MATCH : 0;
00818 }
00819
00820 static int lid_hash(const void *obj, const int flags)
00821 {
00822 const struct cel_linkedid *lid = obj;
00823 const char *key;
00824
00825 key = lid->id;
00826
00827 return ast_str_case_hash(key);
00828 }
00829
00830 static int lid_cmp(void *obj, void *arg, int flags)
00831 {
00832 struct cel_linkedid *lid1 = obj;
00833 struct cel_linkedid *lid2 = arg;
00834 const char *key;
00835
00836 key = lid2->id;
00837
00838 return !strcasecmp(lid1->id, key) ? CMP_MATCH : 0;
00839 }
00840
00841 static void ast_cel_engine_term(void)
00842 {
00843
00844 ast_mutex_lock(&reload_lock);
00845
00846 if (appset) {
00847 ao2_ref(appset, -1);
00848 appset = NULL;
00849 }
00850 if (linkedids) {
00851 ao2_ref(linkedids, -1);
00852 linkedids = NULL;
00853 }
00854
00855 ast_mutex_unlock(&reload_lock);
00856
00857 ast_cli_unregister(&cli_status);
00858 }
00859
00860 int ast_cel_engine_init(void)
00861 {
00862
00863
00864
00865
00866
00867 appset = ao2_container_alloc(NUM_APP_BUCKETS, app_hash, app_cmp);
00868 if (!appset) {
00869 return -1;
00870 }
00871 linkedids = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp);
00872 if (!linkedids) {
00873 ast_cel_engine_term();
00874 return -1;
00875 }
00876
00877 if (do_reload(0) || ast_cli_register(&cli_status)) {
00878 ast_cel_engine_term();
00879 return -1;
00880 }
00881
00882 ast_register_atexit(ast_cel_engine_term);
00883
00884 return 0;
00885 }
00886
00887 int ast_cel_engine_reload(void)
00888 {
00889 return do_reload(1);
00890 }
00891