Channel info dialplan functions. More...
#include "asterisk.h"
#include <regex.h>
#include <ctype.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/indications.h"
#include "asterisk/stringfields.h"
#include "asterisk/global_datastores.h"
Go to the source code of this file.
Defines | |
#define | locked_copy_string(chan, dest, source, len) |
#define | locked_string_field_set(chan, field, source) |
Functions | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Channel information dialplan functions") | |
static int | func_channel_read (struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) |
static int | func_channel_write (struct ast_channel *chan, const char *function, char *data, const char *value) |
static int | func_channel_write_real (struct ast_channel *chan, const char *function, char *data, const char *value) |
static int | func_channels_read (struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen) |
static int | func_mchan_read (struct ast_channel *chan, const char *function, char *data, struct ast_str **buf, ssize_t len) |
static int | func_mchan_write (struct ast_channel *chan, const char *function, char *data, const char *value) |
static int | load_module (void) |
static int | unload_module (void) |
Variables | |
static struct ast_custom_function | channel_function |
static struct ast_custom_function | channels_function |
static struct ast_custom_function | mchan_function |
static const char *const | transfercapability_table [0x20] |
Channel info dialplan functions.
Definition in file func_channel.c.
#define locked_copy_string | ( | chan, | |||
dest, | |||||
source, | |||||
len | ) |
do { \ ast_channel_lock(chan); \ ast_copy_string(dest, source, len); \ ast_channel_unlock(chan); \ } while (0)
Definition at line 317 of file func_channel.c.
Referenced by func_channel_read().
#define locked_string_field_set | ( | chan, | |||
field, | |||||
source | ) |
do { \ ast_channel_lock(chan); \ ast_string_field_set(chan, field, source); \ ast_channel_unlock(chan); \ } while (0)
Definition at line 323 of file func_channel.c.
Referenced by func_channel_write_real().
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Channel information dialplan functions" | ||||
) |
static int func_channel_read | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 336 of file func_channel.c.
References ast_channel::_state, ast_channel::amaflags, ast_channel::appl, ast_bridged_channel(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, ast_getformatname(), ast_log(), ast_print_group(), ast_state2str(), ast_strlen_zero(), ast_channel::callgroup, ast_channel::cdr, ast_channel::context, ast_tone_zone::country, ast_datastore::data, ast_channel::data, ast_channel::exten, ast_channel_tech::func_channel_read, locked_copy_string, LOG_WARNING, ast_secure_call_store::media, ast_channel::nativeformats, pbx_builtin_getvar_helper(), ast_channel::readformat, secure_call_info, ast_secure_call_store::signaling, ast_channel::tech, ast_channel::transfercapability, ast_channel_tech::type, ast_channel::writeformat, and ast_channel::zone.
00338 { 00339 int ret = 0; 00340 00341 if (!chan) { 00342 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function); 00343 return -1; 00344 } 00345 00346 if (!strcasecmp(data, "audionativeformat")) 00347 /* use the _multiple version when chan->nativeformats holds multiple formats */ 00348 /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_AUDIO_MASK); */ 00349 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len); 00350 else if (!strcasecmp(data, "videonativeformat")) 00351 /* use the _multiple version when chan->nativeformats holds multiple formats */ 00352 /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_VIDEO_MASK); */ 00353 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len); 00354 else if (!strcasecmp(data, "audioreadformat")) 00355 ast_copy_string(buf, ast_getformatname(chan->readformat), len); 00356 else if (!strcasecmp(data, "audiowriteformat")) 00357 ast_copy_string(buf, ast_getformatname(chan->writeformat), len); 00358 #ifdef CHANNEL_TRACE 00359 else if (!strcasecmp(data, "trace")) { 00360 ast_channel_lock(chan); 00361 ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); 00362 ast_channel_unlock(chan); 00363 } 00364 #endif 00365 else if (!strcasecmp(data, "tonezone") && chan->zone) 00366 locked_copy_string(chan, buf, chan->zone->country, len); 00367 else if (!strcasecmp(data, "language")) 00368 locked_copy_string(chan, buf, chan->language, len); 00369 else if (!strcasecmp(data, "musicclass")) 00370 locked_copy_string(chan, buf, chan->musicclass, len); 00371 else if (!strcasecmp(data, "name")) { 00372 locked_copy_string(chan, buf, chan->name, len); 00373 } else if (!strcasecmp(data, "parkinglot")) 00374 locked_copy_string(chan, buf, chan->parkinglot, len); 00375 else if (!strcasecmp(data, "state")) 00376 locked_copy_string(chan, buf, ast_state2str(chan->_state), len); 00377 else if (!strcasecmp(data, "channeltype")) 00378 locked_copy_string(chan, buf, chan->tech->type, len); 00379 else if (!strcasecmp(data, "accountcode")) 00380 locked_copy_string(chan, buf, chan->accountcode, len); 00381 else if (!strcasecmp(data, "checkhangup")) { 00382 ast_channel_lock(chan); 00383 ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len); 00384 ast_channel_unlock(chan); 00385 } else if (!strcasecmp(data, "peeraccount")) 00386 locked_copy_string(chan, buf, chan->peeraccount, len); 00387 else if (!strcasecmp(data, "hangupsource")) 00388 locked_copy_string(chan, buf, chan->hangupsource, len); 00389 else if (!strcasecmp(data, "appname") && chan->appl) 00390 locked_copy_string(chan, buf, chan->appl, len); 00391 else if (!strcasecmp(data, "appdata") && chan->data) 00392 locked_copy_string(chan, buf, chan->data, len); 00393 else if (!strcasecmp(data, "exten") && chan->data) 00394 locked_copy_string(chan, buf, chan->exten, len); 00395 else if (!strcasecmp(data, "context") && chan->data) 00396 locked_copy_string(chan, buf, chan->context, len); 00397 else if (!strcasecmp(data, "userfield") && chan->data) 00398 locked_copy_string(chan, buf, chan->userfield, len); 00399 else if (!strcasecmp(data, "channame") && chan->data) 00400 locked_copy_string(chan, buf, chan->name, len); 00401 else if (!strcasecmp(data, "linkedid")) { 00402 ast_channel_lock(chan); 00403 if (ast_strlen_zero(chan->linkedid)) { 00404 /* fall back on the channel's uniqueid if linkedid is unset */ 00405 ast_copy_string(buf, chan->uniqueid, len); 00406 } 00407 else { 00408 ast_copy_string(buf, chan->linkedid, len); 00409 } 00410 ast_channel_unlock(chan); 00411 } else if (!strcasecmp(data, "peer")) { 00412 struct ast_channel *p; 00413 ast_channel_lock(chan); 00414 p = ast_bridged_channel(chan); 00415 if (p || chan->tech || chan->cdr) /* dummy channel? if so, we hid the peer name in the language */ 00416 ast_copy_string(buf, (p ? p->name : ""), len); 00417 else { 00418 /* a dummy channel can still pass along bridged peer info via 00419 the BRIDGEPEER variable */ 00420 const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); 00421 if (!ast_strlen_zero(pname)) 00422 ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */ 00423 else 00424 buf[0] = 0; 00425 } 00426 ast_channel_unlock(chan); 00427 } else if (!strcasecmp(data, "uniqueid")) { 00428 locked_copy_string(chan, buf, chan->uniqueid, len); 00429 } else if (!strcasecmp(data, "transfercapability")) 00430 locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len); 00431 else if (!strcasecmp(data, "callgroup")) { 00432 char groupbuf[256]; 00433 locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len); 00434 } else if (!strcasecmp(data, "amaflags")) { 00435 char amabuf[256]; 00436 snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags); 00437 locked_copy_string(chan, buf, amabuf, len); 00438 } else if (!strncasecmp(data, "secure_bridge_", 14)) { 00439 struct ast_datastore *ds; 00440 ast_channel_lock(chan); 00441 if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { 00442 struct ast_secure_call_store *encrypt = ds->data; 00443 if (!strcasecmp(data, "secure_bridge_signaling")) { 00444 snprintf(buf, len, "%s", encrypt->signaling ? "1" : ""); 00445 } else if (!strcasecmp(data, "secure_bridge_media")) { 00446 snprintf(buf, len, "%s", encrypt->media ? "1" : ""); 00447 } 00448 } 00449 ast_channel_unlock(chan); 00450 } else if (!chan->tech || !chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) { 00451 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); 00452 ret = -1; 00453 } 00454 00455 return ret; 00456 }
static int func_channel_write | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 576 of file func_channel.c.
References AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_setoption(), ast_log(), AST_OPTION_CHANNEL_WRITE, ast_channel::data, func_channel_write_real(), and LOG_WARNING.
00577 { 00578 int res; 00579 ast_chan_write_info_t write_info = { 00580 .version = AST_CHAN_WRITE_INFO_T_VERSION, 00581 .write_fn = func_channel_write_real, 00582 .chan = chan, 00583 .function = function, 00584 .data = data, 00585 .value = value, 00586 }; 00587 00588 if (!chan) { 00589 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function); 00590 return -1; 00591 } 00592 00593 res = func_channel_write_real(chan, function, data, value); 00594 ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0); 00595 00596 return res; 00597 }
static int func_channel_write_real | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 458 of file func_channel.c.
References accountcode, ast_channel::amaflags, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_datastore_alloc, ast_false(), ast_free, ast_get_group(), ast_get_indication_zone(), ast_log(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, ast_set_hangupsource(), ast_tone_zone_ref(), ast_tone_zone_unref(), ast_true(), ast_channel::callgroup, ast_datastore::data, ast_channel_tech::func_channel_write, language, locked_string_field_set, LOG_ERROR, LOG_WARNING, ast_secure_call_store::media, musicclass, parkinglot, secure_call_info, ast_secure_call_store::signaling, ast_channel::tech, ast_channel::transfercapability, and ast_channel::zone.
Referenced by func_channel_write().
00460 { 00461 int ret = 0; 00462 signed char gainset; 00463 00464 if (!strcasecmp(data, "language")) 00465 locked_string_field_set(chan, language, value); 00466 else if (!strcasecmp(data, "parkinglot")) 00467 locked_string_field_set(chan, parkinglot, value); 00468 else if (!strcasecmp(data, "musicclass")) 00469 locked_string_field_set(chan, musicclass, value); 00470 else if (!strcasecmp(data, "accountcode")) 00471 locked_string_field_set(chan, accountcode, value); 00472 else if (!strcasecmp(data, "userfield")) 00473 locked_string_field_set(chan, userfield, value); 00474 else if (!strcasecmp(data, "amaflags")) { 00475 ast_channel_lock(chan); 00476 if(isdigit(*value)) { 00477 sscanf(value, "%30d", &chan->amaflags); 00478 } else if (!strcasecmp(value,"OMIT")){ 00479 chan->amaflags = 1; 00480 } else if (!strcasecmp(value,"BILLING")){ 00481 chan->amaflags = 2; 00482 } else if (!strcasecmp(value,"DOCUMENTATION")){ 00483 chan->amaflags = 3; 00484 } 00485 ast_channel_unlock(chan); 00486 } else if (!strcasecmp(data, "peeraccount")) 00487 locked_string_field_set(chan, peeraccount, value); 00488 else if (!strcasecmp(data, "hangupsource")) 00489 /* XXX - should we be forcing this here? */ 00490 ast_set_hangupsource(chan, value, 0); 00491 #ifdef CHANNEL_TRACE 00492 else if (!strcasecmp(data, "trace")) { 00493 ast_channel_lock(chan); 00494 if (ast_true(value)) 00495 ret = ast_channel_trace_enable(chan); 00496 else if (ast_false(value)) 00497 ret = ast_channel_trace_disable(chan); 00498 else { 00499 ret = -1; 00500 ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).\n"); 00501 } 00502 ast_channel_unlock(chan); 00503 } 00504 #endif 00505 else if (!strcasecmp(data, "tonezone")) { 00506 struct ast_tone_zone *new_zone; 00507 if (!(new_zone = ast_get_indication_zone(value))) { 00508 ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value); 00509 ret = -1; 00510 } else { 00511 ast_channel_lock(chan); 00512 if (chan->zone) { 00513 chan->zone = ast_tone_zone_unref(chan->zone); 00514 } 00515 chan->zone = ast_tone_zone_ref(new_zone); 00516 ast_channel_unlock(chan); 00517 new_zone = ast_tone_zone_unref(new_zone); 00518 } 00519 } else if (!strcasecmp(data, "callgroup")) 00520 chan->callgroup = ast_get_group(value); 00521 else if (!strcasecmp(data, "txgain")) { 00522 sscanf(value, "%4hhd", &gainset); 00523 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0); 00524 } else if (!strcasecmp(data, "rxgain")) { 00525 sscanf(value, "%4hhd", &gainset); 00526 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0); 00527 } else if (!strcasecmp(data, "transfercapability")) { 00528 unsigned short i; 00529 for (i = 0; i < 0x20; i++) { 00530 if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) { 00531 chan->transfercapability = i; 00532 break; 00533 } 00534 } 00535 } else if (!strncasecmp(data, "secure_bridge_", 14)) { 00536 struct ast_datastore *ds; 00537 struct ast_secure_call_store *store; 00538 00539 if (!chan || !value) { 00540 return -1; 00541 } 00542 00543 ast_channel_lock(chan); 00544 if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { 00545 if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) { 00546 ast_channel_unlock(chan); 00547 return -1; 00548 } 00549 if (!(store = ast_calloc(1, sizeof(*store)))) { 00550 ast_channel_unlock(chan); 00551 ast_free(ds); 00552 return -1; 00553 } 00554 ds->data = store; 00555 ast_channel_datastore_add(chan, ds); 00556 } else { 00557 store = ds->data; 00558 } 00559 ast_channel_unlock(chan); 00560 00561 if (!strcasecmp(data, "secure_bridge_signaling")) { 00562 store->signaling = ast_true(value) ? 1 : 0; 00563 } else if (!strcasecmp(data, "secure_bridge_media")) { 00564 store->media = ast_true(value) ? 1 : 0; 00565 } 00566 } else if (!chan->tech->func_channel_write 00567 || chan->tech->func_channel_write(chan, function, data, value)) { 00568 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", 00569 data); 00570 ret = -1; 00571 } 00572 00573 return ret; 00574 }
static int func_channels_read | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
char * | buf, | |||
size_t | maxlen | |||
) | [static] |
Definition at line 605 of file func_channel.c.
References ast_channel_iterator_all_new(), ast_channel_iterator_destroy(), ast_channel_iterator_next(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_log(), ast_strlen_zero(), and LOG_WARNING.
00606 { 00607 struct ast_channel *c = NULL; 00608 regex_t re; 00609 int res; 00610 size_t buflen = 0; 00611 struct ast_channel_iterator *iter; 00612 00613 buf[0] = '\0'; 00614 00615 if (!ast_strlen_zero(data)) { 00616 if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) { 00617 regerror(res, &re, buf, maxlen); 00618 ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf); 00619 return -1; 00620 } 00621 } 00622 00623 if (!(iter = ast_channel_iterator_all_new())) { 00624 if (!ast_strlen_zero(data)) { 00625 regfree(&re); 00626 } 00627 return -1; 00628 } 00629 00630 while ((c = ast_channel_iterator_next(iter))) { 00631 ast_channel_lock(c); 00632 if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) { 00633 size_t namelen = strlen(c->name); 00634 if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) { 00635 if (!ast_strlen_zero(buf)) { 00636 strcat(buf, " "); 00637 buflen++; 00638 } 00639 strcat(buf, c->name); 00640 buflen += namelen; 00641 } else { 00642 ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n"); 00643 } 00644 } 00645 ast_channel_unlock(c); 00646 c = ast_channel_unref(c); 00647 } 00648 00649 ast_channel_iterator_destroy(iter); 00650 00651 if (!ast_strlen_zero(data)) { 00652 regfree(&re); 00653 } 00654 00655 return 0; 00656 }
static int func_mchan_read | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
struct ast_str ** | buf, | |||
ssize_t | len | |||
) | [static] |
Definition at line 663 of file func_channel.c.
References ast_alloca, ast_channel_get_by_name(), ast_channel_unref, ast_log(), ast_str_substitute_variables(), and LOG_WARNING.
00665 { 00666 struct ast_channel *mchan; 00667 char *template = ast_alloca(4 + strlen(data)); 00668 00669 if (!chan) { 00670 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function); 00671 return -1; 00672 } 00673 00674 mchan = ast_channel_get_by_name(chan->linkedid); 00675 sprintf(template, "${%s}", data); /* SAFE */ 00676 ast_str_substitute_variables(buf, len, mchan ? mchan : chan, template); 00677 if (mchan) { 00678 ast_channel_unref(mchan); 00679 } 00680 return 0; 00681 }
static int func_mchan_write | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 683 of file func_channel.c.
References ast_channel_get_by_name(), ast_channel_unref, ast_log(), LOG_WARNING, and pbx_builtin_setvar_helper().
00685 { 00686 struct ast_channel *mchan; 00687 00688 if (!chan) { 00689 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function); 00690 return -1; 00691 } 00692 00693 mchan = ast_channel_get_by_name(chan->linkedid); 00694 pbx_builtin_setvar_helper(mchan ? mchan : chan, data, value); 00695 if (mchan) { 00696 ast_channel_unref(mchan); 00697 } 00698 return 0; 00699 }
static int load_module | ( | void | ) | [static] |
Definition at line 718 of file func_channel.c.
References ast_custom_function_register.
00719 { 00720 int res = 0; 00721 00722 res |= ast_custom_function_register(&channel_function); 00723 res |= ast_custom_function_register(&channels_function); 00724 res |= ast_custom_function_register(&mchan_function); 00725 00726 return res; 00727 }
static int unload_module | ( | void | ) | [static] |
Definition at line 707 of file func_channel.c.
References ast_custom_function_unregister().
00708 { 00709 int res = 0; 00710 00711 res |= ast_custom_function_unregister(&channel_function); 00712 res |= ast_custom_function_unregister(&channels_function); 00713 res |= ast_custom_function_unregister(&mchan_function); 00714 00715 return res; 00716 }
struct ast_custom_function channel_function [static] |
{ .name = "CHANNEL", .read = func_channel_read, .write = func_channel_write, }
Definition at line 599 of file func_channel.c.
struct ast_custom_function channels_function [static] |
{ .name = "CHANNELS", .read = func_channels_read, }
Definition at line 658 of file func_channel.c.
struct ast_custom_function mchan_function [static] |
{ .name = "MASTER_CHANNEL", .read2 = func_mchan_read, .write = func_mchan_write, }
Definition at line 701 of file func_channel.c.
const char* const transfercapability_table[0x20] [static] |
{ "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "VIDEO", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", }
Definition at line 330 of file func_channel.c.