37 #if defined(HAVE_SYSINFO)
38 #include <sys/sysinfo.h>
41 #include <sys/loadavg.h>
71 #include "asterisk/stasis_channels.h"
214 #define EXT_DATA_SIZE 256
216 #define EXT_DATA_SIZE 8192
219 #define SWITCH_DATA_LENGTH 256
222 #define VAR_SOFTTRAN 2
223 #define VAR_HARDTRAN 3
274 int total_specificity;
358 #define HINTDEVICE_DATA_LENGTH 16
363 #define HASH_EXTENHINT_SIZE 17
365 #define HASH_EXTENHINT_SIZE 563
432 const char *right_key = arg;
440 cmp = strcasecmp(left->
hintdevice, right_key);
447 cmp = strncmp(left->
hintdevice, right_key, strlen(right_key));
481 static int autohint_cmp(
void *obj,
void *arg,
int flags)
485 const char *right_key = arg;
493 cmp = strcasecmp(left->
context, right_key);
500 cmp = strncmp(left->
context, right_key, strlen(right_key));
511 static int hintdevice_remove_cb(
void *obj,
void *arg,
void *data,
int flags)
515 struct ast_hint *hint =
data;
517 if (!strcasecmp(candidate->
hintdevice, device)
518 && candidate->
hint == hint) {
524 static int remove_hintdevice(
struct ast_hint *hint)
530 hintdevice_remove_cb, device, hint,
"Remove device from container");
538 static char *parse_hint_device(
struct ast_str *hint_args);
545 static void hintdevice_destroy(
void *obj)
565 if (!hint || !devicelist) {
576 while ((cur = strsep(&parse,
"&,"))) {
579 devicelength = strlen(cur);
589 device = ao2_t_alloc(
sizeof(*device) + devicelength, hintdevice_destroy,
590 "allocating a hintdevice structure");
592 ast_free(device_name);
599 ast_free(device_name);
603 ao2_t_link(hintdevices, device,
"Linking device into hintdevice container.");
604 ao2_t_ref(device, -1,
"hintdevice is linked so we can unref");
613 const char *
const text;
614 } extension_states[] = {
635 static int matchcid(
const char *cidpattern,
const char *callerid);
637 static void log_match_char_tree(
struct match_char *
node,
char *prefix);
639 static void new_find_extension(
const char *str,
struct scoreboard *score,
640 struct match_char *tree,
int length,
int spec,
const char *callerid,
642 static struct match_char *already_in_tree(
struct match_char *current,
char *pat,
int is_pattern);
645 static void create_match_char_tree(
struct ast_context *con);
647 static void destroy_pattern_tree(
struct match_char *pattern_tree);
648 static int hashtab_compare_extens(
const void *ha_a,
const void *ah_b);
649 static int hashtab_compare_exten_numbers(
const void *ah_a,
const void *ah_b);
650 static int hashtab_compare_exten_labels(
const void *ah_a,
const void *ah_b);
651 static unsigned int hashtab_hash_extens(
const void *obj);
652 static unsigned int hashtab_hash_priority(
const void *obj);
653 static unsigned int hashtab_hash_labels(
const void *obj);
654 static void __ast_internal_context_destroy(
struct ast_context *con);
655 static int ast_add_extension_nolock(
const char *context,
int replace,
const char *
extension,
657 const char *application,
void *data,
void (*
datad)(
void *),
const char *
registrar);
659 int replace,
const char *extension,
int priority,
const char *label,
const char *callerid,
660 const char *application,
void *data,
void (*
datad)(
void *),
665 static void get_device_state_causing_channels(
struct ao2_container *c);
666 static unsigned int ext_strncpy(
char *dst,
const char *src,
size_t dst_size,
int nofluff);
679 static int compare_char(
const void *a,
const void *b)
681 const unsigned char *ac = a;
682 const unsigned char *bc = b;
698 static int hashtab_compare_extens(
const void *ah_a,
const void *ah_b)
726 static int hashtab_compare_exten_numbers(
const void *ah_a,
const void *ah_b)
733 static int hashtab_compare_exten_labels(
const void *ah_a,
const void *ah_b)
740 unsigned int ast_hashtab_hash_contexts(
const void *obj)
746 static unsigned int hashtab_hash_extens(
const void *obj)
756 static unsigned int hashtab_hash_priority(
const void *obj)
759 return ast_hashtab_hash_int(ac->
priority);
762 static unsigned int hashtab_hash_labels(
const void *obj)
768 static int autofallthrough = 1;
769 static int extenpatternmatchnew = 0;
770 static char *overrideswitch = NULL;
777 AST_MUTEX_DEFINE_STATIC(maxcalllock);
778 static int countcalls;
779 static int totalcalls;
797 static int stateid = 1;
824 void check_contexts_trouble(
void);
826 void check_contexts_trouble(
void)
832 int check_contexts(
char *,
int);
834 int check_contexts(
char *file,
int line )
845 if (!contexts_table) {
846 ast_log(LOG_NOTICE,
"Called from: %s:%d: No contexts_table!\n", file, line);
850 t1 = ast_hashtab_start_traversal(contexts_table);
852 for(c2=contexts;c2;c2=c2->
next) {
859 ast_log(LOG_NOTICE,
"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->
name);
860 check_contexts_trouble();
864 for(c2=contexts;c2;c2=c2->
next) {
867 ast_log(LOG_NOTICE,
"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->
name);
868 check_contexts_trouble();
875 for(c2=contexts;c2;c2=c2->
next) {
883 char dummy_name[1024];
884 ex.exten = dummy_name;
891 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context records "
892 "the exten %s (CID match: %s) but it is not in its root_table\n",
895 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context records "
896 "the exten %s but it is not in its root_table\n",
897 file, line, c2->
name, dummy_name);
899 check_contexts_trouble();
906 ast_log(LOG_NOTICE,
"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->
name);
910 t1 = ast_hashtab_start_traversal(c2->
root_table);
919 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->
name, e2->
exten);
920 check_contexts_trouble();
932 for(e1 = c2->
root; e1; e1 = e1->
next) {
934 for(e2=e1;e2;e2=e2->
peer) {
937 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->
name, e1->
exten, e2->
priority );
938 check_contexts_trouble();
942 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->
name, e1->
exten, e2->
priority );
943 check_contexts_trouble();
947 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->
name, e1->
exten, e2->
priority );
948 check_contexts_trouble();
952 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->
name, e1->
exten, e2->
priority );
953 check_contexts_trouble();
959 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->
name, e1->
exten, e2->
priority );
960 check_contexts_trouble();
965 ast_log(LOG_NOTICE,
"Called from: %s:%d: No e1->peer_table!\n", file, line);
970 t1 = ast_hashtab_start_traversal(e1->
peer_table);
972 for(e3=e1;e3;e3=e3->
peer) {
979 ast_log(LOG_NOTICE,
"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->
name, e1->
exten, e2->
priority );
980 check_contexts_trouble();
990 static void pbx_destroy(
struct ast_pbx *p)
1075 board->total_specificity = spec;
1076 board->total_length = length;
1077 board->exten =
exten;
1078 board->last_char = last;
1080 #ifdef NEED_DEBUG_HERE
1081 ast_log(LOG_NOTICE,
"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->
exten, length, spec);
1086 static void log_match_char_tree(
struct match_char *node,
char *prefix)
1089 struct ast_str *my_prefix = ast_str_alloca(1024);
1093 if (node && node->exten)
1094 snprintf(extenstr,
sizeof(extenstr),
"(%p)", node->exten);
1096 if (strlen(node->x) > 1) {
1097 ast_debug(1,
"%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ?
'Y':
'N',
1098 node->deleted?
'D':
'-', node->specificity, node->exten?
"EXTEN:":
"",
1099 node->exten ? node->exten->
exten :
"", extenstr);
1101 ast_debug(1,
"%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ?
'Y':
'N',
1102 node->deleted?
'D':
'-', node->specificity, node->exten?
"EXTEN:":
"",
1103 node->exten ? node->exten->
exten :
"", extenstr);
1108 if (node->next_char)
1112 log_match_char_tree(node->alt_char, prefix);
1116 static void cli_match_char_tree(
struct match_char *node,
char *prefix,
int fd)
1119 struct ast_str *my_prefix = ast_str_alloca(1024);
1124 snprintf(extenstr,
sizeof(extenstr),
"(%p)", node->exten);
1127 if (strlen(node->x) > 1) {
1128 ast_cli(fd,
"%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ?
'Y' :
'N',
1129 node->deleted ?
'D' :
'-', node->specificity, node->exten?
"EXTEN:" :
"",
1130 node->exten ? node->exten->
name :
"", extenstr);
1132 ast_cli(fd,
"%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ?
'Y' :
'N',
1133 node->deleted ?
'D' :
'-', node->specificity, node->exten?
"EXTEN:" :
"",
1134 node->exten ? node->exten->
name :
"", extenstr);
1139 if (node->next_char)
1140 cli_match_char_tree(node->next_char,
ast_str_buffer(my_prefix), fd);
1143 cli_match_char_tree(node->alt_char, prefix, fd);
1151 for (node2 = node; node2; node2 = node2->next_char) {
1153 #ifdef NEED_DEBUG_HERE
1154 ast_log(LOG_NOTICE,
"CanMatch_exten returns exten %s(%p)\n", node2->exten->
exten, node2->exten);
1156 return node2->exten;
1159 #ifdef NEED_DEBUG_HERE
1160 ast_log(LOG_NOTICE,
"CanMatch_exten returns NULL, match_char=%s\n", node->x);
1171 if (node && node->x[0] ==
'.' && !node->x[1]) {
1175 if (node && node->x[0] ==
'!' && !node->x[1]) {
1179 if (!node || !node->next_char) {
1183 m3 = node->next_char;
1188 for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
1193 for (m4 = m3; m4; m4 = m4->alt_char) {
1194 e3 = trie_find_next_match(m3);
1224 static const char *candidate_exten_advance(
const char *str)
1227 while (*str ==
'-') {
1233 #define MORE(s) (*candidate_exten_advance(s))
1234 #define ADVANCE(s) candidate_exten_advance(s)
1236 static void new_find_extension(
const char *str,
struct scoreboard *score,
struct match_char *tree,
int length,
int spec,
const char *callerid,
const char *label,
enum ext_match_t action)
1242 ast_log(LOG_NOTICE,
"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
1244 ast_log(LOG_NOTICE,
"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
1246 for (p = tree; p; p = p->alt_char) {
1247 if (p->is_pattern) {
1248 if (p->x[0] ==
'N') {
1249 if (p->x[1] == 0 && *str >=
'2' && *str <=
'9' ) {
1250 #define NEW_MATCHER_CHK_MATCH \
1251 if (p->exten && !MORE(str)) { \
1252 if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { \
1253 update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
1254 if (!p->deleted) { \
1255 if (action == E_FINDLABEL) { \
1256 if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
1257 ast_debug(4, "Found label in preferred extension\n"); \
1261 ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->name); \
1268 #define NEW_MATCHER_RECURSE \
1269 if (p->next_char && (MORE(str) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
1270 || p->next_char->x[0] == '!')) { \
1271 if (MORE(str) || p->next_char->x[0] == '!') { \
1272 new_find_extension(ADVANCE(str), score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
1273 if (score->exten) { \
1274 ast_debug(4 ,"returning an exact match-- %s\n", score->exten->name); \
1278 new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
1279 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
1280 ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->name : \
1285 } else if ((p->next_char || action == E_CANMATCH) && !MORE(str)) { \
1286 score->canmatch = 1; \
1287 score->canmatch_exten = get_canmatch_exten(p); \
1288 if (action == E_CANMATCH || action == E_MATCHMORE) { \
1289 ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
1294 NEW_MATCHER_CHK_MATCH;
1295 NEW_MATCHER_RECURSE;
1297 }
else if (p->x[0] ==
'Z') {
1298 if (p->x[1] == 0 && *str >=
'1' && *str <=
'9' ) {
1299 NEW_MATCHER_CHK_MATCH;
1300 NEW_MATCHER_RECURSE;
1302 }
else if (p->x[0] ==
'X') {
1303 if (p->x[1] == 0 && *str >=
'0' && *str <=
'9' ) {
1304 NEW_MATCHER_CHK_MATCH;
1305 NEW_MATCHER_RECURSE;
1307 }
else if (p->x[0] ==
'.' && p->x[1] == 0) {
1310 const char *str2 = str;
1311 while (*str2 && *str2 !=
'/') {
1315 if (p->exten && *str2 !=
'/') {
1316 update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten,
'.', callerid, p->deleted, p);
1318 ast_debug(4,
"return because scoreboard has a match with '/'--- %s\n",
1319 score->exten->
name);
1323 if (p->next_char && p->next_char->x[0] ==
'/' && p->next_char->x[1] == 0) {
1324 new_find_extension(
"/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
1325 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1326 ast_debug(4,
"return because scoreboard has exact match OR "
1327 "CANMATCH/MATCHMORE & canmatch set--- %s\n",
1328 score->exten ? score->exten->
name :
"NULL");
1332 }
else if (p->x[0] ==
'!' && p->x[1] == 0) {
1335 const char *str2 = str;
1336 while (*str2 && *str2 !=
'/') {
1340 if (p->exten && *str2 !=
'/') {
1341 update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten,
'!', callerid, p->deleted, p);
1343 ast_debug(4,
"return because scoreboard has a '!' match--- %s\n",
1344 score->exten->
name);
1348 if (p->next_char && p->next_char->x[0] ==
'/' && p->next_char->x[1] == 0) {
1349 new_find_extension(
"/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
1350 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1351 ast_debug(4,
"return because scoreboard has exact match OR "
1352 "CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n",
1353 score->exten ? score->exten->
name :
"NULL");
1357 }
else if (p->x[0] ==
'/' && p->x[1] == 0) {
1359 if (p->next_char && callerid && *callerid) {
1360 new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
1361 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1362 ast_debug(4,
"return because scoreboard has exact match OR "
1363 "CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n",
1364 score->exten ? score->exten->
name :
"NULL");
1368 }
else if (strchr(p->x, *str)) {
1369 ast_debug(4,
"Nothing strange about this match\n");
1370 NEW_MATCHER_CHK_MATCH;
1371 NEW_MATCHER_RECURSE;
1373 }
else if (strchr(p->x, *str)) {
1374 ast_debug(4,
"Nothing strange about this match\n");
1375 NEW_MATCHER_CHK_MATCH;
1376 NEW_MATCHER_RECURSE;
1379 ast_debug(4,
"return at end of func\n");
1402 static struct match_char *already_in_tree(
struct match_char *current,
char *pat,
int is_pattern)
1410 for (t = current; t; t = t->alt_char) {
1411 if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {
1423 static void insert_in_next_chars_alt_char_list(
struct match_char **parent_ptr,
struct match_char *node)
1429 if (!(*parent_ptr)) {
1434 if ((*parent_ptr)->specificity > node->specificity) {
1436 node->alt_char = (*parent_ptr);
1441 lcurr = *parent_ptr;
1442 for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
1443 if (curr->specificity > node->specificity) {
1444 node->alt_char = curr;
1445 lcurr->alt_char = node;
1452 lcurr->alt_char = node;
1468 if (!(m =
ast_calloc(1,
sizeof(*m) + strlen(pattern->
buf)))) {
1475 strcpy(m->x, pattern->
buf);
1479 m->is_pattern = is_pattern;
1480 if (pattern->
specif == 1 && is_pattern && pattern->
buf[0] ==
'N') {
1481 m->specificity = 0x0832;
1482 }
else if (pattern->
specif == 1 && is_pattern && pattern->
buf[0] ==
'Z') {
1483 m->specificity = 0x0931;
1484 }
else if (pattern->
specif == 1 && is_pattern && pattern->
buf[0] ==
'X') {
1485 m->specificity = 0x0a30;
1486 }
else if (pattern->
specif == 1 && is_pattern && pattern->
buf[0] ==
'.') {
1487 m->specificity = 0x18000;
1488 }
else if (pattern->
specif == 1 && is_pattern && pattern->
buf[0] ==
'!') {
1489 m->specificity = 0x28000;
1491 m->specificity = pattern->
specif;
1495 insert_in_next_chars_alt_char_list(&con->
pattern_tree, m);
1498 insert_in_next_chars_alt_char_list(nextcharptr, m);
1500 insert_in_next_chars_alt_char_list(¤t->next_char, m);
1518 static const char *get_pattern_node(
struct pattern_node *node,
const char *src,
int pattern,
const char *extenbuf)
1520 #define INC_DST_OVERFLOW_CHECK \
1522 if (dst - node->buf < sizeof(node->buf) - 1) { \
1530 node->
buf[0] =
'\0';
1532 if (*src ==
'[' && pattern) {
1533 char *dst = node->
buf;
1534 const char *src_next;
1544 if (*src ==
'[' || *src ==
'\\' || *src ==
'-' || *src ==
']') {
1546 INC_DST_OVERFLOW_CHECK;
1548 }
else if (*src ==
'-') {
1549 unsigned char first;
1553 first = *(src_next - 1);
1562 if (node->
buf[0] && last) {
1564 while (++first <= last) {
1566 INC_DST_OVERFLOW_CHECK;
1575 INC_DST_OVERFLOW_CHECK;
1577 }
else if (*src ==
'\0') {
1578 ast_log(LOG_WARNING,
1579 "A matching ']' was not found for '[' in exten pattern '%s'\n",
1582 }
else if (*src ==
']') {
1587 INC_DST_OVERFLOW_CHECK;
1595 "Expanded character set too large to deal with in exten pattern '%s'. Ignoring character set.\n",
1597 node->
buf[0] =
'\0';
1602 length = strlen(node->
buf);
1604 ast_log(LOG_WARNING,
"Empty character set in exten pattern '%s'. Ignoring.\n",
1606 node->
buf[0] =
'\0';
1609 qsort(node->
buf, length, 1, compare_char);
1613 src_next = node->
buf;
1614 while (*src_next++) {
1615 if (*dst != *src_next) {
1620 length = strlen(node->
buf);
1622 node->
specif = length | (
unsigned char) node->
buf[0];
1624 }
else if (*src ==
'-') {
1634 node->
buf[0] = *++src;
1635 if (!node->
buf[0]) {
1639 node->
buf[0] = *src;
1642 if (node->
buf[0] ==
'n') {
1644 }
else if (node->
buf[0] ==
'x') {
1646 }
else if (node->
buf[0] ==
'z') {
1651 node->
buf[1] =
'\0';
1659 #undef INC_DST_OVERFLOW_CHECK
1662 #define MAX_EXTENBUF_SIZE 512
1673 char extenbuf[MAX_EXTENBUF_SIZE];
1674 volatile size_t required_space = strlen(e1->
exten) + 1;
1678 required_space += (strlen(e1->
cidmatch) + 2 );
1679 if (required_space > MAX_EXTENBUF_SIZE) {
1681 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1687 if (required_space > MAX_EXTENBUF_SIZE) {
1689 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1697 ast_debug(1,
"Adding exten %s to tree\n", extenbuf);
1709 pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
1710 for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
1711 idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
1712 pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
1716 if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].
buf, pattern))
1718 if (!pat_node[idx_next].buf[0]) {
1728 ast_log(LOG_WARNING,
"Found duplicate exten. Had %s found %s\n",
1729 m2->deleted ?
"(deleted/invalid)" : m2->exten->
name, e1->
name);
1735 m0 = &m2->next_char;
1746 m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
1750 m0 = &m1->next_char;
1752 if (!pat_node[idx_next].buf[0]) {
1753 if (m2 && m2->exten) {
1754 ast_log(LOG_WARNING,
"Found duplicate exten. Had %s found %s\n",
1755 m2->deleted ?
"(deleted/invalid)" : m2->exten->
name, e1->
name);
1770 static void create_match_char_tree(
struct ast_context *con)
1775 int biggest_bucket, resizes, numobjs, numbucks;
1777 ast_debug(1,
"Creating Extension Trie for context %s(%p)\n", con->
name, con);
1779 ast_debug(1,
"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
1780 numobjs, numbucks, biggest_bucket, resizes);
1782 t1 = ast_hashtab_start_traversal(con->
root_table);
1785 add_exten_to_pattern_tree(con, e1, 0);
1787 ast_log(LOG_ERROR,
"Attempt to create extension with no extension name.\n");
1793 static void destroy_pattern_tree(
struct match_char *pattern_tree)
1796 if (pattern_tree->alt_char) {
1797 destroy_pattern_tree(pattern_tree->alt_char);
1798 pattern_tree->alt_char = 0;
1801 if (pattern_tree->next_char) {
1802 destroy_pattern_tree(pattern_tree->next_char);
1803 pattern_tree->next_char = 0;
1805 pattern_tree->exten = 0;
1806 ast_free(pattern_tree);
1817 static int ext_cmp_exten_strlen(
const char *str)
1824 while (*str ==
'-') {
1847 static int ext_cmp_exten_partial(
const char *left,
const char *right)
1853 while (*left ==
'-') {
1856 while (*right ==
'-') {
1869 cmp = *left - *right;
1890 static int ext_cmp_exten(
const char *left,
const char *right)
1896 while (*left ==
'-') {
1899 while (*right ==
'-') {
1903 cmp = *left - *right;
1995 bitwise[c / BITS_PER] = 1 << ((BITS_PER - 1) - (c % BITS_PER));
2003 return 0x0800 |
'2';
2010 return 0x0A00 |
'0';
2017 return 0x0900 |
'1';
2037 end = strchr(*p,
']');
2040 ast_log(LOG_WARNING,
"Wrong usage of [] in the extension\n");
2046 for (; *p < end; ++*p) {
2051 if (*p + 2 < end && (*p)[1] ==
'-') {
2060 for (; c1 <= c2; ++c1) {
2061 unsigned char mask = 1 << ((BITS_PER - 1) - (c1 % BITS_PER));
2069 if (!(bitwise[c1 / BITS_PER] & mask)) {
2071 bitwise[c1 / BITS_PER] |= mask;
2078 return count | cmin;
2092 static int ext_cmp_pattern(
const char *left,
const char *right)
2099 unsigned char left_bitwise[32] = { 0, };
2100 unsigned char right_bitwise[32] = { 0, };
2104 cmp = left_pos - right_pos;
2113 cmp = memcmp(right_bitwise, left_bitwise, ARRAY_LEN(left_bitwise));
2140 static int ext_cmp(
const char *left,
const char *right)
2143 if (left[0] !=
'_') {
2144 if (right[0] ==
'_') {
2148 return ext_cmp_exten(left, right);
2150 if (right[0] !=
'_') {
2159 return ext_cmp_pattern(left + 1, right + 1);
2162 static int ext_fluff_count(
const char *exten)
2166 if (*exten !=
'_') {
2169 if (*exten ==
'-') {
2180 if (*exten ==
'-') {
2182 }
else if (*exten ==
'[') {
2184 exten = strchr(exten,
']');
2223 static int _extension_match_core(
const char *pattern,
const char *data,
enum ext_match_t mode)
2225 mode &= E_MATCH_MASK;
2227 #ifdef NEED_DEBUG_HERE
2228 ast_log(LOG_NOTICE,
"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (
int)mode);
2231 if (pattern[0] !=
'_') {
2232 int lp = ext_cmp_exten_strlen(pattern);
2233 int ld = ext_cmp_exten_strlen(data);
2236 #ifdef NEED_DEBUG_HERE
2237 ast_log(LOG_NOTICE,
"return (0) - pattern too short, cannot match\n");
2242 if (mode == E_MATCH) {
2243 #ifdef NEED_DEBUG_HERE
2244 ast_log(LOG_NOTICE,
"return (!ext_cmp_exten(%s,%s) when mode== E_MATCH)\n", pattern, data);
2246 return !ext_cmp_exten(pattern, data);
2248 if (ld == 0 || !ext_cmp_exten_partial(pattern, data)) {
2249 #ifdef NEED_DEBUG_HERE
2250 ast_log(LOG_NOTICE,
"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
2252 return (mode == E_MATCHMORE) ? lp > ld : 1;
2254 #ifdef NEED_DEBUG_HERE
2255 ast_log(LOG_NOTICE,
"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
2260 if (mode == E_MATCH && data[0] ==
'_') {
2270 #ifdef NEED_DEBUG_HERE
2271 ast_log(LOG_NOTICE,
"Comparing as patterns first. pattern:%s data:%s\n", pattern, data);
2273 if (!ext_cmp_pattern(pattern + 1, data + 1)) {
2274 #ifdef NEED_DEBUG_HERE
2275 ast_log(LOG_NOTICE,
"return (1) - pattern matches pattern\n");
2290 while (*data ==
'-') {
2293 while (*pattern ==
'-') {
2296 if (!*data || !*pattern || *pattern ==
'/') {
2303 end = strchr(pattern,
']');
2305 ast_log(LOG_WARNING,
"Wrong usage of [] in the extension\n");
2308 if (pattern == end) {
2313 for (; pattern < end; ++pattern) {
2314 if (pattern+2 < end && pattern[1] ==
'-') {
2315 if (*data >= pattern[0] && *data <= pattern[2])
2321 }
else if (*data == pattern[0])
2324 if (pattern >= end) {
2325 #ifdef NEED_DEBUG_HERE
2326 ast_log(LOG_NOTICE,
"return (0) when pattern>=end\n");
2334 if (*data < '2' || *data >
'9') {
2335 #ifdef NEED_DEBUG_HERE
2336 ast_log(LOG_NOTICE,
"return (0) N is not matched\n");
2343 if (*data < '0' || *data >
'9') {
2344 #ifdef NEED_DEBUG_HERE
2345 ast_log(LOG_NOTICE,
"return (0) X is not matched\n");
2352 if (*data < '1' || *data >
'9') {
2353 #ifdef NEED_DEBUG_HERE
2354 ast_log(LOG_NOTICE,
"return (0) Z is not matched\n");
2360 #ifdef NEED_DEBUG_HERE
2361 ast_log(LOG_NOTICE,
"return (1) when '.' is matched\n");
2365 #ifdef NEED_DEBUG_HERE
2366 ast_log(LOG_NOTICE,
"return (2) when '!' is matched\n");
2370 if (*data != *pattern) {
2371 #ifdef NEED_DEBUG_HERE
2372 ast_log(LOG_NOTICE,
"return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
2382 #ifdef NEED_DEBUG_HERE
2383 ast_log(LOG_NOTICE,
"return (0) when data longer than pattern\n");
2392 if (*pattern ==
'\0' || *pattern ==
'/') {
2393 #ifdef NEED_DEBUG_HERE
2394 ast_log(LOG_NOTICE,
"at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
2396 return (mode == E_MATCHMORE) ? 0 : 1;
2397 }
else if (*pattern ==
'!') {
2398 #ifdef NEED_DEBUG_HERE
2399 ast_log(LOG_NOTICE,
"at end, return (2) when '!' is matched\n");
2403 #ifdef NEED_DEBUG_HERE
2404 ast_log(LOG_NOTICE,
"at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
2406 return (mode == E_MATCH) ? 0 : 1;
2414 static int extension_match_core(
const char *pattern,
const char *data,
enum ext_match_t mode)
2417 static int prof_id = -2;
2418 if (prof_id == -2) {
2421 ast_mark(prof_id, 1);
2422 i = _extension_match_core(ast_strlen_zero(pattern) ?
"" : pattern, ast_strlen_zero(data) ?
"" : data, mode);
2423 ast_mark(prof_id, 0);
2429 return extension_match_core(pattern, extension, E_MATCH);
2432 int ast_extension_close(
const char *pattern,
const char *data,
int needmore)
2434 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
2435 ast_log(LOG_WARNING,
"invalid argument %d\n", needmore);
2436 return extension_match_core(pattern, data, needmore);
2450 if (contexts_table) {
2454 while ((tmp = ast_walk_contexts(tmp))) {
2455 if (!strcasecmp(name, tmp->
name)) {
2464 #define STATUS_NO_CONTEXT 1
2465 #define STATUS_NO_EXTENSION 2
2466 #define STATUS_NO_PRIORITY 3
2467 #define STATUS_NO_LABEL 4
2468 #define STATUS_SUCCESS 5
2470 static int matchcid(
const char *cidpattern,
const char *callerid)
2475 if (ast_strlen_zero(callerid)) {
2476 return ast_strlen_zero(cidpattern) ? 1 : 0;
2484 const char *context,
const char *exten,
int priority,
2485 const char *label,
const char *callerid,
enum ext_match_t action)
2489 struct ast_exten *e = NULL, *eroot = NULL;
2492 struct ast_str *tmpdata = NULL;
2495 pattern.
label = label;
2497 #ifdef NEED_DEBUG_HERE
2498 ast_log(LOG_NOTICE,
"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (
int) action);
2502 if (q->stacklen == 0) {
2503 q->status = STATUS_NO_CONTEXT;
2506 q->foundcontext = NULL;
2507 }
else if (q->stacklen >= AST_PBX_MAX_STACK) {
2508 ast_log(LOG_WARNING,
"Maximum PBX stack (%d) exceeded. Too many includes?\n", AST_PBX_MAX_STACK);
2513 for (x = 0; x < q->stacklen; x++) {
2514 if (!strcasecmp(q->incstack[x], context))
2527 if (q->status < STATUS_NO_EXTENSION)
2528 q->status = STATUS_NO_EXTENSION;
2533 score.total_specificity = 0;
2535 score.total_length = 0;
2537 create_match_char_tree(tmp);
2539 ast_debug(1,
"Tree Created in context %s:\n", context);
2544 ast_log(LOG_NOTICE,
"The Trie we are searching in:\n");
2549 if (!ast_strlen_zero(overrideswitch)) {
2556 name = strsep(&osw,
"/");
2560 ast_log(LOG_WARNING,
"No such switch '%s'\n",
name);
2564 if (osw && strchr(osw,
'$')) {
2569 ast_log(LOG_WARNING,
"Can't evaluate overrideswitch?!\n");
2580 if (action == E_CANMATCH)
2581 aswf = asw->canmatch;
2582 else if (action == E_MATCHMORE)
2583 aswf = asw->matchmore;
2592 res = aswf(chan, context, exten, priority, callerid, datap);
2600 q->foundcontext = context;
2607 if (extenpatternmatchnew) {
2608 new_find_extension(exten, &score, tmp->
pattern_tree, 0, 0, callerid, label, action);
2609 eroot = score.exten;
2611 if (score.last_char ==
'!' && action == E_MATCHMORE) {
2615 #ifdef NEED_DEBUG_HERE
2616 ast_log(LOG_NOTICE,
"Returning MATCHMORE NULL with exclamation point.\n");
2621 if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
2622 q->status = STATUS_SUCCESS;
2623 #ifdef NEED_DEBUG_HERE
2624 ast_log(LOG_NOTICE,
"Returning CANMATCH exten %s\n", score.canmatch_exten->
exten);
2626 return score.canmatch_exten;
2629 if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
2631 struct ast_exten *z = trie_find_next_match(score.node);
2633 #ifdef NEED_DEBUG_HERE
2634 ast_log(LOG_NOTICE,
"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->
exten);
2637 if (score.canmatch_exten) {
2638 #ifdef NEED_DEBUG_HERE
2639 ast_log(LOG_NOTICE,
"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->
exten, score.canmatch_exten);
2641 return score.canmatch_exten;
2643 #ifdef NEED_DEBUG_HERE
2644 ast_log(LOG_NOTICE,
"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
2650 #ifdef NEED_DEBUG_HERE
2651 ast_log(LOG_NOTICE,
"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
2658 if (q->status < STATUS_NO_PRIORITY)
2659 q->status = STATUS_NO_PRIORITY;
2661 if (action == E_FINDLABEL && label ) {
2662 if (q->status < STATUS_NO_LABEL)
2663 q->status = STATUS_NO_LABEL;
2669 q->status = STATUS_SUCCESS;
2670 q->foundcontext = context;
2671 #ifdef NEED_DEBUG_HERE
2672 ast_log(LOG_NOTICE,
"Returning complete match of exten %s\n", e->
exten);
2681 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
2682 int match = extension_match_core(eroot->exten, exten, action);
2685 if (!match || (eroot->matchcid && !
matchcid(eroot->cidmatch, callerid)))
2687 if (match == 2 && action == E_MATCHMORE) {
2694 if (q->status < STATUS_NO_PRIORITY)
2695 q->status = STATUS_NO_PRIORITY;
2697 if (action == E_FINDLABEL && label ) {
2698 if (q->status < STATUS_NO_LABEL)
2699 q->status = STATUS_NO_LABEL;
2705 q->status = STATUS_SUCCESS;
2706 q->foundcontext = context;
2713 for (idx = 0; idx < ast_context_switches_count(tmp); idx++) {
2714 const struct ast_sw *sw = ast_context_switches_get(tmp, idx);
2720 ast_log(LOG_WARNING,
"No such switch '%s'\n", ast_get_switch_name(sw));
2725 if (ast_get_switch_eval(sw)) {
2727 ast_log(LOG_WARNING,
"Can't evaluate switch?!\n");
2730 pbx_substitute_variables_helper(chan, ast_get_switch_data(sw),
2734 datap = ast_get_switch_data(sw);
2738 if (action == E_CANMATCH)
2739 aswf = asw->canmatch;
2740 else if (action == E_MATCHMORE)
2741 aswf = asw->matchmore;
2749 res = aswf(chan, context, exten, priority, callerid, datap);
2756 q->foundcontext = context;
2764 q->incstack[q->stacklen++] = tmp->
data;
2766 for (idx = 0; idx < ast_context_includes_count(tmp); idx++) {
2767 const struct ast_include *i = ast_context_includes_get(tmp, idx);
2769 if (include_valid(i)) {
2770 if ((e = pbx_find_extension(chan, bypass, q, include_rname(i), exten, priority, label, callerid, action))) {
2771 #ifdef NEED_DEBUG_HERE
2772 ast_log(LOG_NOTICE,
"Returning recursive match of %s\n", e->
exten);
2783 static void exception_store_free(
void *data)
2787 ast_free(exception);
2791 .
type =
"EXCEPTION",
2792 .destroy = exception_store_free,
2812 ds = ast_datastore_alloc(&exception_store_info, NULL);
2819 ds->
data = exception;
2822 exception = ds->
data;
2827 exception->
priority = ast_channel_priority(chan);
2832 static int acf_exception_read(
struct ast_channel *chan,
const char *name,
char *data,
char *buf,
size_t buflen)
2836 if (!ds || !ds->
data)
2838 exception = ds->
data;
2839 if (!strcasecmp(data,
"REASON"))
2841 else if (!strcasecmp(data,
"CONTEXT"))
2843 else if (!strncasecmp(data,
"EXTEN", 5))
2845 else if (!strcasecmp(data,
"PRIORITY"))
2846 snprintf(buf, buflen,
"%d", exception->
priority);
2853 .
name =
"EXCEPTION",
2854 .read = acf_exception_read,
2876 const char *context,
const char *exten,
int priority,
2877 const char *label,
const char *callerid,
enum ext_match_t action,
int *found,
int combined_find_spawn)
2881 char *substitute = NULL;
2884 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
2889 context = con->
name;
2895 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
2899 if (matching_action) {
2902 }
else if (action == E_FINDLABEL) {
2913 if (ast_strlen_zero(e->
data)) {
2917 if ((!(tmp = strchr(e->
data,
'$'))) || (!strstr(tmp,
"${") && !strstr(tmp,
"$["))) {
2927 ast_log(LOG_WARNING,
"No application '%s' for extension (%s, %s, %d)\n", e->
app, context, exten, priority);
2930 if (ast_channel_context(c) != context)
2931 ast_channel_context_set(c, context);
2932 if (ast_channel_exten(c) != exten)
2933 ast_channel_exten_set(c, exten);
2934 ast_channel_priority_set(c, priority);
2936 pbx_substitute_variables_helper(c, substitute, passdata,
sizeof(passdata)-1);
2939 if (VERBOSITY_ATLEAST(3)) {
2941 exten, context, priority,
2942 COLORIZE(COLOR_BRCYAN, 0,
app_name(app)),
2943 COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(c)),
2944 COLORIZE(COLOR_BRMAGENTA, 0, passdata),
2953 if (matching_action) {
2957 ast_log(LOG_WARNING,
"No execution engine for switch %s\n", q.swo->
name);
2960 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
2966 case STATUS_NO_CONTEXT:
2967 if (!matching_action && !combined_find_spawn)
2968 ast_log(LOG_NOTICE,
"Cannot find extension context '%s'\n",
S_OR(context,
""));
2970 case STATUS_NO_EXTENSION:
2971 if (!matching_action && !combined_find_spawn)
2972 ast_log(LOG_NOTICE,
"Cannot find extension '%s' in context '%s'\n", exten,
S_OR(context,
""));
2974 case STATUS_NO_PRIORITY:
2975 if (!matching_action && !combined_find_spawn)
2976 ast_log(LOG_NOTICE,
"No such priority %d in extension '%s' in context '%s'\n", priority, exten,
S_OR(context,
""));
2978 case STATUS_NO_LABEL:
2979 if (context && !combined_find_spawn)
2980 ast_log(LOG_NOTICE,
"No such label '%s' in extension '%s' in context '%s'\n",
S_OR(label,
""), exten,
S_OR(context,
""));
2986 return (matching_action) ? 0 : -1;
2994 return pbx_find_extension(c, NULL, &q, context, exten,
PRIORITY_HINT, NULL,
"", E_MATCH);
2997 static struct ast_exten *ast_hint_extension(
struct ast_channel *c,
const char *context,
const char *exten)
3037 static char *parse_hint_presence(
struct ast_str *hint_args)
3042 if ((tmp = strrchr(copy,
','))) {
3056 static char *parse_hint_device(
struct ast_str *hint_args)
3061 if ((tmp = strrchr(copy,
','))) {
3069 static void device_state_info_dt(
void *obj)
3073 ao2_cleanup(info->causing_channel);
3081 static int ast_extension_state3(
struct ast_str *hint_app,
struct ao2_container *device_state_info)
3088 rest = parse_hint_device(hint_app);
3091 while ((cur = strsep(&rest,
"&"))) {
3095 if (device_state_info) {
3101 obj->device_state = state;
3102 strcpy(obj->device_name, cur);
3117 if (!e || !hint_app) {
3121 ast_str_set(&hint_app, 0,
"%s", ast_get_extension_app(e));
3122 return ast_extension_state3(hint_app, device_state_info);
3130 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
3131 if (extension_states[i].extension_state == extension_state)
3132 return extension_states[i].text;
3141 static int internal_extension_state_extended(
struct ast_channel *c,
const char *context,
const char *exten,
3146 if (!(e = ast_hint_extension(c, context, exten))) {
3150 if (e->
exten[0] ==
'_') {
3160 if (!(e = ast_hint_extension(c, context, exten))) {
3172 return internal_extension_state_extended(c, context, exten, NULL);
3182 if (device_state_info) {
3183 container = alloc_device_state_info();
3186 ret = internal_extension_state_extended(c, context, exten, container);
3187 if (ret < 0 && container) {
3192 if (device_state_info) {
3193 get_device_state_causing_channels(container);
3200 static int extension_presence_state_helper(
struct ast_exten *e,
char **subtype,
char **
message)
3203 char *presence_provider;
3206 if (!e || !hint_app) {
3210 app = ast_get_extension_app(e);
3211 if (ast_strlen_zero(app)) {
3216 presence_provider = parse_hint_presence(hint_app);
3218 if (ast_strlen_zero(presence_provider)) {
3223 return ast_presence_state(presence_provider, subtype, message);
3230 if (!(e = ast_hint_extension(c, context, exten))) {
3234 if (e->
exten[0] ==
'_') {
3241 if (!(e = ast_hint_extension(c, context, exten))) {
3247 return extension_presence_state_helper(e, subtype, message);
3251 const char *context,
3255 struct ast_hint *hint,
3261 info.reason = reason;
3267 info.device_state_info = device_state_info;
3272 info.presence_subtype =
"";
3277 info.presence_message =
"";
3284 res = cb(context, exten, &info, data);
3296 static void get_device_state_causing_channels(
struct ao2_container *c)
3306 for (; (info = ao2_iterator_next(&iter));
ao2_ref(info, -1)) {
3310 struct timeval chantime = {0, };
3312 switch (info->device_state) {
3337 snprintf(match,
sizeof(match),
"%s-", info->device_name);
3340 ast_channel_lock(chan);
3343 ast_channel_unlock(chan);
3348 ast_channel_unlock(chan);
3349 info->causing_channel = chan;
3353 if (!info->causing_channel) {
3354 chantime = ast_channel_creationtime(chan);
3356 info->causing_channel = chan;
3357 }
else if (
ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
3358 chantime = ast_channel_creationtime(chan);
3361 info->causing_channel = chan;
3363 ast_channel_unlock(chan);
3370 static void device_state_notify_callbacks(
struct ast_hint *hint,
struct ast_str **hint_app)
3377 int first_extended_cb_call = 1;
3393 ast_get_context_name(ast_get_extension_context(hint->
exten)),
3394 sizeof(context_name));
3396 sizeof(exten_name));
3411 device_state_info = alloc_device_state_info();
3413 state = ast_extension_state3(*hint_app, device_state_info);
3416 ao2_cleanup(device_state_info);
3426 for (; (state_cb = ao2_iterator_next(&cb_iter));
ao2_ref(state_cb, -1)) {
3427 execute_state_callback(state_cb->
change_cb,
3443 for (; (state_cb = ao2_iterator_next(&cb_iter));
ao2_ref(state_cb, -1)) {
3444 if (state_cb->
extended && first_extended_cb_call) {
3446 first_extended_cb_call = 0;
3447 get_device_state_causing_channels(device_state_info);
3449 if (state_cb->
extended || !same_state) {
3450 execute_state_callback(state_cb->
change_cb,
3456 state_cb->
extended ? device_state_info : NULL);
3461 ao2_cleanup(device_state_info);
3464 static void presence_state_notify_callbacks(
struct ast_hint *hint,
struct ast_str **hint_app,
3484 ast_get_context_name(ast_get_extension_context(hint->
exten)),
3485 sizeof(context_name));
3487 sizeof(exten_name));
3512 for (; (state_cb = ao2_iterator_next(&cb_iter));
ao2_ref(state_cb, -1)) {
3513 execute_state_callback(state_cb->
change_cb,
3525 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
3526 execute_state_callback(state_cb->
change_cb,
3539 struct ast_hint *hint;
3554 device_state_notify_callbacks(hint, &hint_app);
3558 char *presence_subtype = NULL;
3559 char *presence_message = NULL;
3562 state = extension_presence_state_helper(
3563 hint->
exten, &presence_subtype, &presence_message);
3566 .
state = state > 0 ? state : AST_PRESENCE_INVALID,
3567 .subtype = presence_subtype,
3568 .message = presence_message
3571 presence_state_notify_callbacks(hint, &hint_app, &presence_state);
3574 ast_free(presence_subtype);
3575 ast_free(presence_message);
3593 char *virtual_device;
3612 for (; (state_cb = ao2_iterator_next(&cb_iter));
ao2_ref(state_cb, -1)) {
3613 execute_state_callback(state_cb->
change_cb,
3630 if (dev_state->
eid) {
3651 dev_iter = ao2_t_callback(hintdevices,
3655 "find devices in container");
3657 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1,
"Next device")) {
3659 device_state_notify_callbacks(device->
hint, &hint_app);
3669 if (ast_strlen_zero(type)) {
3674 virtual_device = strchr(type,
':');
3675 device_name = strchr(type,
'/');
3676 if (virtual_device && (!device_name || (virtual_device < device_name))) {
3677 device_name = virtual_device;
3681 if (ast_strlen_zero(device_name)) {
3685 *device_name++ =
'\0';
3688 for (; (autohint = ao2_iterator_next(&auto_iter)); ao2_t_ref(autohint, -1,
"Next autohint")) {
3714 static void destroy_state_cb(
void *doomed)
3727 static int extension_state_add_destroy(
const char *context,
const char *exten,
3730 struct ast_hint *hint;
3736 if (!context && !exten) {
3744 if (!(state_cb = ao2_alloc(
sizeof(*state_cb), destroy_state_cb))) {
3745 ao2_unlock(statecbs);
3756 ao2_unlock(statecbs);
3760 if (!context || !exten)
3764 e = ast_hint_extension(NULL, context, exten);
3773 if (e->
exten[0] ==
'_') {
3779 e = ast_hint_extension(NULL, context, exten);
3780 if (!e || e->
exten[0] ==
'_') {
3787 hint = ao2_find(hints, e, 0);
3794 if (!(state_cb = ao2_alloc(
sizeof(*state_cb), destroy_state_cb))) {
3802 }
while (
id == -1 ||
id == 0);
3820 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
3826 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
3832 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
3838 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
3845 const struct ast_hint *hint = obj;
3848 if ((state_cb = ao2_find(hint->
callbacks,
id, 0))) {
3865 p_cur = ao2_find(statecbs, change_cb,
OBJ_UNLINK);
3871 struct ast_hint *hint;
3889 static int hint_id_cmp(
void *obj,
void *arg,
int flags)
3903 static void destroy_hint(
void *obj)
3905 struct ast_hint *hint = obj;
3924 if (!hint_remove_message_type()) {
3944 struct ast_hint *hint;
3955 remove_hintdevice(hint);
3963 ast_get_context_name(ast_get_extension_context(hint->
exten)),
3980 struct ast_hint *hint_new;
3981 struct ast_hint *hint_found;
3982 char *message = NULL;
3983 char *subtype = NULL;
3995 hint_new = ao2_alloc(
sizeof(*hint_new), destroy_hint);
4007 hint_new->
exten = e;
4008 if (strstr(e->
app,
"${") && e->
exten[0] ==
'_') {
4014 if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
4025 hint_found = ao2_find(hints, e, 0);
4030 ast_debug(2,
"HINTS: Not re-adding existing hint %s: %s\n",
4031 ast_get_extension_name(e), ast_get_extension_app(e));
4036 ast_debug(2,
"HINTS: Adding hint %s: %s\n",
4037 ast_get_extension_name(e), ast_get_extension_app(e));
4040 ast_log(LOG_WARNING,
"Could not add devices for hint: %s@%s.\n",
4041 ast_get_extension_name(e),
4042 ast_get_context_name(ast_get_extension_context(e)));
4046 if (!(strstr(e->
app,
"${") && e->
exten[0] ==
'_')) {
4052 for (; (state_cb = ao2_iterator_next(&cb_iter));
ao2_ref(state_cb, -1)) {
4053 execute_state_callback(state_cb->
change_cb,
4054 ast_get_context_name(ast_get_extension_context(e)),
4055 ast_get_extension_name(e),
4074 if (!hint_change_message_type()) {
4094 struct ast_hint *hint;
4113 remove_hintdevice(hint);
4123 ast_log(LOG_WARNING,
"Could not add devices for hint: %s@%s.\n",
4124 ast_get_extension_name(ne),
4125 ast_get_context_name(ast_get_extension_context(ne)));
4137 int ast_get_hint(
char *hint,
int hintsize,
char *name,
int namesize,
struct ast_channel *c,
const char *context,
const char *exten)
4139 struct ast_exten *e = ast_hint_extension(c, context, exten);
4145 const char *tmp = ast_get_extension_app_data(e);
4157 struct ast_exten *e = ast_hint_extension(c, context, exten);
4164 ast_str_set(hint, hintsize,
"%s", ast_get_extension_app(e));
4167 const char *tmp = ast_get_extension_app_data(e);
4192 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
4197 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
4202 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
4211 ast_channel_lock(chan);
4220 if (context != ast_channel_context(chan)) {
4221 ast_channel_context_set(chan, context);
4223 ast_channel_exten_set(chan,
"h");
4224 ast_channel_priority_set(chan, 1);
4229 ast_channel_unlock(chan);
4233 ast_channel_exten(chan), ast_channel_priority(chan),
4235 ast_channel_caller(chan)->
id.
number.str, NULL), &found, 1);
4237 ast_channel_lock(chan);
4242 ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
4243 ast_channel_unlock(chan);
4245 if (found && spawn_error) {
4247 ast_debug(1,
"Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
4248 ast_channel_context(chan), ast_channel_exten(chan),
4249 ast_channel_priority(chan), ast_channel_name(chan));
4250 ast_verb(2,
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
4251 ast_channel_context(chan), ast_channel_exten(chan),
4252 ast_channel_priority(chan), ast_channel_name(chan));
4260 ast_channel_unlock(chan);
4266 ast_channel_lock(c);
4267 ast_channel_exten_set(c, exten);
4268 ast_channel_priority_set(c, pri);
4269 ast_channel_unlock(c);
4285 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4296 if (pos < buflen - 1) {
4317 if (ast_channel_pbx(c)) {
4318 ast_log(LOG_WARNING,
"%s already has PBX structure??\n", ast_channel_name(c));
4320 ast_free(ast_channel_pbx(c));
4323 return AST_PBX_FAILED;
4332 callid = ast_channel_callid(c);
4336 ast_channel_lock(c);
4338 ast_channel_unlock(c);
4345 ast_channel_pbx_set(c, pbx);
4350 ast_channel_lock(c);
4353 ast_channel_unlock(c);
4355 if (ast_strlen_zero(ast_channel_exten(c))) {
4357 ast_verb(2,
"Starting %s at %s,%s,%d failed so falling back to exten 's'\n", ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
4366 char dst_exten[256];
4373 dst_exten[pos] =
'\0';
4376 while (!(res =
ast_spawn_extension(c, ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
4377 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL),
4381 ast_channel_priority_set(c, ast_channel_priority(c) + 1);
4392 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4395 memset(ast_channel_whentohangup(c), 0,
sizeof(*ast_channel_whentohangup(c)));
4399 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4402 memset(ast_channel_whentohangup(c), 0,
sizeof(*ast_channel_whentohangup(c)));
4411 ast_debug(1,
"Extension %s, priority %d returned normally even though call was hung up\n",
4412 ast_channel_exten(c), ast_channel_priority(c));
4418 if (strchr(
"0123456789ABCDEF*#", res)) {
4419 ast_debug(1,
"Oooh, got something to jump out with ('%c')!\n", res);
4421 dst_exten[pos++] = digit = res;
4422 dst_exten[pos] =
'\0';
4424 ast_debug(1,
"Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4425 ast_verb(2,
"Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4429 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4434 pos = strlen(dst_exten);
4437 ast_debug(1,
"Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4438 ast_verb(2,
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4442 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4444 if (!strcmp(ast_channel_exten(c),
"e")) {
4445 ast_verb(2,
"Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
4459 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4462 memset(ast_channel_whentohangup(c), 0,
sizeof(*ast_channel_whentohangup(c)));
4466 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4469 memset(ast_channel_whentohangup(c), 0,
sizeof(*ast_channel_whentohangup(c)));
4488 || (ast_strlen_zero(dst_exten) &&
4490 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL)))) {
4497 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4498 ast_verb(3,
"Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
4499 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
4503 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4506 ast_log(LOG_WARNING,
"Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
4507 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
4518 else if (!autofallthrough)
4524 ast_verb(3,
"Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
4525 if (!strcasecmp(status,
"CONGESTION"))
4527 else if (!strcasecmp(status,
"CHANUNAVAIL"))
4529 else if (!strcasecmp(status,
"BUSY"))
4530 res = indicate_busy(c,
"10");
4535 if (
collect_digits(c, waittime, dst_exten,
sizeof(dst_exten), pos))
4541 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4545 if (!timeout && !ast_strlen_zero(dst_exten)) {
4548 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4549 ast_verb(3,
"Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
4553 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4556 ast_log(LOG_WARNING,
4557 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
4558 dst_exten, ast_channel_context(c));
4565 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4566 ast_verb(3,
"Timeout on %s\n", ast_channel_name(c));
4569 S_COR(ast_channel_caller(c)->
id.
number.valid, ast_channel_caller(c)->
id.
number.str, NULL))) {
4572 ast_log(LOG_WARNING,
4573 "Timeout, but no rule 't' or 'e' in context '%s'\n",
4574 ast_channel_context(c));
4583 if (!found && !error) {
4584 ast_log(LOG_WARNING,
"Don't know what to do with '%s'\n", ast_channel_name(c));
4592 ast_channel_caller(c)->
id.
number.str, NULL))) {
4598 ast_channel_lock(c);
4601 ast_channel_unlock(c);
4602 pbx_destroy(ast_channel_pbx(c));
4603 ast_channel_pbx_set(c, NULL);
4609 return AST_PBX_SUCCESS;
4621 #if defined(HAVE_SYSINFO)
4622 struct sysinfo sys_info;
4625 ast_mutex_lock(&maxcalllock);
4628 ast_log(LOG_WARNING,
"Maximum call limit of %d calls exceeded by '%s'!\n",
ast_option_maxcalls, ast_channel_name(c));
4633 getloadavg(&curloadavg, 1);
4635 ast_log(LOG_WARNING,
"Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n",
ast_option_maxload, ast_channel_name(c), curloadavg);
4639 #if defined(HAVE_SYSINFO)
4642 if (!sysinfo(&sys_info)) {
4645 uint64_t curfreemem = sys_info.freeram + sys_info.bufferram;
4646 curfreemem *= sys_info.mem_unit;
4647 curfreemem /= 1024 * 1024;
4649 ast_log(LOG_WARNING,
"Available system memory (~%" PRIu64
"MB) is below the configured low watermark (%ldMB)\n",
4661 ast_mutex_unlock(&maxcalllock);
4666 static void decrease_call_count(
void)
4668 ast_mutex_lock(&maxcalllock);
4671 ast_mutex_unlock(&maxcalllock);
4674 static void destroy_exten(
struct ast_exten *e)
4688 static void *pbx_thread(
void *data)
4701 decrease_call_count();
4713 ast_log(LOG_WARNING,
"Asked to start thread on NULL channel?\n");
4714 return AST_PBX_FAILED;
4718 ast_log(LOG_WARNING,
"PBX requires Asterisk to be fully booted\n");
4719 return AST_PBX_FAILED;
4723 return AST_PBX_CALL_LIMIT;
4726 if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
4727 ast_log(LOG_WARNING,
"Failed to create new channel thread\n");
4728 decrease_call_count();
4729 return AST_PBX_FAILED;
4732 return AST_PBX_SUCCESS;
4740 ast_log(LOG_WARNING,
"PBX requires Asterisk to be fully booted\n");
4741 return AST_PBX_FAILED;
4745 return AST_PBX_CALL_LIMIT;
4750 decrease_call_count();
4772 int oldval = autofallthrough;
4773 autofallthrough = newval;
4779 int oldval = extenpatternmatchnew;
4780 extenpatternmatchnew = newval;
4786 if (overrideswitch) {
4787 ast_free(overrideswitch);
4789 if (!ast_strlen_zero(newval)) {
4792 overrideswitch = NULL;
4867 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
4870 if (!strcmp(ast_get_include_name(i), include) &&
4871 (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) {
4874 ast_verb(3,
"Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
4924 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
4927 if (!strcmp(ast_get_switch_name(i), sw) &&
4928 !strcmp(ast_get_switch_data(i), data) &&
4929 (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) {
4932 ast_verb(3,
"Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
4950 return ast_context_remove_extension_callerid(context, extension, priority, NULL,
AST_EXT_MATCHCID_ANY, registrar);
4953 int ast_context_remove_extension_callerid(
const char *context,
const char *extension,
int priority,
const char *callerid,
int matchcallerid,
const char *
registrar)
4960 ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid,
4961 matchcallerid, registrar, 0);
4980 return ast_context_remove_extension_callerid2(con, extension, priority, NULL,
AST_EXT_MATCHCID_ANY, registrar, already_locked);
4983 int ast_context_remove_extension_callerid2(
struct ast_context *con,
const char *extension,
int priority,
const char *callerid,
int matchcallerid,
const char *registrar,
int already_locked)
4988 char dummy_name[1024];
4989 char dummy_cid[1024];
4994 if (!already_locked)
4998 ast_verb(3,
"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->
name, extension, priority, matchcallerid ?
"/" :
"", matchcallerid ? callerid :
"", registrar);
5000 #ifdef CONTEXT_DEBUG
5001 check_contexts(__FILE__, __LINE__);
5004 ex.exten = dummy_name;
5005 ext_strncpy(dummy_name, extension,
sizeof(dummy_name), 1);
5006 ex.matchcid = matchcallerid;
5008 ex.cidmatch = dummy_cid;
5009 ext_strncpy(dummy_cid, callerid,
sizeof(dummy_cid), 1);
5015 if (priority == 0) {
5018 ast_log(LOG_ERROR,
"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->
name);
5020 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5026 ast_log(LOG_WARNING,
"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
5030 ex.priority = priority;
5033 if (exten2->
label) {
5036 ast_log(LOG_ERROR,
"Did not remove this priority label (%d/%s) "
5037 "from the peer_label_table of context %s, extension %s!\n",
5044 ast_log(LOG_ERROR,
"Did not remove this priority (%d) from the "
5045 "peer_table of context %s, extension %s!\n",
5046 priority, con->
name, exten2->
name);
5048 if (exten2 == exten && exten2->
peer) {
5057 ast_log(LOG_ERROR,
"Did not remove this exten (%s) from the "
5058 "context root_table (%s) (priority %d)\n",
5062 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5070 ast_debug(3,
"Could not find priority %d of exten %s in context %s!\n",
5076 ast_log(LOG_WARNING,
"Cannot find extension %s in root_table in context %s\n",
5077 extension, con->
name);
5081 ast_log(LOG_NOTICE,
"match char tree after exten removal:\n");
5087 for (exten = con->
root; exten; prev_exten = exten, exten = exten->
next) {
5088 if (!strcmp(exten->
exten, ex.exten) &&
5090 (!ast_strlen_zero(ex.cidmatch) && !ast_strlen_zero(exten->
cidmatch) && !strcmp(exten->
cidmatch, ex.cidmatch)) ||
5091 (ast_strlen_zero(ex.cidmatch) && ast_strlen_zero(exten->
cidmatch)))) {
5097 if (!already_locked)
5103 for (peer = exten, next_peer = exten->
peer ? exten->
peer : exten->
next;
5104 peer && !strcmp(peer->
exten, ex.exten) &&
5105 (!callerid || (!matchcallerid && !peer->
matchcid) || (matchcallerid && peer->
matchcid && !strcmp(peer->
cidmatch, ex.cidmatch))) ;
5106 peer = next_peer, next_peer = next_peer ? (next_peer->
peer ? next_peer->
peer : next_peer->
next) : NULL) {
5108 if ((priority == 0 || peer->
priority == priority) &&
5109 (!registrar || !strcmp(peer->
registrar, registrar) )) {
5113 if (!previous_peer) {
5128 con->
root = next_node;
5130 prev_exten->
next = next_node;
5141 destroy_exten(peer);
5143 previous_peer =
peer;
5146 if (!already_locked)
5148 return found ? 0 : -1;
5158 struct ast_hint *hint;
5166 e->
command =
"core show hints";
5168 "Usage: core show hints\n"
5169 " List registered hints.\n"
5170 " Hint details are shown in five columns. In order from left to right, they are:\n"
5171 " 1. Hint extension URI.\n"
5172 " 2. List of mapped device or presence state identifiers.\n"
5173 " 3. Current extension state. The aggregate of mapped device states.\n"
5174 " 4. Current presence state for the mapped presence state provider.\n"
5175 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
5182 ast_cli(a->fd,
"There are no registered dialplan hints\n");
5186 ast_cli(a->fd,
"\n -= Registered Asterisk Dial Plan Hints =-\n");
5189 for (; (hint = ao2_iterator_next(&i));
ao2_ref(hint, -1)) {
5197 snprintf(buf,
sizeof(buf),
"%s@%s",
5198 ast_get_extension_name(hint->
exten),
5199 ast_get_context_name(ast_get_extension_context(hint->
exten)));
5201 ast_cli(a->fd,
"%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
5203 ast_get_extension_app(hint->
exten),
5213 ast_cli(a->fd,
"----------------\n");
5214 ast_cli(a->fd,
"- %d hints registered\n", num);
5221 struct ast_hint *hint;
5230 wordlen = strlen(word);
5234 for (; (hint = ao2_iterator_next(&i));
ao2_ref(hint, -1)) {
5241 if (!strncasecmp(word, ast_get_extension_name(hint->
exten), wordlen) && ++which > state) {
5257 struct ast_hint *hint;
5259 int num = 0, extenlen;
5265 e->
command =
"core show hint";
5267 "Usage: core show hint <exten>\n"
5268 " List registered hint.\n"
5269 " Hint details are shown in five columns. In order from left to right, they are:\n"
5270 " 1. Hint extension URI.\n"
5271 " 2. List of mapped device or presence state identifiers.\n"
5272 " 3. Current extension state. The aggregate of mapped device states.\n"
5273 " 4. Current presence state for the mapped presence state provider.\n"
5274 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
5281 return CLI_SHOWUSAGE;
5284 ast_cli(a->fd,
"There are no registered dialplan hints\n");
5288 extenlen = strlen(a->argv[3]);
5290 for (; (hint = ao2_iterator_next(&i));
ao2_ref(hint, -1)) {
5297 if (!strncasecmp(ast_get_extension_name(hint->
exten), a->argv[3], extenlen)) {
5299 sprintf(buf,
"%s@%s",
5300 ast_get_extension_name(hint->
exten),
5301 ast_get_context_name(ast_get_extension_context(hint->
exten)));
5302 ast_cli(a->fd,
"%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
5304 ast_get_extension_app(hint->
exten),
5314 ast_cli(a->fd,
"No hints matching extension %s\n", a->argv[3]);
5316 ast_cli(a->fd,
"%d hint%s matching extension %s\n", num, (num!=1 ?
"s":
""), a->argv[3]);
5340 const int blocks_max = 50000;
5341 long long int allocated = 0;
5354 e->
command =
"core eat memory";
5356 "Usage: core eat memory\n"
5357 " Eats all available memory so you can test if the system survives\n";
5363 blocks =
ast_malloc(
sizeof(
void*) * blocks_max);
5365 ast_log(LOG_ERROR,
"Already out of mem?\n");
5369 for (i = 0; sizes[i]; ++i) {
5370 int alloc_size = sizes[i];
5371 ast_log(LOG_WARNING,
"Allocating %d sized blocks (got %d blocks already)\n", alloc_size, blocks_pos);
5374 if (blocks_pos >= blocks_max) {
5375 ast_log(LOG_ERROR,
"Memory buffer too small? Run me again :)\n");
5384 blocks[blocks_pos++] = block;
5385 allocated += alloc_size;
5390 ast_log(LOG_WARNING,
"Allocated %lld bytes total!\n", allocated);
5398 static char *complete_show_dialplan_context(
const char *line,
const char *word,
int pos,
5412 wordlen = strlen(word);
5415 while ( (c = ast_walk_contexts(c)) ) {
5416 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
5433 int context_existence;
5434 int extension_existence;
5440 int prio = ast_get_extension_priority(e);
5442 snprintf(buf, buflen,
"hint: %s",
5443 ast_get_extension_app(e));
5445 snprintf(buf, buflen,
"%d. %s(%s)",
5446 prio, ast_get_extension_app(e),
5447 (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (
char *)ast_get_extension_app_data(e) :
""));
5455 ast_cli(fd,
" %-17s %-45s [%s:%d]\n",
5462 ast_cli(fd,
" %-17s %-45s [%s]\n",
5463 buf1, buf2, ast_get_extension_registrar(exten));
5467 static int show_dialplan_helper(
int fd,
const char *context,
const char *exten,
struct dialplan_counters *dpc,
const struct ast_include *rinclude,
int includecount,
const char *includes[])
5470 int res = 0, old_total_exten = dpc->total_exten;
5475 while ( (c = ast_walk_contexts(c)) ) {
5479 char buf[1024], buf2[1024];
5481 char buf[256], buf2[256];
5483 int context_info_printed = 0;
5485 if (context && strcmp(ast_get_context_name(c), context))
5488 dpc->context_existence = 1;
5499 dpc->total_context++;
5500 ast_cli(fd,
"[ Context '%s' created by '%s' ]\n",
5501 ast_get_context_name(c), ast_get_context_registrar(c));
5503 ast_cli(fd,
"Autohints support enabled\n");
5505 context_info_printed = 1;
5510 while ( (e = ast_walk_context_extensions(c, e)) ) {
5516 dpc->extension_existence = 1;
5519 if (!context_info_printed) {
5520 dpc->total_context++;
5522 ast_cli(fd,
"[ Included context '%s' created by '%s' ]\n",
5523 ast_get_context_name(c), ast_get_context_registrar(c));
5525 ast_cli(fd,
"[ Context '%s' created by '%s' ]\n",
5526 ast_get_context_name(c), ast_get_context_registrar(c));
5528 ast_cli(fd,
"Autohints support enabled\n");
5531 context_info_printed = 1;
5537 snprintf(buf,
sizeof(buf),
"'%s' (CID match '%s') => ", ast_get_extension_name(e), e->
cidmatch);
5539 snprintf(buf,
sizeof(buf),
"'%s' =>", ast_get_extension_name(e));
5548 while ( (p = ast_walk_extension_priorities(e, p)) ) {
5549 const char *el = ast_get_extension_label(p);
5552 snprintf(buf,
sizeof(buf),
" [%s]", el);
5562 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
5563 const struct ast_include *i = ast_context_includes_get(c, idx);
5565 snprintf(buf,
sizeof(buf),
"'%s'", ast_get_include_name(i));
5568 if (includecount >= AST_PBX_MAX_STACK) {
5569 ast_log(LOG_WARNING,
"Maximum include depth exceeded!\n");
5573 for (x = 0; x < includecount; x++) {
5574 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
5580 includes[includecount] = ast_get_include_name(i);
5581 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
5583 ast_log(LOG_WARNING,
"Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
5587 ast_cli(fd,
" Include => %-45s [%s]\n",
5588 buf, ast_get_include_registrar(i));
5593 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
5594 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
5595 const char *ipname = ast_get_ignorepat_name(ip);
5598 snprintf(buf,
sizeof(buf),
"'%s'", ipname);
5599 snprintf(ignorepat,
sizeof(ignorepat),
"_%s.", ipname);
5601 ast_cli(fd,
" Ignore pattern => %-45s [%s]\n",
5602 buf, ast_get_ignorepat_registrar(ip));
5606 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
5607 const struct ast_sw *sw = ast_context_switches_get(c, idx);
5609 snprintf(buf,
sizeof(buf),
"'%s/%s'",
5610 ast_get_switch_name(sw),
5611 ast_get_switch_data(sw));
5612 ast_cli(fd,
" Alt. Switch => %-45s [%s]\n",
5613 buf, ast_get_switch_registrar(sw));
5620 if (context_info_printed)
5625 return (dpc->total_exten == old_total_exten) ? -1 : res;
5628 static int show_debug_helper(
int fd,
const char *context,
const char *exten,
struct dialplan_counters *dpc,
struct ast_include *rinclude,
int includecount,
const char *includes[])
5631 int res = 0, old_total_exten = dpc->total_exten;
5633 ast_cli(fd,
"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
5635 ast_cli(fd,
"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
5636 ast_cli(fd,
" Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
5637 ast_cli(fd,
" <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
5638 ast_cli(fd,
" <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
5639 ast_cli(fd,
" [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
5640 ast_cli(fd,
" In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
5641 ast_cli(fd,
" are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
5645 while ( (c = ast_walk_contexts(c)) ) {
5646 int context_info_printed = 0;
5648 if (context && strcmp(ast_get_context_name(c), context))
5651 dpc->context_existence = 1;
5660 dpc->total_context++;
5661 ast_cli(fd,
"[ Context '%s' created by '%s' ]\n",
5662 ast_get_context_name(c), ast_get_context_registrar(c));
5663 context_info_printed = 1;
5669 ast_cli(fd,
"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
5675 if (context_info_printed)
5680 return (dpc->total_exten == old_total_exten) ? -1 : res;
5685 char *exten = NULL, *context = NULL;
5688 const char *incstack[AST_PBX_MAX_STACK];
5694 "Usage: dialplan show [[exten@]context]\n"
5698 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
5701 memset(&counters, 0,
sizeof(counters));
5703 if (a->argc != 2 && a->argc != 3)
5704 return CLI_SHOWUSAGE;
5708 if (strchr(a->argv[2],
'@')) {
5710 exten = strsep(&context,
"@");
5712 if (ast_strlen_zero(exten))
5717 if (ast_strlen_zero(context))
5721 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
5724 if (context && !counters.context_existence) {
5725 ast_cli(a->fd,
"There is no existence of '%s' context\n", context);
5729 if (exten && !counters.extension_existence) {
5731 ast_cli(a->fd,
"There is no existence of %s@%s extension\n",
5735 "There is no existence of '%s' extension in all contexts\n",
5740 ast_cli(a->fd,
"-= %d %s (%d %s) in %d %s. =-\n",
5741 counters.total_exten, counters.total_exten == 1 ?
"extension" :
"extensions",
5742 counters.total_prio, counters.total_prio == 1 ?
"priority" :
"priorities",
5743 counters.total_context, counters.total_context == 1 ?
"context" :
"contexts");
5752 char *exten = NULL, *context = NULL;
5755 const char *incstack[AST_PBX_MAX_STACK];
5759 e->
command =
"dialplan debug";
5761 "Usage: dialplan debug [context]\n"
5762 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
5765 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
5768 memset(&counters, 0,
sizeof(counters));
5770 if (a->argc != 2 && a->argc != 3)
5771 return CLI_SHOWUSAGE;
5776 if (strchr(a->argv[2],
'@')) {
5778 exten = strsep(&context,
"@");
5780 if (ast_strlen_zero(exten))
5785 if (ast_strlen_zero(context))
5789 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
5792 if (context && !counters.context_existence) {
5793 ast_cli(a->fd,
"There is no existence of '%s' context\n", context);
5798 ast_cli(a->fd,
"-= %d %s. =-\n",
5799 counters.total_context, counters.total_context == 1 ?
"context" :
"contexts");
5816 const char *actionidtext,
const char *context,
5819 int includecount,
const char *includes[])
5822 int res = 0, old_total_exten = dpc->total_exten;
5824 if (ast_strlen_zero(exten))
5826 if (ast_strlen_zero(context))
5829 ast_debug(3,
"manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
5834 ast_log(LOG_WARNING,
"Failed to lock contexts list for manager: listdialplan\n");
5839 while ( (c = ast_walk_contexts(c)) ) {
5843 if (context && strcmp(ast_get_context_name(c), context) != 0)
5846 dpc->context_existence = 1;
5847 dpc->total_context++;
5849 ast_debug(3,
"manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
5852 ast_debug(3,
"manager_show_dialplan: Failed to lock context\n");
5858 while ( (e = ast_walk_context_extensions(c, e)) ) {
5864 ast_debug(3,
"manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
5867 ast_debug(3,
"manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
5869 dpc->extension_existence = 1;
5874 while ( (p = ast_walk_extension_priorities(e, p)) ) {
5875 int prio = ast_get_extension_priority(p);
5878 if (!dpc->total_items++)
5880 astman_append(s,
"Event: ListDialplan\r\n%s", actionidtext);
5881 astman_append(s,
"Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
5884 if (ast_get_extension_label(p))
5885 astman_append(s,
"ExtensionLabel: %s\r\n", ast_get_extension_label(p));
5888 astman_append(s,
"Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
5890 astman_append(s,
"Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (
char *) ast_get_extension_app_data(p));
5892 astman_append(s,
"Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
5896 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
5897 const struct ast_include *i = ast_context_includes_get(c, idx);
5901 if (includecount >= AST_PBX_MAX_STACK) {
5902 ast_log(LOG_WARNING,
"Maximum include depth exceeded!\n");
5906 for (x = 0; x < includecount; x++) {
5907 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
5913 includes[includecount] = ast_get_include_name(i);
5916 ast_log(LOG_WARNING,
"Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
5920 if (!dpc->total_items++)
5922 astman_append(s,
"Event: ListDialplan\r\n%s", actionidtext);
5923 astman_append(s,
"Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
5925 ast_debug(3,
"manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
5929 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
5930 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
5931 const char *ipname = ast_get_ignorepat_name(ip);
5934 snprintf(ignorepat,
sizeof(ignorepat),
"_%s.", ipname);
5936 if (!dpc->total_items++)
5938 astman_append(s,
"Event: ListDialplan\r\n%s", actionidtext);
5939 astman_append(s,
"Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
5944 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
5945 const struct ast_sw *sw = ast_context_switches_get(c, idx);
5947 if (!dpc->total_items++)
5949 astman_append(s,
"Event: ListDialplan\r\n%s", actionidtext);
5950 astman_append(s,
"Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw));
5952 ast_debug(3,
"manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
5960 if (dpc->total_exten == old_total_exten) {
5961 ast_debug(3,
"manager_show_dialplan: Found nothing new\n");
5972 const char *exten, *context;
5974 const char *incstack[AST_PBX_MAX_STACK];
5980 if (!ast_strlen_zero(
id))
5981 snprintf(idtext,
sizeof(idtext),
"ActionID: %s\r\n",
id);
5985 memset(&counters, 0,
sizeof(counters));
5992 if (!ast_strlen_zero(context) && !counters.context_existence) {
5993 char errorbuf[BUFSIZ];
5995 snprintf(errorbuf,
sizeof(errorbuf),
"Did not find context %s", context);
5999 if (!ast_strlen_zero(exten) && !counters.extension_existence) {
6000 char errorbuf[BUFSIZ];
6002 if (!ast_strlen_zero(context))
6003 snprintf(errorbuf,
sizeof(errorbuf),
"Did not find extension %s@%s", exten, context);
6005 snprintf(errorbuf,
sizeof(errorbuf),
"Did not find extension %s in any context", exten);
6010 if (!counters.total_items) {
6016 "ListExtensions: %d\r\n"
6017 "ListPriorities: %d\r\n"
6018 "ListContexts: %d\r\n",
6019 counters.total_exten, counters.total_prio, counters.total_context);
6030 int i, j, exten, combined;
6034 e->
command =
"core show device2extenstate";
6036 "Usage: core show device2extenstate\n"
6037 " Lists device state to extension state combinations.\n";
6051 ast_cli(a->fd,
"\n");
6062 e->
command =
"dialplan set extenpatternmatchnew true";
6064 "Usage: dialplan set extenpatternmatchnew true|false\n"
6065 " Use the NEW extension pattern matching algorithm, true or false.\n";
6072 return CLI_SHOWUSAGE;
6077 ast_cli(a->fd,
"\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
6079 ast_cli(a->fd,
"\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
6090 e->
command =
"dialplan set extenpatternmatchnew false";
6092 "Usage: dialplan set extenpatternmatchnew true|false\n"
6093 " Use the NEW extension pattern matching algorithm, true or false.\n";
6100 return CLI_SHOWUSAGE;
6105 ast_cli(a->fd,
"\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
6107 ast_cli(a->fd,
"\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
6117 AST_CLI_DEFINE(handle_eat_memory,
"Eats all available memory"),
6122 AST_CLI_DEFINE(handle_show_device2extenstate,
"Show expected exten state from multiple device states"),
6124 AST_CLI_DEFINE(handle_show_dialplan,
"Show dialplan"),
6126 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew,
"Use the Old extension pattern matching algorithm."),
6127 AST_CLI_DEFINE(handle_set_extenpatternmatchnew,
"Use the New extension pattern matching algorithm."),
6133 struct ast_exten *eroot = NULL, *e = NULL;
6136 while ((context = ast_walk_contexts(context))) {
6137 while ((eroot = ast_walk_context_extensions(context, eroot))) {
6138 while ((e = ast_walk_extension_priorities(eroot, e))) {
6139 if (e->cached_app == app)
6140 e->cached_app = NULL;
6155 size_t name_bytes = strlen(name);
6156 size_t registrar_bytes = strlen(registrar);
6157 int length =
sizeof(
struct ast_context) + name_bytes + registrar_bytes + 2;
6159 if (!contexts_table) {
6162 if (!contexts_table) {
6167 ast_hashtab_hash_contexts,
6175 local_contexts = &contexts;
6183 local_contexts = extcontexts;
6193 tmp->
name = memcpy(&tmp->
data[0], name, name_bytes);
6194 tmp->
registrar = memcpy(&tmp->
data[name_bytes + 1], registrar, registrar_bytes);
6205 ast_assert(tmp->
name == &tmp->
data[0]);
6207 ast_log(LOG_ERROR,
"Danger! We failed to allocate a context for %s!\n", name);
6215 tmp->
next = *local_contexts;
6216 *local_contexts = tmp;
6217 ast_hashtab_insert_safe(contexts_table, tmp);
6220 tmp->
next = *local_contexts;
6224 *local_contexts = tmp;
6226 ast_debug(1,
"Registered extension context '%s'; registrar: %s\n", tmp->
name, registrar);
6242 int last_presence_state;
6243 char *last_presence_subtype;
6244 char *last_presence_message;
6252 static void context_merge_incls_swits_igps_other_registrars(
struct ast_context *
new,
struct ast_context *old,
const char *registrar)
6256 ast_debug(1,
"merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(
new), registrar);
6259 for (idx = 0; idx < ast_context_includes_count(old); idx++) {
6260 const struct ast_include *i = ast_context_includes_get(old, idx);
6262 if (!strcmp(ast_get_include_registrar(i), registrar)) {
6269 for (idx = 0; idx < ast_context_switches_count(old); idx++) {
6270 const struct ast_sw *sw = ast_context_switches_get(old, idx);
6272 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
6275 ast_context_add_switch2(
new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
6279 for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) {
6280 const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx);
6282 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) {
6285 ast_context_add_ignorepat2(
new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
6298 iter = ast_hashtab_start_traversal(table);
6300 size_t name_len = strlen(con->
name) + 1;
6301 size_t registrar_len = strlen(con->
registrar) + 1;
6320 ast_verb(3,
"Enabled autohints support on context '%s'\n", con->
name);
6330 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
6333 int insert_count = 0;
6342 exten_iter = ast_hashtab_start_traversal(context->
root_table);
6347 new_exten_item = NULL;
6349 prio_iter = ast_hashtab_start_traversal(exten_item->
peer_table);
6354 if (new_exten_item) {
6357 new_prio_item = NULL;
6359 if (strcmp(prio_item->
registrar,registrar) == 0) {
6372 context_merge_incls_swits_igps_other_registrars(
new, context, registrar);
6377 ast_log(LOG_ERROR,
"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->
name);
6390 if (!res1 && new_exten_item && new_prio_item){
6391 ast_verb(3,
"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
6406 context_merge_incls_swits_igps_other_registrars(
new, context, registrar);
6409 if (!insert_count && !
new && (strcmp(context->
registrar, registrar) != 0 ||
6420 context_merge_incls_swits_igps_other_registrars(
new, context, registrar);
6435 struct ast_hint *hint;
6442 struct timeval begintime;
6443 struct timeval writelocktime;
6444 struct timeval endlocktime;
6445 struct timeval enddeltime;
6463 if (!contexts_table) {
6468 contexts_table = exttable;
6469 contexts = *extcontexts;
6475 iter = ast_hashtab_start_traversal(contexts_table);
6478 context_merge(extcontexts, exttable, tmp, registrar);
6487 for (; (hint = ao2_iterator_next(&i));
ao2_ref(hint, -1)) {
6500 +
sizeof(*saved_hint);
6515 saved_hint->laststate = hint->
laststate;
6516 saved_hint->context = saved_hint->data;
6518 saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
6534 oldtable = contexts_table;
6535 oldcontextslist = contexts;
6538 contexts_table = exttable;
6539 contexts = *extcontexts;
6548 exten = pbx_find_extension(NULL, NULL, &q, saved_hint->context, saved_hint->exten,
6555 if (exten && exten->
exten[0] ==
'_') {
6556 ast_add_extension_nolock(exten->
parent->
name, 0, saved_hint->exten,
6565 hint = exten ? ao2_find(hints, exten, 0) : NULL;
6579 hint->
laststate = saved_hint->laststate;
6589 ast_free(saved_hint);
6606 execute_state_callback(thiscb->
change_cb,
6607 saved_hint->context,
6616 ast_free(saved_hint->last_presence_subtype);
6617 ast_free(saved_hint->last_presence_message);
6618 ast_free(saved_hint);
6632 for (tmp = oldcontextslist; tmp; ) {
6636 __ast_internal_context_destroy(tmp);
6643 ast_verb(5,
"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
6647 ast_verb(5,
"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
6651 ast_verb(5,
"Time to delete the old dialplan: %8.6f sec\n", ft);
6655 ast_verb(5,
"Total time merge_contexts_delete: %8.6f sec\n", ft);
6656 ast_verb(5,
"%s successfully loaded %d contexts (enable debug for details).\n", registrar, ctx_count);
6685 const char *registrar)
6699 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
6700 const struct ast_include *i = ast_context_includes_get(con, idx);
6702 if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) {
6716 ast_debug(1,
"Including context '%s' in context '%s'\n",
6717 ast_get_include_name(new_include), ast_get_context_name(con));
6750 const char *data,
int eval,
const char *registrar)
6756 if (!(new_sw = sw_alloc(value, data, eval, registrar))) {
6764 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
6765 const struct ast_sw *i = ast_context_switches_get(con, idx);
6767 if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) &&
6768 !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) {
6783 ast_verb(3,
"Including switch '%s/%s' in context '%s'\n",
6784 ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con));
6802 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
6808 int ast_context_remove_ignorepat2(
struct ast_context *con,
const char *ignorepat,
const char *registrar)
6814 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6817 if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) &&
6818 (!registrar || (registrar == ast_get_ignorepat_registrar(ip)))) {
6842 ret = ast_context_add_ignorepat2(c, value, registrar);
6848 int ast_context_add_ignorepat2(
struct ast_context *con,
const char *value,
const char *registrar)
6850 struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar);
6858 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6859 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
6861 if (!strcasecmp(ast_get_ignorepat_name(i), value)) {
6864 ignorepat_free(ignorepat);
6870 ignorepat_free(ignorepat);
6889 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6890 const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx);
6908 static int ast_add_extension_nolock(
const char *context,
int replace,
const char *extension,
6909 int priority,
const char *label,
const char *callerid,
6910 const char *application,
void *data,
void (*datad)(
void *),
const char *registrar)
6918 application, data, datad, registrar, NULL, 0, 1);
6929 int priority,
const char *label,
const char *callerid,
6930 const char *application,
void *data,
void (*datad)(
void *),
const char *registrar)
6938 application, data, datad, registrar, NULL, 0);
6950 ast_channel_lock(chan);
6952 if (!ast_strlen_zero(context))
6953 ast_channel_context_set(chan, context);
6954 if (!ast_strlen_zero(exten))
6955 ast_channel_exten_set(chan, exten);
6956 if (priority > -1) {
6961 ast_channel_priority_set(chan, priority);
6964 ast_channel_unlock(chan);
6973 ast_channel_lock(chan);
6981 ast_channel_unlock(chan);
6984 ast_channel_unlock(chan);
6989 ast_log(LOG_WARNING,
"Unable to gain control of channel %s\n", ast_channel_name(chan));
6995 ast_log(LOG_WARNING,
"Unable to start PBX on %s\n", ast_channel_name(newchan));
7026 static unsigned int ext_strncpy(
char *dst,
const char *src,
size_t dst_size,
int nofluff)
7029 unsigned int insquares;
7030 unsigned int is_pattern;
7039 is_pattern = *src ==
'_';
7040 while (*src && count < dst_size) {
7045 }
else if (*src ==
']') {
7047 }
else if (*src ==
' ' && !insquares) {
7050 }
else if (*src ==
'-' && !insquares && nofluff) {
7072 int repeated_label = 0;
7074 for (ep = NULL; e ; ep = e, e = e->
peer) {
7075 if (e->label && tmp->
label && e->priority != tmp->
priority && !strcmp(e->label, tmp->
label)) {
7076 if (strcmp(e->name, tmp->
name)) {
7077 ast_log(LOG_WARNING,
7078 "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
7081 ast_log(LOG_WARNING,
7082 "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
7087 if (e->priority >= tmp->
priority) {
7092 if (repeated_label) {
7097 ast_hashtab_insert_safe(eh->
peer_table, tmp);
7105 if (e->priority == tmp->
priority) {
7109 if (strcmp(e->name, tmp->
name)) {
7110 ast_log(LOG_WARNING,
7111 "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
7114 ast_log(LOG_WARNING,
7115 "Unable to register extension '%s' priority %d in '%s', already in use\n",
7140 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7144 ast_hashtab_insert_safe(tmp->
peer_table,tmp);
7153 ast_hashtab_insert_safe(con->
root_table, tmp);
7161 ast_log(LOG_ERROR,
"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7165 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7167 ast_hashtab_insert_safe(con->
root_table, tmp);
7171 ast_hashtab_insert_safe(tmp->
peer_table, tmp);
7180 ast_hashtab_insert_safe(con->
root_table, tmp);
7188 ast_log(LOG_ERROR,
"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7205 ast_hashtab_insert_safe(eh->
peer_table, tmp);
7211 e->peer_label_table = 0;
7212 ast_hashtab_insert_safe(tmp->
peer_table, tmp);
7217 ast_hashtab_insert_safe(con->
root_table, tmp);
7258 int replace,
const char *extension,
int priority,
const char *label,
const char *callerid,
7259 const char *application,
void *data,
void (*datad)(
void *),
7260 const char *registrar,
const char *registrar_file,
int registrar_line)
7263 application, data, datad, registrar, registrar_file, registrar_line, 1);
7267 int replace,
const char *extension,
int priority,
const char *label,
const char *callerid,
7268 const char *application,
void *data,
void (*datad)(
void *),
7269 const char *registrar,
const char *registrar_file,
int registrar_line)
7272 application, data, datad, registrar, registrar_file, registrar_line, 0);
7284 int replace,
const char *extension,
int priority,
const char *label,
const char *callerid,
7285 const char *application,
void *data,
void (*datad)(
void *),
7286 const char *registrar,
const char *registrar_file,
int registrar_line,
int lock_context)
7294 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
7298 char expand_buf[VAR_BUF_SIZE];
7300 char dummy_name[1024];
7304 if (ast_strlen_zero(extension)) {
7305 ast_log(LOG_ERROR,
"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
7315 if (priority ==
PRIORITY_HINT && strstr(application,
"${") && extension[0] !=
'_') {
7320 ast_channel_exten_set(c, extension);
7321 ast_channel_context_set(c, con->
name);
7330 pbx_substitute_variables_helper(c, application, expand_buf,
sizeof(expand_buf));
7331 if (0 < inhibited) {
7335 application = expand_buf;
7346 exten_fluff = ext_fluff_count(extension);
7349 callerid_fluff = callerid ? ext_fluff_count(callerid) : 0;
7352 length += strlen(extension) + 1;
7354 length += strlen(extension) + 1 - exten_fluff;
7356 length += strlen(application) + 1;
7358 length += strlen(label) + 1;
7361 length += strlen(callerid) + 1;
7362 if (callerid_fluff) {
7363 length += strlen(callerid) + 1 - callerid_fluff;
7368 if (registrar_file) {
7369 length += strlen(registrar_file) + 1;
7382 if (ast_strlen_zero(label))
7390 p += strlen(label) + 1;
7393 p +=
ext_strncpy(p, extension, strlen(extension) + 1, 0);
7396 p +=
ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
7406 p +=
ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
7407 if (callerid_fluff) {
7409 p +=
ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
7417 if (registrar_file) {
7419 strcpy(p, registrar_file);
7420 p += strlen(registrar_file) + 1;
7426 strcpy(p, application);
7440 dummy_exten.
exten = dummy_name;
7446 add_exten_to_pattern_tree(con, tmp, 0);
7447 ast_hashtab_insert_safe(con->
root_table, tmp);
7451 for (e = con->
root; e; el = e, e = e->
next) {
7466 if (e && res == 0) {
7470 struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
7502 hashtab_compare_exten_numbers,
7505 hashtab_hash_priority,
7508 hashtab_compare_exten_labels,
7511 hashtab_hash_labels,
7519 hashtab_compare_extens,
7522 hashtab_hash_extens,
7530 ast_hashtab_insert_safe(tmp->
peer_table, tmp);
7531 ast_hashtab_insert_safe(con->
root_table, tmp);
7540 if (DEBUG_ATLEAST(1)) {
7542 ast_log(LOG_DEBUG,
"Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
7545 ast_log(LOG_DEBUG,
"Added extension '%s' priority %d to %s (%p)\n",
7572 unsigned int dialed:1;
7574 unsigned int in_separate_thread:1;
7582 if (outgoing->
dial) {
7586 ast_cond_destroy(&outgoing->
cond);
7600 if (
outgoing->in_separate_thread) {
7625 ast_channel_name(chan));
7628 ast_log(LOG_WARNING,
"No such application '%s'\n",
outgoing->
app);
7646 ast_log(LOG_ERROR,
"Failed to start PBX on %s\n", ast_channel_name(chan));
7667 ast_verb(4,
"Treating progress as answer on '%s' due to early media option\n",
7668 ast_channel_name(channel));
7693 case AST_CAUSE_USER_BUSY:
7696 case AST_CAUSE_CALL_REJECTED:
7697 case AST_CAUSE_NETWORK_OUT_OF_ORDER:
7698 case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
7699 case AST_CAUSE_NORMAL_TEMPORARY_FAILURE:
7700 case AST_CAUSE_SWITCH_CONGESTION:
7701 case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
7704 case AST_CAUSE_ANSWERED_ELSEWHERE:
7705 case AST_CAUSE_NO_ANSWER:
7709 case AST_CAUSE_UNALLOCATED:
7720 static int pbx_outgoing_attempt(
const char *type,
struct ast_format_cap *cap,
7721 const char *addr,
int timeout,
const char *context,
const char *exten,
int priority,
7722 const char *app,
const char *appdata,
int *reason,
int synchronous,
7723 const char *cid_num,
const char *cid_name,
struct ast_variable *vars,
7724 const char *account,
struct ast_channel **locked_channel,
int early_media,
7730 char tmp_cid_name[128];
7731 char tmp_cid_num[128];
7737 ast_cond_init(&
outgoing->cond, NULL);
7739 if (!ast_strlen_zero(app)) {
7758 if (!ast_strlen_zero(predial_callee)) {
7764 if (synchronous && reason) {
7776 ast_channel_lock(dialed);
7780 if (!ast_strlen_zero(account)) {
7782 ast_channel_accountcode_set(dialed, account);
7783 ast_channel_peeraccount_set(dialed, account);
7788 if (!ast_strlen_zero(predial_callee)) {
7795 tmp =
S_COR(ast_channel_caller(dialed)->
id.
number.valid, ast_channel_caller(dialed)->
id.
number.str, NULL);
7798 cid_num = tmp_cid_num;
7800 tmp =
S_COR(ast_channel_caller(dialed)->
id.name.valid, ast_channel_caller(dialed)->
id.name.str, NULL);
7803 cid_name = tmp_cid_name;
7806 ast_channel_unlock(dialed);
7808 if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
7822 if (!ast_strlen_zero(cid_num)) {
7823 connected.id.number.valid = 1;
7824 connected.id.number.str = (
char *) cid_num;
7825 connected.id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
7827 if (!ast_strlen_zero(cid_name)) {
7828 connected.id.name.valid = 1;
7829 connected.id.name.str = (
char *) cid_name;
7830 connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
7839 if (locked_channel) {
7852 ast_channel_lock(dialed);
7870 ast_log(LOG_WARNING,
"Unable to spawn dialing thread for '%s/%s'\n", type, addr);
7872 if (locked_channel) {
7874 ast_channel_unlock(dialed);
7900 if (locked_channel) {
7905 if (locked_channel) {
7906 ast_channel_lock(dialed);
7910 if (locked_channel) {
7911 *locked_channel = dialed;
7917 int timeout,
const char *context,
const char *exten,
int priority,
int *reason,
7918 int synchronous,
const char *cid_num,
const char *cid_name,
struct ast_variable *vars,
7919 const char *account,
struct ast_channel **locked_channel,
int early_media,
7923 synchronous, cid_num, cid_name, vars, account, locked_channel, early_media, assignedids, NULL);
7927 int timeout,
const char *context,
const char *exten,
int priority,
int *reason,
7928 int synchronous,
const char *cid_num,
const char *cid_name,
struct ast_variable *vars,
7929 const char *account,
struct ast_channel **locked_channel,
int early_media,
7936 reason = &my_reason;
7939 if (locked_channel) {
7940 *locked_channel = NULL;
7943 res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
7944 NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
7945 early_media, assignedids, predial_callee);
7953 ast_assert(!locked_channel || !*locked_channel);
7960 "failed", context, NULL, NULL, 0,
"OutgoingSpoolFailed");
7962 char failed_reason[12];
7965 snprintf(failed_reason,
sizeof(failed_reason),
"%d", *reason);
7967 ast_channel_unlock(failed);
7970 ast_log(LOG_ERROR,
"Unable to run PBX on '%s'\n",
7971 ast_channel_name(failed));
7981 int timeout,
const char *app,
const char *appdata,
int *reason,
int synchronous,
7982 const char *cid_num,
const char *cid_name,
struct ast_variable *vars,
7983 const char *account,
struct ast_channel **locked_channel,
7986 return ast_pbx_outgoing_app_predial(type, cap, addr, timeout, app, appdata, reason, synchronous,
7987 cid_num, cid_name, vars, account, locked_channel, assignedids, NULL);
7990 int ast_pbx_outgoing_app_predial(
const char *type,
struct ast_format_cap *cap,
const char *addr,
7991 int timeout,
const char *app,
const char *appdata,
int *reason,
int synchronous,
7992 const char *cid_num,
const char *cid_name,
struct ast_variable *vars,
7993 const char *account,
struct ast_channel **locked_channel,
7999 if (locked_channel) {
8000 *locked_channel = NULL;
8002 if (ast_strlen_zero(app)) {
8006 return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
8007 reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
8008 assignedids, predial_callee);
8015 static void __ast_internal_context_destroy(
struct ast_context *con)
8040 for (e = tmp->
root; e;) {
8041 for (en = e->
peer; en;) {
8051 ast_rwlock_destroy(&tmp->
lock);
8059 struct ast_exten *exten_item, *prio_item;
8061 for (tmp = list; tmp; ) {
8069 for (; tmp; tmpl = tmp, tmp = tmp->
next) {
8070 ast_debug(1,
"check ctx %s %s\n", tmp->name, tmp->registrar);
8071 if ( !strcasecmp(tmp->name, con->
name) ) {
8088 for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) {
8091 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
8097 for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) {
8100 if (!strcmp(ast_get_include_registrar(i), registrar)) {
8106 for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) {
8109 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
8115 if (tmp->root_table) {
8116 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
8118 int end_traversal = 1;
8129 prio_iter = ast_hashtab_start_traversal(exten_item->
peer_table);
8136 ast_verb(5,
"Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
8142 end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->
priority, cidmatch, prio_item->
matchcid, NULL, 1);
8152 if (end_traversal) {
8155 ast_free(prio_iter);
8164 if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && !ast_context_switches_count(tmp)) {
8165 ast_debug(1,
"delete ctx %s %s\n", tmp->name, tmp->registrar);
8176 __ast_internal_context_destroy(tmp);
8178 ast_debug(1,
"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
8179 tmp->refcount, tmp->root);
8185 ast_verb(3,
"Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
8186 ast_debug(1,
"delete ctx %s %s\n", tmp->name, tmp->registrar);
8197 __ast_internal_context_destroy(tmp);
8201 tmp = con ? NULL : next;
8224 __ast_context_destroy(contexts, contexts_table, con,registrar);
8228 void wait_for_hangup(
struct ast_channel *chan,
const void *data)
8235 if (ast_strlen_zero(data) || (sscanf(data,
"%30lg", &waitsec) != 1) || (waitsec < 0))
8238 waittime = waitsec * 1000.0;
8253 static int testtime_write(
struct ast_channel *chan,
const char *cmd,
char *var,
const char *value)
8257 char *remainder, result[30], timezone[80];
8266 if (!(remainder =
ast_strptime(value,
"%Y/%m/%d %H:%M:%S", &tm))) {
8269 sscanf(remainder,
"%79s", timezone);
8272 snprintf(result,
sizeof(result),
"%ld", (
long) tv.tv_sec);
8279 .write = testtime_write,
8285 if (ast_strlen_zero(condition)) {
8287 }
else if (sscanf(condition,
"%30d", &res) == 1) {
8297 struct ast_str *hint_app = NULL;
8318 cmpdevice =
ast_alloca(
sizeof(*cmpdevice) + strlen(presence_state->provider));
8319 strcpy(cmpdevice->
hintdevice, presence_state->provider);
8322 dev_iter = ao2_t_callback(hintdevices,
8326 "find devices in container");
8333 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1,
"Next device")) {
8335 presence_state_notify_callbacks(device->
hint, &hint_app, presence_state);
8344 static int action_extensionstatelist(
struct mansession *s,
const struct message *m)
8347 struct ast_hint *hint;
8360 for (; (hint = ao2_iterator_next(&it_hints));
ao2_ref(hint, -1)) {
8376 if (!ast_strlen_zero(action_id)) {
8384 "StatusText: %s\r\n\r\n",
8409 static void unload_pbx(
void)
8428 ast_verb(1,
"Asterisk PBX Core Initializing\n");
8430 ast_verb(5,
"Registering builtin functions:\n");
8465 return ast_mutex_lock(&
conlock);
8470 return ast_mutex_lock(&
conlock);
8475 return ast_mutex_unlock(&
conlock);
8483 return ast_rwlock_wrlock(&con->
lock);
8488 return ast_rwlock_rdlock(&con->
lock);
8493 return ast_rwlock_unlock(&con->
lock);
8499 const char *ast_get_context_name(
struct ast_context *con)
8501 return con ? con->
name : NULL;
8506 return exten ? exten->
parent : NULL;
8509 const char *ast_get_extension_name(
struct ast_exten *exten)
8511 return exten ? exten->
name : NULL;
8514 const char *ast_get_extension_label(
struct ast_exten *exten)
8516 return exten ? exten->
label : NULL;
8519 int ast_get_extension_priority(
struct ast_exten *exten)
8521 return exten ? exten->
priority : -1;
8527 const char *ast_get_context_registrar(
struct ast_context *c)
8532 const char *ast_get_extension_registrar(
struct ast_exten *e)
8547 int ast_get_extension_matchcid(
struct ast_exten *e)
8552 const char *ast_get_extension_cidmatch(
struct ast_exten *e)
8557 const char *ast_get_extension_app(
struct ast_exten *e)
8559 return e ? e->
app : NULL;
8562 void *ast_get_extension_app_data(
struct ast_exten *e)
8564 return e ? e->
data : NULL;
8568 const char *context,
const char *exten,
int priority)
8573 e = pbx_find_extension(c, NULL, &q, context, exten, priority, NULL,
"", E_MATCH);
8576 const char *tmp = ast_get_extension_app_data(e);
8593 return con ? con->
next : contexts;
8600 return con ? con->
root : NULL;
8612 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
8613 const struct ast_sw *s = ast_context_switches_get(con, idx);
8627 if (!ast_context_switches_count(con)) {
8631 return ast_context_switches_get(con, 0);
8634 int ast_context_switches_count(
const struct ast_context *con)
8639 const struct ast_sw *ast_context_switches_get(
const struct ast_context *con,
int idx)
8647 return priority ? priority->
peer :
exten;
8657 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
8664 if (inc == include) {
8672 if (!ast_context_includes_count(con)) {
8676 return ast_context_includes_get(con, 0);
8679 int ast_context_includes_count(
const struct ast_context *con)
8700 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
8701 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
8715 if (!ast_context_ignorepats_count(con)) {
8719 return ast_context_ignorepats_get(con, 0);
8722 int ast_context_ignorepats_count(
const struct ast_context *con)
8736 int includecount = ast_context_includes_count(con);
8738 if (includecount >= AST_PBX_MAX_STACK) {
8739 ast_log(LOG_WARNING,
"Context %s contains too many includes (%d). Maximum is %d.\n",
8740 ast_get_context_name(con), includecount, AST_PBX_MAX_STACK);
8743 for (idx = 0; idx < includecount; idx++) {
8744 const struct ast_include *inc = ast_context_includes_get(con, idx);
8751 ast_log(LOG_WARNING,
"Context '%s' tries to include nonexistent context '%s'\n",
8752 ast_get_context_name(con), include_rname(inc));
8760 static int __ast_goto_if_exists(
struct ast_channel *chan,
const char *context,
const char *exten,
int priority,
int async)
8767 if (context == NULL)
8768 context = ast_channel_context(chan);
8770 exten = ast_channel_exten(chan);
8774 S_COR(ast_channel_caller(chan)->
id.
number.valid, ast_channel_caller(chan)->
id.
number.str, NULL)))
8775 return goto_func(chan, context, exten, priority);
8777 return AST_PBX_GOTO_FAILED;
8783 return __ast_goto_if_exists(chan, context, exten, priority, 0);
8788 return __ast_goto_if_exists(chan, context, exten, priority, 1);
8800 }
else if (!*prip) {
8803 *extenp = *contextp;
8806 context = *contextp;
8813 }
else if (*pri ==
'-') {
8818 if ((rest && sscanf(pri,
"%30d%1s", ipri, rest) != 1) || sscanf(pri,
"%30d", ipri) != 1) {
8820 exten ? exten : ast_channel_exten(chan), pri,
8821 S_COR(ast_channel_caller(chan)->
id.
number.valid, ast_channel_caller(chan)->
id.
number.str, NULL));
8823 ast_log(LOG_WARNING,
"Priority '%s' must be a number > 0, or valid label\n", pri);
8832 static int pbx_parseable_goto(
struct ast_channel *chan,
const char *goto_string,
int async)
8840 if (ast_strlen_zero(goto_string)) {
8841 ast_log(LOG_WARNING,
"Goto requires an argument ([[context,]extension,]priority)\n");
8845 context = strsep(&stringp,
",");
8846 exten = strsep(&stringp,
",");
8847 pri = strsep(&stringp,
",");
8855 ipri = ast_channel_priority(chan) + (ipri * mode);
8868 return pbx_parseable_goto(chan, goto_string, 0);
8873 return pbx_parseable_goto(chan, goto_string, 1);
8876 static int hint_hash(
const void *obj,
const int flags)
8878 const struct ast_hint *hint = obj;
8882 exten_name = ast_get_extension_name(hint->
exten);
8883 if (ast_strlen_zero(exten_name)) {
8896 static int hint_cmp(
void *obj,
void *arg,
int flags)
8898 const struct ast_hint *hint = obj;
8904 static int statecbs_cmp(
void *obj,
void *arg,
int flags)
8916 static void pbx_shutdown(
void)
8941 if (contexts_table) {
8946 static void print_hints_key(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
8948 struct ast_hint *hint = v_obj;
8953 prnt(where,
"%s@%s", ast_get_extension_name(hint->
exten),
8954 ast_get_context_name(ast_get_extension_context(hint->
exten)));
8957 static void print_hintdevices_key(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
8964 prnt(where,
"%s => %s@%s", hintdevice->
hintdevice,
8965 ast_get_extension_name(hintdevice->
hint->
exten),
8966 ast_get_context_name(ast_get_extension_context(hintdevice->
hint->
exten)));
8969 static void print_autohint_key(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
8976 prnt(where,
"%s", autohint->
context);
8979 static void print_statecbs_key(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
8986 prnt(where,
"%d", state_cb->
id);
8992 HASH_EXTENHINT_SIZE, hint_hash, NULL, hint_cmp);
9021 return (hints && hintdevices && autohints && statecbs) ? 0 : -1;
static void manager_dpsendack(struct mansession *s, const struct message *m)
Send ack once.
ast_include: include= support in extensions.conf
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
Launch a new extension (i.e. new stack)
Options for ast_pbx_run()
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
const char * ast_get_extension_registrar_file(struct ast_exten *e)
Get name of configuration file used by registrar to register this extension.
Main Channel structure associated with a channel.
ast_device_state
Device States.
int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
This function locks given context, removes switch, unlock context and return.
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
void( ao2_prnt_fn)(void *where, const char *fmt,...)
Print output.
int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data)
Enables an option globally.
Asterisk locking-related definitions:
ast_extension_states
Extension states.
void astman_append(struct mansession *s, const char *fmt,...)
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
int ast_unlock_context(struct ast_context *con)
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Private include file for pbx.
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
static int ast_add_hint(struct ast_exten *e)
Add hint to hint list, check initial extension state.
int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
Uses hint and presence state callback to get the presence state of an extension.
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
static char * handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Send ack once.
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
Change hint for an extension.
Main dialing structure. Contains global options, channels being dialed, and more! ...
struct ast_include * include_alloc(const char *value, const char *registrar)
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
static int ast_add_extension2_lockopt(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line, int lock_context)
Same as ast_add_extension2() but controls the context locking.
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
void include_free(struct ast_include *inc)
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout)
Set the maximum time (globally) allowed for trying to ring phones.
#define ast_channel_unref(c)
Decrease channel reference count.
The arg parameter is a search key, but is not an object.
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation...
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
void ast_context_set_autohints(struct ast_context *con, int enabled)
Enable or disable autohints support on a context.
int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
Locks context, remove included contexts, unlocks context. When we call this function, &conlock lock must be locked, because when we giving *con argument, some process can remove/change this context and after that there can be segfault.
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Time-related functions and macros.
int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and execute an application on the channel...
int pbx_set_extenpatternmatchnew(int newval)
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Check extension state for an extension by using hint.
static void show_dialplan_helper_extension_output(int fd, char *buf1, char *buf2, struct ast_exten *exten)
Writes CLI output of a single extension for show dialplan.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
char context[AST_MAX_CONTEXT]
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
descriptor for a cli entry.
static int publish_hint_remove(struct ast_hint *hint)
Publish a hint removed event.
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
static struct stasis_subscription * presence_state_sub
Subscription for presence state change events.
static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
add hintdevice structure and link it into the container.
struct ast_app * cached_app
ast_state_cb: An extension state notify register item
char * appdata
Application data to pass to application.
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
Remove a switch.
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
void * ast_hashtab_next(struct ast_hashtab_iter *it)
Gets the next object in the list, advances iter one step returns null on end of traversal.
Structure for variables, used for configurations and for channel variables.
static char * handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handle_show_hints: CLI support for listing registered dial plan hints
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
adds a list of channel variables to a channel
static struct ao2_container * hintdevices
Container for hint devices.
int dial_res
Result of the dial operation when dialed is set.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
struct ast_context * ast_context_find(const char *name)
Find a context.
int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten, struct ao2_container **device_state_info)
Check extended extension state for an extension by using hint.
static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, struct ast_pbx_args *args)
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Structure to pass both assignedid values to channel drivers.
char context[1]
Name of the context.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Structure for a data store type.
ast_channel_state
ast_channel states
const ast_string_field exten
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
#define AST_VECTOR_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
const ast_string_field app
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct ast_hint * hint
Hint this hintdevice belongs to.
int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Main interface to add extensions to the list for out context.
ast_control_frame_type
Internal control frame subtype field values.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
struct ast_channel * ast_channel_yank(struct ast_channel *yankee)
Gain control of a channel in the system.
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Stasis message payload representing a presence state update.
static ast_mutex_t context_merge_lock
Lock to hold off restructuring of hints by ast_merge_contexts_and_delete.
double ast_option_maxload
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
ast_cond_t cond
Condition for synchronous dialing.
static enum ast_control_frame_type pbx_dial_reason(enum ast_dial_result dial_result, int cause)
Attempt to convert disconnect cause to old originate reason.
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
struct ast_hashtab * peer_table
int ast_rdlock_contexts(void)
Read locks the context list.
static struct ao2_container * hints
void ast_free_ptr(void *ptr)
free() wrapper
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
const ast_string_field context
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
Get hint for channel.
ast_state_cb_type change_cb
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
static char * handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handle_show_hint: CLI support for listing registered dial plan hint
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
int ast_extension_cmp(const char *a, const char *b)
Determine if one extension should match before another.
struct ast_context * next
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
const ast_string_field exten
int indicate_congestion(struct ast_channel *chan, const char *data)
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void ast_dial_set_state_callback(struct ast_dial *dial, ast_dial_state_callback callback)
Set a callback for state changes.
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
int ast_wrlock_contexts(void)
Write locks the context list.
Configuration File Parser.
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
static void * pbx_outgoing_exec(void *data)
Internal function which dials an outgoing leg and sends it to a provided extension or application...
const char * registrar_file
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
#define ast_hashtab_insert_immediate(tab, obj)
Insert without checking.
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
ast_dial_result
List of return codes for dial run API calls.
ast_sw: Switch statement in extensions.conf
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
Check state of extension by using hints.
int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
General Asterisk PBX channel definitions.
int raise_exception(struct ast_channel *chan, const char *reason, int priority)
int priority
Dialplan priority.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
static int increase_call_count(const struct ast_channel *c)
Increase call count for channel.
Asterisk file paths, configured in asterisk.conf.
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
ast_state_cb_update_reason
const ast_string_field reason
const struct ast_eid * eid
The EID of the server where this message originated.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
#define ast_strdupa(s)
duplicate a string in memory from the stack
static int ext_cmp_pattern_pos(const char **p, unsigned char *bitwise)
helper functions to sort extension patterns in the desired way, so that more specific patterns appear...
void pbx_set_overrideswitch(const char *newval)
int pbx_parse_location(struct ast_channel *chan, char **contextp, char **extenp, char **prip, int *ipri, int *mode, char *rest)
Parses a dialplan location into context, extension, priority.
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Data structure associated with a custom dialplan function.
void(* ast_state_cb_destroy_type)(int id, void *data)
Typedef for devicestate and hint callback removal indication callback.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
Add a switch.
#define AST_MAX_EXTENSION
#define AST_STRING_FIELD(name)
Declare a string field.
struct ast_switch * pbx_findswitch(const char *sw)
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
structure to hold extensions
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
int ast_context_remove_include(const char *context, const char *include, const char *registrar)
Remove included contexts. This function locks contexts list by &conlist, search for the right context...
static void print_ext(struct ast_exten *e, char *buf, int buflen)
helper function to print an extension
struct ast_dial * dial
Dialing structure being used.
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
struct ao2_container * container
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static ast_mutex_t conlock
Lock for the ast_context list.
struct ast_hashtab * peer_label_table
char * registrar
Name of the registrar.
void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
end the traversal, free the iterator, unlock if necc.
int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
Add an ignorepat.
enum ast_dial_result ast_dial_state(struct ast_dial *dial)
Return state of dial.
Core PBX routines and definitions.
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm. Also, unlike strptime(3), ast_strptime() initializes its memory prior to use.
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
ast_pbx_result
The result codes when starting the PBX on a channel with ast_pbx_start.
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
static void pbx_outgoing_state_callback(struct ast_dial *dial)
Internal dialing state callback which causes early media to trigger an answer.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
struct ast_party_dialed dialed
Dialed/Called information.
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_PBX_INCOMPLETE
struct ast_exten * exten
Hint extension.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
int( ast_switch_f)(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
All switch functions have the same interface, so define a type for them.
static int manager_show_dialplan_helper(struct mansession *s, const struct message *m, const char *actionidtext, const char *context, const char *exten, struct dialplan_counters *dpc, const struct ast_include *rinclude, int includecount, const char *includes[])
Show dialplan extensions XXX this function is similar but not exactly the same as the CLI's show dial...
Presence state management.
char context_name[AST_MAX_CONTEXT]
int ast_unlock_contexts(void)
Unlocks contexts.
struct ast_ignorepats ignorepats
void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
int ast_extension_state_add_destroy(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
Add watcher for extension states with destructor.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Support for dynamic strings.
int pbx_set_autofallthrough(int newval)
void * ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
Looks up the object, removes the corresponding bucket.
static int manager_show_dialplan(struct mansession *s, const struct message *m)
Manager listing of dial plan.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int ast_get_extension_registrar_line(struct ast_exten *e)
Get line number of configuration file used by registrar to register this extension.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
ast_ignorepat: Ignore patterns in dial plan
Structure for dial plan autohints.
int ast_thread_inhibit_escalations_swap(int inhibit)
Swap the current thread escalation inhibit setting.
ast_state_cb_destroy_type destroy_cb
Structure for dial plan hints.
Connected Line/Party information.
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
Append a channel.
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
const char * app_name(struct ast_app *app)
Structure which contains information about an outgoing dial.
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
an iterator for traversing the buckets
static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
collect digits from the channel into the buffer.
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
int ast_safe_sleep_without_silence(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups, and do not generate silence.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
int ast_context_destroy_by_name(const char *context, const char *registrar)
Destroy a context by name.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
static int autohint_hash_cb(const void *obj, const int flags)
#define ast_calloc(num, len)
A wrapper for calloc()
struct ast_dial * ast_dial_create(void)
New dialing structure.
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
static struct ast_context * find_context(const char *context)
lookup for a context with a given name,
struct ast_channel * ast_dial_get_channel(struct ast_dial *dial, int num)
Get the dialing channel, if prerun has been executed.
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
Adds a switch (first param is a ast_context)
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
static int publish_hint_change(struct ast_hint *hint, struct ast_exten *ne)
Publish a hint changed event.
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks to see if adding anything to this extension might match something. (exists ^ canmatch) ...
Asterisk XML Documentation API.
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
Map devstate to an extension state.
Prototypes for public functions only of internal interest,.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids)
Synchronously or asynchronously make an outbound call and send it to a particular extension...
Vector container support.
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
This functionc locks given context, search for the right extension and fires out all peer in this ext...
unsigned int ast_hashtab_hash_string(const void *obj)
Hashes a string to a number.
An API for managing task processing threads that can be shared across modules.
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
static int find_hint_by_cb_id(void *obj, void *arg, int flags)
Find Hint by callback id.
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media, const struct ast_assigned_ids *assignedids, const char *predial_callee)
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
Run all hangup handlers on the channel.
int pbx_checkcondition(const char *condition)
Evaluate a condition.
struct ast_channel * ast_dial_answered_steal(struct ast_dial *dial)
Steal the channel that answered.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
void unreference_cached_app(struct ast_app *app)
static void context_table_create_autohints(struct ast_hashtab *table)
struct ast_includes includes
Assume that the ao2_container is already locked.
static int ext_strncpy(char *dst, const char *src, int len)
copy a string skipping whitespace
STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type)
A message type used to synchronize with the CDR topic.
The arg parameter is an object of the same type.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
static int ext_cmp(const char *a, const char *b)
the full routine to compare extensions in rules.
static struct ast_exten * ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
Find hint for given extension in context.
struct ast_hint::@382 devices
Structure for dial plan hint devices.
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag)
ao2_callback_data() is a generic function that applies cb_fn() to all objects in a container...
#define ast_channel_ref(c)
Increase channel reference count.
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Structure for rwlock and tracking information.
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
static char * complete_core_show_hint(const char *line, const char *word, int pos, int state)
autocomplete for CLI command 'core show hint'
Standard Command Line Interface.
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
static int enabled
Whether or not we are storing history.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
ast_app: A registered application
int ast_extension_state_add_extended(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extended extension states.
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_async_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
struct stasis_message_type * ast_presence_state_message_type(void)
Get presence state message type.
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
Remove an ignorepat.
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
static int add_priority(struct ast_context *con, struct ast_exten *tmp, struct ast_exten *el, struct ast_exten *e, int replace)
add the extension in the priority chain.
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Data structure associated with a single frame of data.
const char * cidmatch_display
static int hintdevice_hash_cb(const void *obj, const int flags)
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c, const char *context, const char *exten, int priority)
Fill a string buffer with the data at a dialplan extension.
Internal Asterisk hangup causes.
enum ast_presence_state state
static int ast_remove_hint(struct ast_exten *e)
Remove hint from extension.
You shouldn't care about the contents of this struct.
struct ast_hashtab * root_table
Counters for the show dialplan manager command.
The structure that contains device state.
Handy terminal functions for vt* terms.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
struct ast_context * parent
int ast_context_add_include(const char *context, const char *include, const char *registrar)
Add a context include.
char * last_presence_message
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
int ast_active_calls(void)
Retrieve the number of active calls.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
int ast_extension_state_add_destroy_extended(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
Add watcher for extended extension states with destructor.
Search option field mask.
int(* ast_state_cb_type)(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Typedef for devicestate and hint callbacks.
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
The return value depends on the action:
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
Get hint for channel.
int ast_dial_reason(struct ast_dial *dial, int num)
Get the reason an outgoing channel has failed.
struct ast_app * pbx_findapp(const char *app)
Look up an application.
struct stasis_topic * ast_presence_state_topic_all(void)
Get presence state topic.
Say numbers and dates (maybe words one day too)
char * last_presence_subtype
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
const ast_string_field context
unsigned int no_hangup_chan
int ast_hashtab_size(struct ast_hashtab *tab)
Returns the number of elements stored in the hashtab.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
void ast_hashtab_get_stats(struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets)
Returns key stats for the table.
char exten_name[AST_MAX_EXTENSION]
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
ast_context: An extension context
struct ao2_container * callbacks
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static struct ao2_container * autohints
Container for autohint contexts.
void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Set the connected line information in the Asterisk channel.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
char exten[AST_MAX_EXTENSION]
static void pbx_outgoing_destroy(void *obj)
Destructor for outgoing structure.
const char * ast_extension_state2str(int extension_state)
Return extension_state as string.
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
struct match_char * pattern_tree
int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Same as ast_add_extension2, but assumes you have already locked context.
const char * ast_presence_state2str(enum ast_presence_state state)
Convert presence state to text string for output.
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
static struct stasis_subscription * device_state_sub
Subscription for device state change events.
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
match_char: forms a syntax tree for quick matching of extension patterns
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
void ast_hashtab_destroy(struct ast_hashtab *tab, void(*objdestroyfunc)(void *obj))
This func will free the hash table and all its memory.
#define ao2_link(container, obj)
Add an object to a container.
int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_format_cap *cap)
Request all appended channels, but do not dial.
void * ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj)
Hash the object and then compare ptrs in bucket list instead of calling the compare routine...