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 284 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 290 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 303 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.
00305 { 00306 int ret = 0; 00307 00308 if (!strcasecmp(data, "audionativeformat")) 00309 /* use the _multiple version when chan->nativeformats holds multiple formats */ 00310 /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_AUDIO_MASK); */ 00311 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len); 00312 else if (!strcasecmp(data, "videonativeformat")) 00313 /* use the _multiple version when chan->nativeformats holds multiple formats */ 00314 /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_VIDEO_MASK); */ 00315 ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len); 00316 else if (!strcasecmp(data, "audioreadformat")) 00317 ast_copy_string(buf, ast_getformatname(chan->readformat), len); 00318 else if (!strcasecmp(data, "audiowriteformat")) 00319 ast_copy_string(buf, ast_getformatname(chan->writeformat), len); 00320 #ifdef CHANNEL_TRACE 00321 else if (!strcasecmp(data, "trace")) { 00322 ast_channel_lock(chan); 00323 ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); 00324 ast_channel_unlock(chan); 00325 } 00326 #endif 00327 else if (!strcasecmp(data, "tonezone") && chan->zone) 00328 locked_copy_string(chan, buf, chan->zone->country, len); 00329 else if (!strcasecmp(data, "language")) 00330 locked_copy_string(chan, buf, chan->language, len); 00331 else if (!strcasecmp(data, "musicclass")) 00332 locked_copy_string(chan, buf, chan->musicclass, len); 00333 else if (!strcasecmp(data, "name")) { 00334 locked_copy_string(chan, buf, chan->name, len); 00335 } else if (!strcasecmp(data, "parkinglot")) 00336 locked_copy_string(chan, buf, chan->parkinglot, len); 00337 else if (!strcasecmp(data, "state")) 00338 locked_copy_string(chan, buf, ast_state2str(chan->_state), len); 00339 else if (!strcasecmp(data, "channeltype")) 00340 locked_copy_string(chan, buf, chan->tech->type, len); 00341 else if (!strcasecmp(data, "accountcode")) 00342 locked_copy_string(chan, buf, chan->accountcode, len); 00343 else if (!strcasecmp(data, "checkhangup")) { 00344 ast_channel_lock(chan); 00345 ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len); 00346 ast_channel_unlock(chan); 00347 } else if (!strcasecmp(data, "peeraccount")) 00348 locked_copy_string(chan, buf, chan->peeraccount, len); 00349 else if (!strcasecmp(data, "hangupsource")) 00350 locked_copy_string(chan, buf, chan->hangupsource, len); 00351 else if (!strcasecmp(data, "appname") && chan->appl) 00352 locked_copy_string(chan, buf, chan->appl, len); 00353 else if (!strcasecmp(data, "appdata") && chan->data) 00354 locked_copy_string(chan, buf, chan->data, len); 00355 else if (!strcasecmp(data, "exten") && chan->data) 00356 locked_copy_string(chan, buf, chan->exten, len); 00357 else if (!strcasecmp(data, "context") && chan->data) 00358 locked_copy_string(chan, buf, chan->context, len); 00359 else if (!strcasecmp(data, "userfield") && chan->data) 00360 locked_copy_string(chan, buf, chan->userfield, len); 00361 else if (!strcasecmp(data, "channame") && chan->data) 00362 locked_copy_string(chan, buf, chan->name, len); 00363 else if (!strcasecmp(data, "linkedid")) { 00364 ast_channel_lock(chan); 00365 if (ast_strlen_zero(chan->linkedid)) { 00366 /* fall back on the channel's uniqueid if linkedid is unset */ 00367 ast_copy_string(buf, chan->uniqueid, len); 00368 } 00369 else { 00370 ast_copy_string(buf, chan->linkedid, len); 00371 } 00372 ast_channel_unlock(chan); 00373 } else if (!strcasecmp(data, "peer")) { 00374 struct ast_channel *p; 00375 ast_channel_lock(chan); 00376 p = ast_bridged_channel(chan); 00377 if (p || chan->tech || chan->cdr) /* dummy channel? if so, we hid the peer name in the language */ 00378 ast_copy_string(buf, (p ? p->name : ""), len); 00379 else { 00380 /* a dummy channel can still pass along bridged peer info via 00381 the BRIDGEPEER variable */ 00382 const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); 00383 if (!ast_strlen_zero(pname)) 00384 ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */ 00385 else 00386 buf[0] = 0; 00387 } 00388 ast_channel_unlock(chan); 00389 } else if (!strcasecmp(data, "uniqueid")) { 00390 locked_copy_string(chan, buf, chan->uniqueid, len); 00391 } else if (!strcasecmp(data, "transfercapability")) 00392 locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len); 00393 else if (!strcasecmp(data, "callgroup")) { 00394 char groupbuf[256]; 00395 locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len); 00396 } else if (!strcasecmp(data, "amaflags")) { 00397 char amabuf[256]; 00398 snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags); 00399 locked_copy_string(chan, buf, amabuf, len); 00400 } else if (!strncasecmp(data, "secure_bridge_", 14)) { 00401 struct ast_datastore *ds; 00402 ast_channel_lock(chan); 00403 if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { 00404 struct ast_secure_call_store *encrypt = ds->data; 00405 if (!strcasecmp(data, "secure_bridge_signaling")) { 00406 snprintf(buf, len, "%s", encrypt->signaling ? "1" : ""); 00407 } else if (!strcasecmp(data, "secure_bridge_media")) { 00408 snprintf(buf, len, "%s", encrypt->media ? "1" : ""); 00409 } 00410 } 00411 ast_channel_unlock(chan); 00412 } else if (!chan->tech || !chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) { 00413 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); 00414 ret = -1; 00415 } 00416 00417 return ret; 00418 }
static int func_channel_write | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 538 of file func_channel.c.
References AST_CHAN_WRITE_INFO_T_VERSION, ast_channel_setoption(), AST_OPTION_CHANNEL_WRITE, ast_channel::data, and func_channel_write_real().
00539 { 00540 int res; 00541 ast_chan_write_info_t write_info = { 00542 .version = AST_CHAN_WRITE_INFO_T_VERSION, 00543 .write_fn = func_channel_write_real, 00544 .chan = chan, 00545 .function = function, 00546 .data = data, 00547 .value = value, 00548 }; 00549 00550 res = func_channel_write_real(chan, function, data, value); 00551 ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0); 00552 00553 return res; 00554 }
static int func_channel_write_real | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 420 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().
00422 { 00423 int ret = 0; 00424 signed char gainset; 00425 00426 if (!strcasecmp(data, "language")) 00427 locked_string_field_set(chan, language, value); 00428 else if (!strcasecmp(data, "parkinglot")) 00429 locked_string_field_set(chan, parkinglot, value); 00430 else if (!strcasecmp(data, "musicclass")) 00431 locked_string_field_set(chan, musicclass, value); 00432 else if (!strcasecmp(data, "accountcode")) 00433 locked_string_field_set(chan, accountcode, value); 00434 else if (!strcasecmp(data, "userfield")) 00435 locked_string_field_set(chan, userfield, value); 00436 else if (!strcasecmp(data, "amaflags")) { 00437 ast_channel_lock(chan); 00438 if(isdigit(*value)) { 00439 sscanf(value, "%30d", &chan->amaflags); 00440 } else if (!strcasecmp(value,"OMIT")){ 00441 chan->amaflags = 1; 00442 } else if (!strcasecmp(value,"BILLING")){ 00443 chan->amaflags = 2; 00444 } else if (!strcasecmp(value,"DOCUMENTATION")){ 00445 chan->amaflags = 3; 00446 } 00447 ast_channel_unlock(chan); 00448 } else if (!strcasecmp(data, "peeraccount")) 00449 locked_string_field_set(chan, peeraccount, value); 00450 else if (!strcasecmp(data, "hangupsource")) 00451 /* XXX - should we be forcing this here? */ 00452 ast_set_hangupsource(chan, value, 0); 00453 #ifdef CHANNEL_TRACE 00454 else if (!strcasecmp(data, "trace")) { 00455 ast_channel_lock(chan); 00456 if (ast_true(value)) 00457 ret = ast_channel_trace_enable(chan); 00458 else if (ast_false(value)) 00459 ret = ast_channel_trace_disable(chan); 00460 else { 00461 ret = -1; 00462 ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).\n"); 00463 } 00464 ast_channel_unlock(chan); 00465 } 00466 #endif 00467 else if (!strcasecmp(data, "tonezone")) { 00468 struct ast_tone_zone *new_zone; 00469 if (!(new_zone = ast_get_indication_zone(value))) { 00470 ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value); 00471 ret = -1; 00472 } else { 00473 ast_channel_lock(chan); 00474 if (chan->zone) { 00475 chan->zone = ast_tone_zone_unref(chan->zone); 00476 } 00477 chan->zone = ast_tone_zone_ref(new_zone); 00478 ast_channel_unlock(chan); 00479 new_zone = ast_tone_zone_unref(new_zone); 00480 } 00481 } else if (!strcasecmp(data, "callgroup")) 00482 chan->callgroup = ast_get_group(value); 00483 else if (!strcasecmp(data, "txgain")) { 00484 sscanf(value, "%4hhd", &gainset); 00485 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0); 00486 } else if (!strcasecmp(data, "rxgain")) { 00487 sscanf(value, "%4hhd", &gainset); 00488 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0); 00489 } else if (!strcasecmp(data, "transfercapability")) { 00490 unsigned short i; 00491 for (i = 0; i < 0x20; i++) { 00492 if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) { 00493 chan->transfercapability = i; 00494 break; 00495 } 00496 } 00497 } else if (!strncasecmp(data, "secure_bridge_", 14)) { 00498 struct ast_datastore *ds; 00499 struct ast_secure_call_store *store; 00500 00501 if (!chan || !value) { 00502 return -1; 00503 } 00504 00505 ast_channel_lock(chan); 00506 if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { 00507 if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) { 00508 ast_channel_unlock(chan); 00509 return -1; 00510 } 00511 if (!(store = ast_calloc(1, sizeof(*store)))) { 00512 ast_channel_unlock(chan); 00513 ast_free(ds); 00514 return -1; 00515 } 00516 ds->data = store; 00517 ast_channel_datastore_add(chan, ds); 00518 } else { 00519 store = ds->data; 00520 } 00521 ast_channel_unlock(chan); 00522 00523 if (!strcasecmp(data, "secure_bridge_signaling")) { 00524 store->signaling = ast_true(value) ? 1 : 0; 00525 } else if (!strcasecmp(data, "secure_bridge_media")) { 00526 store->media = ast_true(value) ? 1 : 0; 00527 } 00528 } else if (!chan->tech->func_channel_write 00529 || chan->tech->func_channel_write(chan, function, data, value)) { 00530 ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", 00531 data); 00532 ret = -1; 00533 } 00534 00535 return ret; 00536 }
static int func_channels_read | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
char * | buf, | |||
size_t | maxlen | |||
) | [static] |
Definition at line 562 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.
00563 { 00564 struct ast_channel *c = NULL; 00565 regex_t re; 00566 int res; 00567 size_t buflen = 0; 00568 struct ast_channel_iterator *iter; 00569 00570 buf[0] = '\0'; 00571 00572 if (!ast_strlen_zero(data)) { 00573 if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) { 00574 regerror(res, &re, buf, maxlen); 00575 ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf); 00576 return -1; 00577 } 00578 } 00579 00580 if (!(iter = ast_channel_iterator_all_new())) { 00581 if (!ast_strlen_zero(data)) { 00582 regfree(&re); 00583 } 00584 return -1; 00585 } 00586 00587 while ((c = ast_channel_iterator_next(iter))) { 00588 ast_channel_lock(c); 00589 if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) { 00590 size_t namelen = strlen(c->name); 00591 if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) { 00592 if (!ast_strlen_zero(buf)) { 00593 strcat(buf, " "); 00594 buflen++; 00595 } 00596 strcat(buf, c->name); 00597 buflen += namelen; 00598 } else { 00599 ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n"); 00600 } 00601 } 00602 ast_channel_unlock(c); 00603 c = ast_channel_unref(c); 00604 } 00605 00606 ast_channel_iterator_destroy(iter); 00607 00608 if (!ast_strlen_zero(data)) { 00609 regfree(&re); 00610 } 00611 00612 return 0; 00613 }
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 620 of file func_channel.c.
References ast_alloca, ast_channel_get_by_name(), ast_channel_unref, and ast_str_substitute_variables().
00622 { 00623 struct ast_channel *mchan = ast_channel_get_by_name(chan->linkedid); 00624 char *template = ast_alloca(4 + strlen(data)); 00625 sprintf(template, "${%s}", data); /* SAFE */ 00626 ast_str_substitute_variables(buf, len, mchan ? mchan : chan, template); 00627 if (mchan) { 00628 ast_channel_unref(mchan); 00629 } 00630 return 0; 00631 }
static int func_mchan_write | ( | struct ast_channel * | chan, | |
const char * | function, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Definition at line 633 of file func_channel.c.
References ast_channel_get_by_name(), ast_channel_unref, and pbx_builtin_setvar_helper().
00635 { 00636 struct ast_channel *mchan = ast_channel_get_by_name(chan->linkedid); 00637 pbx_builtin_setvar_helper(mchan ? mchan : chan, data, value); 00638 if (mchan) { 00639 ast_channel_unref(mchan); 00640 } 00641 return 0; 00642 }
static int load_module | ( | void | ) | [static] |
Definition at line 661 of file func_channel.c.
References ast_custom_function_register.
00662 { 00663 int res = 0; 00664 00665 res |= ast_custom_function_register(&channel_function); 00666 res |= ast_custom_function_register(&channels_function); 00667 res |= ast_custom_function_register(&mchan_function); 00668 00669 return res; 00670 }
static int unload_module | ( | void | ) | [static] |
Definition at line 650 of file func_channel.c.
References ast_custom_function_unregister().
00651 { 00652 int res = 0; 00653 00654 res |= ast_custom_function_unregister(&channel_function); 00655 res |= ast_custom_function_unregister(&channels_function); 00656 res |= ast_custom_function_unregister(&mchan_function); 00657 00658 return res; 00659 }
struct ast_custom_function channel_function [static] |
{ .name = "CHANNEL", .read = func_channel_read, .write = func_channel_write, }
Definition at line 556 of file func_channel.c.
struct ast_custom_function channels_function [static] |
{ .name = "CHANNELS", .read = func_channels_read, }
Definition at line 615 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 644 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 297 of file func_channel.c.