Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
pbx.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2008, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Core PBX routines.
22 *
23 * \author Mark Spencer <markster@digium.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/_private.h"
33#include "asterisk/paths.h" /* use ast_config_AST_SYSTEM_NAME */
34#include <ctype.h>
35#include <time.h>
36#include <sys/time.h>
37#if defined(HAVE_SYSINFO)
38#include <sys/sysinfo.h>
39#endif
40#if defined(SOLARIS)
41#include <sys/loadavg.h>
42#endif
43
44#include "asterisk/lock.h"
45#include "asterisk/cli.h"
46#include "asterisk/pbx.h"
47#include "asterisk/channel.h"
48#include "asterisk/file.h"
49#include "asterisk/callerid.h"
50#include "asterisk/cdr.h"
51#include "asterisk/config.h"
52#include "asterisk/term.h"
53#include "asterisk/time.h"
54#include "asterisk/manager.h"
55#include "asterisk/ast_expr.h"
56#define SAY_STUBS /* generate declarations and stubs for say methods */
57#include "asterisk/say.h"
58#include "asterisk/utils.h"
59#include "asterisk/causes.h"
61#include "asterisk/app.h"
62#include "asterisk/hashtab.h"
63#include "asterisk/module.h"
65#include "asterisk/xmldoc.h"
67#include "asterisk/dial.h"
68#include "asterisk/vector.h"
70#include "pbx_private.h"
71
72/*!
73 * \note I M P O R T A N T :
74 *
75 * The speed of extension handling will likely be among the most important
76 * aspects of this PBX. The switching scheme as it exists right now isn't
77 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
78 * of priorities, but a constant search time here would be great ;-)
79 *
80 * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
81 * here, and shows a fairly flat (constant) search time, even for over
82 * 10000 patterns.
83 *
84 * Also, using a hash table for context/priority name lookup can help prevent
85 * the find_extension routines from absorbing exponential cpu cycles as the number
86 * of contexts/priorities grow. I've previously tested find_extension with red-black trees,
87 * which have O(log2(n)) speed. Right now, I'm using hash tables, which do
88 * searches (ideally) in O(1) time. While these techniques do not yield much
89 * speed in small dialplans, they are worth the trouble in large dialplans.
90 *
91 */
92
93/*** DOCUMENTATION
94 <function name="EXCEPTION" language="en_US">
95 <since>
96 <version>1.6.0</version>
97 </since>
98 <synopsis>
99 Retrieve the details of the current dialplan exception.
100 </synopsis>
101 <syntax>
102 <parameter name="field" required="true">
103 <para>The following fields are available for retrieval:</para>
104 <enumlist>
105 <enum name="reason">
106 <para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
107 value set by the RaiseException() application</para>
108 </enum>
109 <enum name="context">
110 <para>The context executing when the exception occurred.</para>
111 </enum>
112 <enum name="exten">
113 <para>The extension executing when the exception occurred.</para>
114 </enum>
115 <enum name="priority">
116 <para>The numeric priority executing when the exception occurred.</para>
117 </enum>
118 </enumlist>
119 </parameter>
120 </syntax>
121 <description>
122 <para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
123 </description>
124 <see-also>
125 <ref type="application">RaiseException</ref>
126 </see-also>
127 </function>
128 <function name="TESTTIME" language="en_US">
129 <since>
130 <version>1.8.0</version>
131 </since>
132 <synopsis>
133 Sets a time to be used with the channel to test logical conditions.
134 </synopsis>
135 <syntax>
136 <parameter name="date" required="true" argsep=" ">
137 <para>Date in ISO 8601 format</para>
138 </parameter>
139 <parameter name="time" required="true" argsep=" ">
140 <para>Time in HH:MM:SS format (24-hour time)</para>
141 </parameter>
142 <parameter name="zone" required="false">
143 <para>Timezone name</para>
144 </parameter>
145 </syntax>
146 <description>
147 <para>To test dialplan timing conditions at times other than the current time, use
148 this function to set an alternate date and time. For example, you may wish to evaluate
149 whether a location will correctly identify to callers that the area is closed on Christmas
150 Day, when Christmas would otherwise fall on a day when the office is normally open.</para>
151 </description>
152 <see-also>
153 <ref type="application">GotoIfTime</ref>
154 </see-also>
155 </function>
156 <manager name="ShowDialPlan" language="en_US">
157 <since>
158 <version>1.6.0</version>
159 </since>
160 <synopsis>
161 Show dialplan contexts and extensions
162 </synopsis>
163 <syntax>
164 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
165 <parameter name="Extension">
166 <para>Show a specific extension.</para>
167 </parameter>
168 <parameter name="Context">
169 <para>Show a specific context.</para>
170 </parameter>
171 </syntax>
172 <description>
173 <para>Show dialplan contexts and extensions. Be aware that showing the full dialplan
174 may take a lot of capacity.</para>
175 </description>
176 </manager>
177 ***/
178
179#ifdef LOW_MEMORY
180#define EXT_DATA_SIZE 256
181#else
182#define EXT_DATA_SIZE 8192
183#endif
184
185#define SWITCH_DATA_LENGTH 256
186
187#define VAR_NORMAL 1
188#define VAR_SOFTTRAN 2
189#define VAR_HARDTRAN 3
190
191struct ast_context;
192struct ast_app;
193
194AST_THREADSTORAGE(switch_data);
195
197 AST_CONTEXT_SCOPE_LOCAL = 0, /*!< Context is only locally accessible */
198 AST_CONTEXT_SCOPE_GLOBAL, /*!< Context is globally accessible */
199};
200
201/*!
202 \brief ast_exten: An extension
203 The dialplan is saved as a linked list with each context
204 having it's own linked list of extensions - one item per
205 priority.
206*/
207struct ast_exten {
208 char *exten; /*!< Clean Extension id */
209 char *name; /*!< Extension name (may include '-' eye candy) */
210 int matchcid; /*!< Match caller id ? */
211 const char *cidmatch; /*!< Caller id to match for this extension */
212 const char *cidmatch_display; /*!< Caller id to match (display version) */
213 int priority; /*!< Priority */
214 const char *label; /*!< Label */
215 struct ast_context *parent; /*!< The context this extension belongs to */
216 const char *app; /*!< Application to execute */
217 struct ast_app *cached_app; /*!< Cached location of application */
218 void *data; /*!< Data to use (arguments) */
219 void (*datad)(void *); /*!< Data destructor */
220 struct ast_exten *peer; /*!< Next higher priority with our extension */
221 struct ast_hashtab *peer_table; /*!< Priorities list in hashtab form -- only on the head of the peer list */
222 struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
223 const char *registrar; /*!< Registrar */
224 const char *registrar_file; /*!< File name used to register extension */
225 int registrar_line; /*!< Line number the extension was registered in text */
226 struct ast_exten *next; /*!< Extension with a greater ID */
227 char stuff[0];
228};
229
230/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
232{
233 int is_pattern; /* the pattern started with '_' */
234 int deleted; /* if this is set, then... don't return it */
235 int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
238 struct ast_exten *exten; /* attached to last char of a pattern for exten */
239 char x[1]; /* the pattern itself-- matches a single char */
240};
241
242struct scoreboard /* make sure all fields are 0 before calling new_find_extension */
243{
246 char last_char; /* set to ! or . if they are the end of the pattern */
247 int canmatch; /* if the string to match was just too short */
251};
252
253/*! \brief ast_context: An extension context */
255 const char *name;
256 const char *registrar;
257
258 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
259 struct ast_exten *root; /*!< The root of the list of extensions */
260 struct ast_hashtab *root_table; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */
261 struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */
262 struct ast_context *next; /*!< Link them together */
263 struct ast_includes includes; /*!< Include other contexts */
264 struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */
265 struct ast_sws alts; /*!< Alternative switches */
266 enum ast_context_scope scope; /*!< The scope of this context */
267 int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */
268 int autohints; /*!< Whether autohints support is enabled or not */
269
270 /*!
271 * Buffer to hold the name & registrar character data.
272 *
273 * The context name *must* be stored first in this buffer.
274 */
275 char data[];
276};
277
280 AST_STRING_FIELD(context); /*!< Context associated with this exception */
281 AST_STRING_FIELD(exten); /*!< Exten associated with this exception */
282 AST_STRING_FIELD(reason); /*!< The exception reason */
283 );
284
285 int priority; /*!< Priority associated with this exception */
286};
287
288static int matchcid(const char *cidpattern, const char *callerid);
289#ifdef NEED_DEBUG
290static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
291#endif
292static void new_find_extension(const char *str, struct scoreboard *score,
293 struct match_char *tree, int length, int spec, const char *callerid,
294 const char *label, enum ext_match_t action);
295static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
296static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
297 struct ast_exten *e1, int findonly);
298static void create_match_char_tree(struct ast_context *con);
299static struct ast_exten *get_canmatch_exten(struct match_char *node);
300static void destroy_pattern_tree(struct match_char *pattern_tree);
301static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
302static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
303static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
304static unsigned int hashtab_hash_extens(const void *obj);
305static unsigned int hashtab_hash_priority(const void *obj);
306static unsigned int hashtab_hash_labels(const void *obj);
307static void __ast_internal_context_destroy( struct ast_context *con);
308static int ast_add_extension2_lockopt(struct ast_context *con,
309 int replace, const char *extension, int priority, const char *label, const char *callerid,
310 const char *application, void *data, void (*datad)(void *),
311 const char *registrar, const char *registrar_file, int registrar_line,
312 int lock_context);
313static struct ast_context *find_context_locked(const char *context);
314static struct ast_context *find_context(const char *context);
315static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff);
316
317/*!
318 * \internal
319 * \brief Character array comparison function for qsort.
320 *
321 * \param a Left side object.
322 * \param b Right side object.
323 *
324 * \retval <0 if a < b
325 * \retval =0 if a = b
326 * \retval >0 if a > b
327 */
328static int compare_char(const void *a, const void *b)
329{
330 const unsigned char *ac = a;
331 const unsigned char *bc = b;
332
333 return *ac - *bc;
334}
335
336/* labels, contexts are case sensitive priority numbers are ints */
337int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
338{
339 const struct ast_context *ac = ah_a;
340 const struct ast_context *bc = ah_b;
341 if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
342 return 1;
343 /* assume context names are registered in a string table! */
344 return strcmp(ac->name, bc->name);
345}
346
347static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
348{
349 const struct ast_exten *ac = ah_a;
350 const struct ast_exten *bc = ah_b;
351 int x = strcmp(ac->exten, bc->exten);
352 if (x) { /* if exten names are diff, then return */
353 return x;
354 }
355
356 /* but if they are the same, do the cidmatch values match? */
357 /* not sure which side may be using ast_ext_matchcid_types, so check both */
358 if (ac->matchcid == AST_EXT_MATCHCID_ANY || bc->matchcid == AST_EXT_MATCHCID_ANY) {
359 return 0;
360 }
361 if (ac->matchcid == AST_EXT_MATCHCID_OFF && bc->matchcid == AST_EXT_MATCHCID_OFF) {
362 return 0;
363 }
364 if (ac->matchcid != bc->matchcid) {
365 return 1;
366 }
367 /* all other cases already disposed of, match now required on callerid string (cidmatch) */
368 /* although ast_add_extension2_lockopt() enforces non-zero ptr, caller may not have */
369 if (ast_strlen_zero(ac->cidmatch) && ast_strlen_zero(bc->cidmatch)) {
370 return 0;
371 }
372 return strcmp(ac->cidmatch, bc->cidmatch);
373}
374
375static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
376{
377 const struct ast_exten *ac = ah_a;
378 const struct ast_exten *bc = ah_b;
379 return ac->priority != bc->priority;
380}
381
382static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
383{
384 const struct ast_exten *ac = ah_a;
385 const struct ast_exten *bc = ah_b;
386 return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
387}
388
389unsigned int ast_hashtab_hash_contexts(const void *obj)
390{
391 const struct ast_context *ac = obj;
392 return ast_hashtab_hash_string(ac->name);
393}
394
395static unsigned int hashtab_hash_extens(const void *obj)
396{
397 const struct ast_exten *ac = obj;
398 unsigned int x = ast_hashtab_hash_string(ac->exten);
399 unsigned int y = 0;
400 if (ac->matchcid == AST_EXT_MATCHCID_ON)
402 return x+y;
403}
404
405static unsigned int hashtab_hash_priority(const void *obj)
406{
407 const struct ast_exten *ac = obj;
408 return ast_hashtab_hash_int(ac->priority);
409}
410
411static unsigned int hashtab_hash_labels(const void *obj)
412{
413 const struct ast_exten *ac = obj;
414 return ast_hashtab_hash_string(S_OR(ac->label, ""));
415}
416
417static int autofallthrough = 1;
418static int extenpatternmatchnew = 0;
419static char *overrideswitch = NULL;
420
422static int countcalls;
423static int totalcalls;
424
425static struct ast_context *contexts;
427
428/*!
429 * \brief Lock for the ast_context list
430 * \note
431 * This lock MUST be recursive, or a deadlock on reload may result. See
432 * https://issues.asterisk.org/view.php?id=17643
433 */
435
436#ifdef CONTEXT_DEBUG
437
438/* these routines are provided for doing run-time checks
439 on the extension structures, in case you are having
440 problems, this routine might help you localize where
441 the problem is occurring. It's kinda like a debug memory
442 allocator's arena checker... It'll eat up your cpu cycles!
443 but you'll see, if you call it in the right places,
444 right where your problems began...
445*/
446
447/* you can break on the check_contexts_trouble()
448routine in your debugger to stop at the moment
449there's a problem */
450void check_contexts_trouble(void);
451
452void check_contexts_trouble(void)
453{
454 int x = 1;
455 x = 2;
456}
457
458int check_contexts(char *, int);
459
460int check_contexts(char *file, int line )
461{
462 struct ast_hashtab_iter *t1;
463 struct ast_context *c1, *c2;
464 int found = 0;
465 struct ast_exten *e1, *e2, *e3;
466 struct ast_exten ex;
467
468 /* try to find inconsistencies */
469 /* is every context in the context table in the context list and vice-versa ? */
470
471 if (!contexts_table) {
472 ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
473 usleep(500000);
474 }
475
477 while( (c1 = ast_hashtab_next(t1))) {
478 for(c2=contexts;c2;c2=c2->next) {
479 if (!strcmp(c1->name, c2->name)) {
480 found = 1;
481 break;
482 }
483 }
484 if (!found) {
485 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
486 check_contexts_trouble();
487 }
488 }
490 for(c2=contexts;c2;c2=c2->next) {
491 c1 = find_context_locked(c2->name);
492 if (!c1) {
493 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
494 check_contexts_trouble();
495 } else
497 }
498
499 /* loop thru all contexts, and verify the exten structure compares to the
500 hashtab structure */
501 for(c2=contexts;c2;c2=c2->next) {
502 c1 = find_context_locked(c2->name);
503 if (c1) {
505
506 /* is every entry in the root list also in the root_table? */
507 for(e1 = c1->root; e1; e1=e1->next)
508 {
509 char dummy_name[1024];
510 ex.exten = dummy_name;
511 ex.matchcid = e1->matchcid;
512 ex.cidmatch = e1->cidmatch;
513 ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
514 e2 = ast_hashtab_lookup(c1->root_table, &ex);
515 if (!e2) {
516 if (e1->matchcid == AST_EXT_MATCHCID_ON) {
517 ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records "
518 "the exten %s (CID match: %s) but it is not in its root_table\n",
519 file, line, c2->name, dummy_name, e1->cidmatch_display);
520 } else {
521 ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records "
522 "the exten %s but it is not in its root_table\n",
523 file, line, c2->name, dummy_name);
524 }
525 check_contexts_trouble();
526 }
527 }
528
529 /* is every entry in the root_table also in the root list? */
530 if (!c2->root_table) {
531 if (c2->root) {
532 ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
533 usleep(500000);
534 }
535 } else {
537 while( (e2 = ast_hashtab_next(t1)) ) {
538 for(e1=c2->root;e1;e1=e1->next) {
539 if (!strcmp(e1->exten, e2->exten)) {
540 found = 1;
541 break;
542 }
543 }
544 if (!found) {
545 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);
546 check_contexts_trouble();
547 }
548
549 }
551 }
552 }
553 /* is every priority reflected in the peer_table at the head of the list? */
554
555 /* is every entry in the root list also in the root_table? */
556 /* are the per-extension peer_tables in the right place? */
557
558 for(e1 = c2->root; e1; e1 = e1->next) {
559
560 for(e2=e1;e2;e2=e2->peer) {
561 ex.priority = e2->priority;
562 if (e2 != e1 && e2->peer_table) {
563 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 );
564 check_contexts_trouble();
565 }
566
567 if (e2 != e1 && e2->peer_label_table) {
568 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 );
569 check_contexts_trouble();
570 }
571
572 if (e2 == e1 && !e2->peer_table){
573 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 );
574 check_contexts_trouble();
575 }
576
577 if (e2 == e1 && !e2->peer_label_table) {
578 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 );
579 check_contexts_trouble();
580 }
581
582
583 e3 = ast_hashtab_lookup(e1->peer_table, &ex);
584 if (!e3) {
585 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 );
586 check_contexts_trouble();
587 }
588 }
589
590 if (!e1->peer_table){
591 ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
592 usleep(500000);
593 }
594
595 /* is every entry in the peer_table also in the peer list? */
597 while( (e2 = ast_hashtab_next(t1)) ) {
598 for(e3=e1;e3;e3=e3->peer) {
599 if (e3->priority == e2->priority) {
600 found = 1;
601 break;
602 }
603 }
604 if (!found) {
605 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 );
606 check_contexts_trouble();
607 }
608 }
610 }
611 }
612 return 0;
613}
614#endif
615
616static void pbx_destroy(struct ast_pbx *p)
617{
618 ast_free(p);
619}
620
621/* form a tree that fully describes all the patterns in a context's extensions
622 * in this tree, a "node" represents an individual character or character set
623 * meant to match the corresponding character in a dial string. The tree
624 * consists of a series of match_char structs linked in a chain
625 * via the alt_char pointers. More than one pattern can share the same parts of the
626 * tree as other extensions with the same pattern to that point.
627 * My first attempt to duplicate the finding of the 'best' pattern was flawed in that
628 * I misunderstood the general algorithm. I thought that the 'best' pattern
629 * was the one with lowest total score. This was not true. Thus, if you have
630 * patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
631 * the "best" match because it has fewer X's, and is therefore more specific,
632 * but this is not how the old algorithm works. It sorts matching patterns
633 * in a similar collating sequence as sorting alphabetic strings, from left to
634 * right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
635 * because "1" is more specific than "X".
636 * So, to accommodate this philosophy, I sort the tree branches along the alt_char
637 * line so they are lowest to highest in specificity numbers. This way, as soon
638 * as we encounter our first complete match, we automatically have the "best"
639 * match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
640 * If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
641 * they are welcome to revert pbx to before 1 Apr 2008.
642 * As an example, consider these 4 extensions:
643 * (a) NXXNXXXXXX
644 * (b) 307754XXXX
645 * (c) fax
646 * (d) NXXXXXXXXX
647 *
648 * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
649 * most numbers. For all numbers beginning with 307754, (b) should always win.
650 *
651 * These pattern should form a (sorted) tree that looks like this:
652 * { "3" } --next--> { "0" } --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
653 * |
654 * |alt
655 * |
656 * { "f" } --next--> { "a" } --next--> { "x" exten_match: (c) }
657 * { "N" } --next--> { "X" } --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
658 * | |
659 * | |alt
660 * |alt |
661 * | { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
662 * |
663 * NULL
664 *
665 * In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
666 * fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
667 *
668 * traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern, it calls itself
669 * on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
670 * We pass a pointer to a scoreboard down through, also.
671 * The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
672 * The first complete match ends the traversal, which should make this version of the pattern matcher faster
673 * the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
674 * these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
675 * according to the sort criteria.
676 * Hope the limit on stack depth won't be a problem... this routine should
677 * be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
678 *
679 * In the above example, with the number "3077549999" as the pattern, the traverser could match extensions a, b and d. All are
680 * of length 10; they have total specificities of 24580, 10246, and 25090, respectively, not that this matters
681 * at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
682 * left the specificity totals in the code as an artifact; at some point, I will strip it out.
683 *
684 * Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
685 * because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
686 * can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
687 * more times faster in extreme cases.
688 *
689 * MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
690 * can have patterns in your CID field as well.
691 *
692 * */
693
694
695static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
696{
697 /* if this extension is marked as deleted, then skip this -- if it never shows
698 on the scoreboard, it will never be found, nor will halt the traversal. */
699 if (deleted)
700 return;
701 board->total_specificity = spec;
702 board->total_length = length;
703 board->exten = exten;
704 board->last_char = last;
705 board->node = node;
706#ifdef NEED_DEBUG_HERE
707 ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
708#endif
709}
710
711#ifdef NEED_DEBUG
712static void log_match_char_tree(struct match_char *node, char *prefix)
713{
714 char extenstr[40];
715 struct ast_str *my_prefix = ast_str_alloca(1024);
716
717 extenstr[0] = '\0';
718
719 if (node && node->exten)
720 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
721
722 if (strlen(node->x) > 1) {
723 ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
724 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
725 node->exten ? node->exten->exten : "", extenstr);
726 } else {
727 ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
728 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
729 node->exten ? node->exten->exten : "", extenstr);
730 }
731
732 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
733
734 if (node->next_char)
735 log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
736
737 if (node->alt_char)
738 log_match_char_tree(node->alt_char, prefix);
739}
740#endif
741
742static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
743{
744 char extenstr[40];
745 struct ast_str *my_prefix = ast_str_alloca(1024);
746
747 extenstr[0] = '\0';
748
749 if (node->exten) {
750 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
751 }
752
753 if (strlen(node->x) > 1) {
754 ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
755 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
756 node->exten ? node->exten->name : "", extenstr);
757 } else {
758 ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
759 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
760 node->exten ? node->exten->name : "", extenstr);
761 }
762
763 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
764
765 if (node->next_char)
766 cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
767
768 if (node->alt_char)
769 cli_match_char_tree(node->alt_char, prefix, fd);
770}
771
773{
774 /* find the exten at the end of the rope */
775 struct match_char *node2 = node;
776
777 for (node2 = node; node2; node2 = node2->next_char) {
778 if (node2->exten) {
779#ifdef NEED_DEBUG_HERE
780 ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
781#endif
782 return node2->exten;
783 }
784 }
785#ifdef NEED_DEBUG_HERE
786 ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
787#endif
788 return 0;
789}
790
792{
793 struct match_char *m3;
794 struct match_char *m4;
795 struct ast_exten *e3;
796
797 if (node && node->x[0] == '.' && !node->x[1]) { /* dot and ! will ALWAYS be next match in a matchmore */
798 return node->exten;
799 }
800
801 if (node && node->x[0] == '!' && !node->x[1]) {
802 return node->exten;
803 }
804
805 if (!node || !node->next_char) {
806 return NULL;
807 }
808
809 m3 = node->next_char;
810
811 if (m3->exten) {
812 return m3->exten;
813 }
814 for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
815 if (m4->exten) {
816 return m4->exten;
817 }
818 }
819 for (m4 = m3; m4; m4 = m4->alt_char) {
820 e3 = trie_find_next_match(m3);
821 if (e3) {
822 return e3;
823 }
824 }
825
826 return NULL;
827}
828
829#ifdef DEBUG_THIS
830static char *action2str(enum ext_match_t action)
831{
832 switch (action) {
833 case E_MATCH:
834 return "MATCH";
835 case E_CANMATCH:
836 return "CANMATCH";
837 case E_MATCHMORE:
838 return "MATCHMORE";
839 case E_FINDLABEL:
840 return "FINDLABEL";
841 case E_SPAWN:
842 return "SPAWN";
843 default:
844 return "?ACTION?";
845 }
846}
847
848#endif
849
850static const char *candidate_exten_advance(const char *str)
851{
852 str++;
853 while (*str == '-') {
854 str++;
855 }
856 return str;
857}
858
859#define MORE(s) (*candidate_exten_advance(s))
860#define ADVANCE(s) candidate_exten_advance(s)
861
862static 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)
863{
864 struct match_char *p; /* note minimal stack storage requirements */
865 struct ast_exten pattern = { .label = label };
866#ifdef DEBUG_THIS
867 if (tree)
868 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
869 else
870 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
871#endif
872 for (p = tree; p; p = p->alt_char) {
873 if (p->is_pattern) {
874 if (p->x[0] == 'N') {
875 if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
876#define NEW_MATCHER_CHK_MATCH \
877 if (p->exten && !MORE(str)) { /* if a shorter pattern matches along the way, might as well report it */ \
878 if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */ \
879 update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
880 if (!p->deleted) { \
881 if (action == E_FINDLABEL) { \
882 if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
883 ast_debug(4, "Found label in preferred extension\n"); \
884 return; \
885 } \
886 } else { \
887 ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->name); \
888 return; /* the first match, by definition, will be the best, because of the sorted tree */ \
889 } \
890 } \
891 } \
892 }
893
894#define NEW_MATCHER_RECURSE \
895 if (p->next_char && (MORE(str) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
896 || p->next_char->x[0] == '!')) { \
897 if (MORE(str) || p->next_char->x[0] == '!') { \
898 new_find_extension(ADVANCE(str), score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
899 if (score->exten) { \
900 ast_debug(4 ,"returning an exact match-- %s\n", score->exten->name); \
901 return; /* the first match is all we need */ \
902 } \
903 } else { \
904 new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
905 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
906 ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->name : \
907 "NULL"); \
908 return; /* the first match is all we need */ \
909 } \
910 } \
911 } else if ((p->next_char || action == E_CANMATCH) && !MORE(str)) { \
912 score->canmatch = 1; \
913 score->canmatch_exten = get_canmatch_exten(p); \
914 if (action == E_CANMATCH || action == E_MATCHMORE) { \
915 ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
916 return; \
917 } \
918 }
919
922 }
923 } else if (p->x[0] == 'Z') {
924 if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
927 }
928 } else if (p->x[0] == 'X') {
929 if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
932 }
933 } else if (p->x[0] == '.' && p->x[1] == 0) {
934 /* how many chars will the . match against? */
935 int i = 0;
936 const char *str2 = str;
937 while (*str2 && *str2 != '/') {
938 str2++;
939 i++;
940 }
941 if (p->exten && *str2 != '/') {
942 update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
943 if (score->exten) {
944 ast_debug(4, "return because scoreboard has a match with '/'--- %s\n",
945 score->exten->name);
946 return; /* the first match is all we need */
947 }
948 }
949 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
950 new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
951 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
952 ast_debug(4, "return because scoreboard has exact match OR "
953 "CANMATCH/MATCHMORE & canmatch set--- %s\n",
954 score->exten ? score->exten->name : "NULL");
955 return; /* the first match is all we need */
956 }
957 }
958 } else if (p->x[0] == '!' && p->x[1] == 0) {
959 /* how many chars will the . match against? */
960 int i = 1;
961 const char *str2 = str;
962 while (*str2 && *str2 != '/') {
963 str2++;
964 i++;
965 }
966 if (p->exten && *str2 != '/') {
967 update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
968 if (score->exten) {
969 ast_debug(4, "return because scoreboard has a '!' match--- %s\n",
970 score->exten->name);
971 return; /* the first match is all we need */
972 }
973 }
974 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
975 new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
976 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
977 ast_debug(4, "return because scoreboard has exact match OR "
978 "CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n",
979 score->exten ? score->exten->name : "NULL");
980 return; /* the first match is all we need */
981 }
982 }
983 } else if (p->x[0] == '/' && p->x[1] == 0) {
984 /* the pattern in the tree includes the cid match! */
985 if (p->next_char && callerid && *callerid) {
986 new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
987 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
988 ast_debug(4, "return because scoreboard has exact match OR "
989 "CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n",
990 score->exten ? score->exten->name : "NULL");
991 return; /* the first match is all we need */
992 }
993 }
994 } else if (strchr(p->x, *str)) {
995 ast_debug(4, "Nothing strange about this match\n");
998 }
999 } else if (strchr(p->x, *str)) {
1000 ast_debug(4, "Nothing strange about this match\n");
1003 }
1004 }
1005 ast_debug(4, "return at end of func\n");
1006}
1007
1008#undef MORE
1009#undef ADVANCE
1010
1011/* the algorithm for forming the extension pattern tree is also a bit simple; you
1012 * traverse all the extensions in a context, and for each char of the extension,
1013 * you see if it exists in the tree; if it doesn't, you add it at the appropriate
1014 * spot. What more can I say? At the end of each exten, you cap it off by adding the
1015 * address of the extension involved. Duplicate patterns will be complained about.
1016 *
1017 * Ideally, this would be done for each context after it is created and fully
1018 * filled. It could be done as a finishing step after extensions.conf or .ael is
1019 * loaded, or it could be done when the first search is encountered. It should only
1020 * have to be done once, until the next unload or reload.
1021 *
1022 * I guess forming this pattern tree would be analogous to compiling a regex. Except
1023 * that a regex only handles 1 pattern, really. This trie holds any number
1024 * of patterns. Well, really, it **could** be considered a single pattern,
1025 * where the "|" (or) operator is allowed, I guess, in a way, sort of...
1026 */
1027
1028static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
1029{
1030 struct match_char *t;
1031
1032 if (!current) {
1033 return 0;
1034 }
1035
1036 for (t = current; t; t = t->alt_char) {
1037 if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
1038 return t;
1039 }
1040 }
1041
1042 return 0;
1043}
1044
1045/* The first arg is the location of the tree ptr, or the
1046 address of the next_char ptr in the node, so we can mess
1047 with it, if we need to insert at the beginning of the list */
1048
1049static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
1050{
1051 struct match_char *curr, *lcurr;
1052
1053 /* insert node into the tree at "current", so the alt_char list from current is
1054 sorted in increasing value as you go to the leaves */
1055 if (!(*parent_ptr)) {
1056 *parent_ptr = node;
1057 return;
1058 }
1059
1060 if ((*parent_ptr)->specificity > node->specificity) {
1061 /* insert at head */
1062 node->alt_char = (*parent_ptr);
1063 *parent_ptr = node;
1064 return;
1065 }
1066
1067 lcurr = *parent_ptr;
1068 for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
1069 if (curr->specificity > node->specificity) {
1070 node->alt_char = curr;
1071 lcurr->alt_char = node;
1072 break;
1073 }
1074 lcurr = curr;
1075 }
1076
1077 if (!curr) {
1078 lcurr->alt_char = node;
1079 }
1080
1081}
1082
1084 /*! Pattern node specificity */
1086 /*! Pattern node match characters. */
1087 char buf[256];
1088};
1089
1090static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, const struct pattern_node *pattern, int is_pattern, int already, struct match_char **nextcharptr)
1091{
1092 struct match_char *m;
1093
1094 if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
1095 return NULL;
1096 }
1097
1098 /* strcpy is safe here since we know its size and have allocated
1099 * just enough space for when we allocated m
1100 */
1101 strcpy(m->x, pattern->buf);
1102
1103 /* the specificity scores are the same as used in the old
1104 pattern matcher. */
1106 if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
1107 m->specificity = 0x0832;
1108 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
1109 m->specificity = 0x0931;
1110 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
1111 m->specificity = 0x0a30;
1112 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
1113 m->specificity = 0x18000;
1114 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
1115 m->specificity = 0x28000;
1116 } else {
1117 m->specificity = pattern->specif;
1118 }
1119
1120 if (!con->pattern_tree) {
1122 } else {
1123 if (already) { /* switch to the new regime (traversing vs appending)*/
1124 insert_in_next_chars_alt_char_list(nextcharptr, m);
1125 } else {
1127 }
1128 }
1129
1130 return m;
1131}
1132
1133/*!
1134 * \internal
1135 * \brief Extract the next exten pattern node.
1136 *
1137 * \param node Pattern node to fill.
1138 * \param src Next source character to read.
1139 * \param pattern TRUE if the exten is a pattern.
1140 * \param extenbuf Original exten buffer to use in diagnostic messages.
1141 *
1142 * \retval Ptr to next extenbuf pos to read.
1143 */
1144static const char *get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
1145{
1146#define INC_DST_OVERFLOW_CHECK \
1147 do { \
1148 if (dst - node->buf < sizeof(node->buf) - 1) { \
1149 ++dst; \
1150 } else { \
1151 overflow = 1; \
1152 } \
1153 } while (0)
1154
1155 node->specif = 0;
1156 node->buf[0] = '\0';
1157 while (*src) {
1158 if (*src == '[' && pattern) {
1159 char *dst = node->buf;
1160 const char *src_next;
1161 int length;
1162 int overflow = 0;
1163
1164 /* get past the '[' */
1165 ++src;
1166 for (;;) {
1167 if (*src == '\\') {
1168 /* Escaped character. */
1169 ++src;
1170 if (*src == '[' || *src == '\\' || *src == '-' || *src == ']') {
1171 *dst = *src++;
1173 }
1174 } else if (*src == '-') {
1175 unsigned char first;
1176 unsigned char last;
1177
1178 src_next = src;
1179 first = *(src_next - 1);
1180 last = *++src_next;
1181
1182 if (last == '\\') {
1183 /* Escaped character. */
1184 last = *++src_next;
1185 }
1186
1187 /* Possible char range. */
1188 if (node->buf[0] && last) {
1189 /* Expand the char range. */
1190 while (++first <= last) {
1191 *dst = first;
1193 }
1194 src = src_next + 1;
1195 } else {
1196 /*
1197 * There was no left or right char for the range.
1198 * It is just a '-'.
1199 */
1200 *dst = *src++;
1202 }
1203 } else if (*src == '\0') {
1205 "A matching ']' was not found for '[' in exten pattern '%s'\n",
1206 extenbuf);
1207 break;
1208 } else if (*src == ']') {
1209 ++src;
1210 break;
1211 } else {
1212 *dst = *src++;
1214 }
1215 }
1216 /* null terminate the exploded range */
1217 *dst = '\0';
1218
1219 if (overflow) {
1221 "Expanded character set too large to deal with in exten pattern '%s'. Ignoring character set.\n",
1222 extenbuf);
1223 node->buf[0] = '\0';
1224 continue;
1225 }
1226
1227 /* Sort the characters in character set. */
1228 length = strlen(node->buf);
1229 if (!length) {
1230 ast_log(LOG_WARNING, "Empty character set in exten pattern '%s'. Ignoring.\n",
1231 extenbuf);
1232 node->buf[0] = '\0';
1233 continue;
1234 }
1235 qsort(node->buf, length, 1, compare_char);
1236
1237 /* Remove duplicate characters from character set. */
1238 dst = node->buf;
1239 src_next = node->buf;
1240 while (*src_next++) {
1241 if (*dst != *src_next) {
1242 *++dst = *src_next;
1243 }
1244 }
1245
1246 length = strlen(node->buf);
1247 length <<= 8;
1248 node->specif = length | (unsigned char) node->buf[0];
1249 break;
1250 } else if (*src == '-') {
1251 /* Skip dashes in all extensions. */
1252 ++src;
1253 } else {
1254 if (*src == '\\') {
1255 /*
1256 * XXX The escape character here does not remove any special
1257 * meaning to characters except the '[', '\\', and '-'
1258 * characters since they are special only in this function.
1259 */
1260 node->buf[0] = *++src;
1261 if (!node->buf[0]) {
1262 break;
1263 }
1264 } else {
1265 node->buf[0] = *src;
1266 if (pattern) {
1267 /* make sure n,x,z patterns are canonicalized to N,X,Z */
1268 if (node->buf[0] == 'n') {
1269 node->buf[0] = 'N';
1270 } else if (node->buf[0] == 'x') {
1271 node->buf[0] = 'X';
1272 } else if (node->buf[0] == 'z') {
1273 node->buf[0] = 'Z';
1274 }
1275 }
1276 }
1277 node->buf[1] = '\0';
1278 node->specif = 1;
1279 ++src;
1280 break;
1281 }
1282 }
1283 return src;
1284
1285#undef INC_DST_OVERFLOW_CHECK
1286}
1287
1288#define MAX_EXTENBUF_SIZE 512
1289static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
1290{
1291 struct match_char *m1 = NULL;
1292 struct match_char *m2 = NULL;
1293 struct match_char **m0;
1294 const char *pos;
1295 int already;
1296 int pattern = 0;
1297 int idx_cur;
1298 int idx_next;
1299 char extenbuf[MAX_EXTENBUF_SIZE];
1300 volatile size_t required_space = strlen(e1->exten) + 1;
1301 struct pattern_node pat_node[2];
1302
1303 if (e1->matchcid) {
1304 required_space += (strlen(e1->cidmatch) + 2 /* '/' + NULL */);
1305 if (required_space > MAX_EXTENBUF_SIZE) {
1307 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1308 e1->exten, e1->cidmatch);
1309 return NULL;
1310 }
1311 sprintf(extenbuf, "%s/%s", e1->exten, e1->cidmatch);/* Safe. We just checked. */
1312 } else {
1313 if (required_space > MAX_EXTENBUF_SIZE) {
1315 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1316 e1->exten, e1->cidmatch);
1317 return NULL;
1318 }
1319 ast_copy_string(extenbuf, e1->exten, required_space);
1320 }
1321
1322#ifdef NEED_DEBUG
1323 ast_debug(1, "Adding exten %s to tree\n", extenbuf);
1324#endif
1325 m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
1326 m0 = &con->pattern_tree;
1327 already = 1;
1328
1329 pos = extenbuf;
1330 if (*pos == '_') {
1331 pattern = 1;
1332 ++pos;
1333 }
1334 idx_cur = 0;
1335 pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
1336 for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
1337 idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
1338 pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
1339
1340 /* See about adding node to tree. */
1341 m2 = NULL;
1342 if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].buf, pattern))
1343 && m2->next_char) {
1344 if (!pat_node[idx_next].buf[0]) {
1345 /*
1346 * This is the end of the pattern, but not the end of the tree.
1347 * Mark this node with the exten... a shorter pattern might win
1348 * if the longer one doesn't match.
1349 */
1350 if (findonly) {
1351 return m2;
1352 }
1353 if (m2->exten) {
1354 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
1355 m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
1356 }
1357 m2->exten = e1;
1358 m2->deleted = 0;
1359 }
1360 m1 = m2->next_char; /* m1 points to the node to compare against */
1361 m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
1362 } else { /* not already OR not m2 OR nor m2->next_char */
1363 if (m2) {
1364 if (findonly) {
1365 return m2;
1366 }
1367 m1 = m2; /* while m0 stays the same */
1368 } else {
1369 if (findonly) {
1370 return m1;
1371 }
1372 m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
1373 if (!m1) { /* m1 is the node just added */
1374 return NULL;
1375 }
1376 m0 = &m1->next_char;
1377 }
1378 if (!pat_node[idx_next].buf[0]) {
1379 if (m2 && m2->exten) {
1380 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
1381 m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
1382 }
1383 m1->deleted = 0;
1384 m1->exten = e1;
1385 }
1386
1387 /* The 'already' variable is a mini-optimization designed to make it so that we
1388 * don't have to call already_in_tree when we know it will return false.
1389 */
1390 already = 0;
1391 }
1392 }
1393 return m1;
1394}
1395
1396static void create_match_char_tree(struct ast_context *con)
1397{
1398 struct ast_hashtab_iter *t1;
1399 struct ast_exten *e1;
1400#ifdef NEED_DEBUG
1401 int biggest_bucket, resizes, numobjs, numbucks;
1402
1403 ast_debug(1, "Creating Extension Trie for context %s(%p)\n", con->name, con);
1404 ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
1405 ast_debug(1, "This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
1406 numobjs, numbucks, biggest_bucket, resizes);
1407#endif
1409 while ((e1 = ast_hashtab_next(t1))) {
1410 if (e1->exten) {
1411 add_exten_to_pattern_tree(con, e1, 0);
1412 } else {
1413 ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
1414 }
1415 }
1417}
1418
1419static void destroy_pattern_tree(struct match_char *pattern_tree) /* pattern tree is a simple binary tree, sort of, so the proper way to destroy it is... recursively! */
1420{
1421 /* destroy all the alternates */
1422 if (pattern_tree->alt_char) {
1423 destroy_pattern_tree(pattern_tree->alt_char);
1424 pattern_tree->alt_char = 0;
1425 }
1426 /* destroy all the nexts */
1427 if (pattern_tree->next_char) {
1428 destroy_pattern_tree(pattern_tree->next_char);
1429 pattern_tree->next_char = 0;
1430 }
1431 pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
1432 ast_free(pattern_tree);
1433}
1434
1435/*!
1436 * \internal
1437 * \brief Get the length of the exten string.
1438 *
1439 * \param str Exten to get length.
1440 *
1441 * \retval strlen of exten.
1442 */
1443static int ext_cmp_exten_strlen(const char *str)
1444{
1445 int len;
1446
1447 len = 0;
1448 for (;;) {
1449 /* Ignore '-' chars as eye candy fluff. */
1450 while (*str == '-') {
1451 ++str;
1452 }
1453 if (!*str) {
1454 break;
1455 }
1456 ++str;
1457 ++len;
1458 }
1459 return len;
1460}
1461
1462/*!
1463 * \internal
1464 * \brief Partial comparison of non-pattern extens.
1465 *
1466 * \param left Exten to compare.
1467 * \param right Exten to compare. Also matches if this string ends first.
1468 *
1469 * \retval <0 if left < right
1470 * \retval =0 if left == right
1471 * \retval >0 if left > right
1472 */
1473static int ext_cmp_exten_partial(const char *left, const char *right)
1474{
1475 int cmp;
1476
1477 for (;;) {
1478 /* Ignore '-' chars as eye candy fluff. */
1479 while (*left == '-') {
1480 ++left;
1481 }
1482 while (*right == '-') {
1483 ++right;
1484 }
1485
1486 if (!*right) {
1487 /*
1488 * Right ended first for partial match or both ended at the same
1489 * time for a match.
1490 */
1491 cmp = 0;
1492 break;
1493 }
1494
1495 cmp = *left - *right;
1496 if (cmp) {
1497 break;
1498 }
1499 ++left;
1500 ++right;
1501 }
1502 return cmp;
1503}
1504
1505/*!
1506 * \internal
1507 * \brief Comparison of non-pattern extens.
1508 *
1509 * \param left Exten to compare.
1510 * \param right Exten to compare.
1511 *
1512 * \retval <0 if left < right
1513 * \retval =0 if left == right
1514 * \retval >0 if left > right
1515 */
1516static int ext_cmp_exten(const char *left, const char *right)
1517{
1518 int cmp;
1519
1520 for (;;) {
1521 /* Ignore '-' chars as eye candy fluff. */
1522 while (*left == '-') {
1523 ++left;
1524 }
1525 while (*right == '-') {
1526 ++right;
1527 }
1528
1529 cmp = *left - *right;
1530 if (cmp) {
1531 break;
1532 }
1533 if (!*left) {
1534 /*
1535 * Get here only if both strings ended at the same time. cmp
1536 * would be non-zero if only one string ended.
1537 */
1538 break;
1539 }
1540 ++left;
1541 ++right;
1542 }
1543 return cmp;
1544}
1545
1546/*
1547 * Special characters used in patterns:
1548 * '_' underscore is the leading character of a pattern.
1549 * In other position it is treated as a regular char.
1550 * '-' The '-' is a separator and ignored. Why? So patterns like NXX-XXX-XXXX work.
1551 * . one or more of any character. Only allowed at the end of
1552 * a pattern.
1553 * ! zero or more of anything. Also impacts the result of CANMATCH
1554 * and MATCHMORE. Only allowed at the end of a pattern.
1555 * In the core routine, ! causes a match with a return code of 2.
1556 * In turn, depending on the search mode: (XXX check if it is implemented)
1557 * - E_MATCH returns 1 (does match)
1558 * - E_MATCHMORE returns 0 (no match)
1559 * - E_CANMATCH returns 1 (does match)
1560 *
1561 * / should not appear as it is considered the separator of the CID info.
1562 * XXX at the moment we may stop on this char.
1563 *
1564 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
1565 * [ denotes the start of a set of character. Everything inside
1566 * is considered literally. We can have ranges a-d and individual
1567 * characters. A '[' and '-' can be considered literally if they
1568 * are just before ']'.
1569 * XXX currently there is no way to specify ']' in a range, nor \ is
1570 * considered specially.
1571 *
1572 * When we compare a pattern with a specific extension, all characters in the extension
1573 * itself are considered literally.
1574 * XXX do we want to consider space as a separator as well ?
1575 * XXX do we want to consider the separators in non-patterns as well ?
1576 */
1577
1578/*!
1579 * \brief helper functions to sort extension patterns in the desired way,
1580 * so that more specific patterns appear first.
1581 *
1582 * \details
1583 * The function compares individual characters (or sets of), returning
1584 * an int where bits 0-7 are the ASCII code of the first char in the set,
1585 * bits 8-15 are the number of characters in the set, and bits 16-20 are
1586 * for special cases.
1587 * This way more specific patterns (smaller character sets) appear first.
1588 * Wildcards have a special value, so that we can directly compare them to
1589 * sets by subtracting the two values. In particular:
1590 * 0x001xx one character, character set starting with xx
1591 * 0x0yyxx yy characters, character set starting with xx
1592 * 0x18000 '.' (one or more of anything)
1593 * 0x28000 '!' (zero or more of anything)
1594 * 0x30000 NUL (end of string)
1595 * 0x40000 error in set.
1596 * The pointer to the string is advanced according to needs.
1597 * NOTES:
1598 * 1. the empty set is ignored.
1599 * 2. given that a full set has always 0 as the first element,
1600 * we could encode the special cases as 0xffXX where XX
1601 * is 1, 2, 3, 4 as used above.
1602 */
1603static int ext_cmp_pattern_pos(const char **p, unsigned char *bitwise)
1604{
1605#define BITS_PER 8 /* Number of bits per unit (byte). */
1606 unsigned char c;
1607 unsigned char cmin;
1608 int count;
1609 const char *end;
1610
1611 do {
1612 /* Get character and advance. (Ignore '-' chars as eye candy fluff.) */
1613 do {
1614 c = *(*p)++;
1615 } while (c == '-');
1616
1617 /* always return unless we have a set of chars */
1618 switch (c) {
1619 default:
1620 /* ordinary character */
1621 bitwise[c / BITS_PER] = 1 << ((BITS_PER - 1) - (c % BITS_PER));
1622 return 0x0100 | c;
1623
1624 case 'n':
1625 case 'N':
1626 /* 2..9 */
1627 bitwise[6] = 0x3f;
1628 bitwise[7] = 0xc0;
1629 return 0x0800 | '2';
1630
1631 case 'x':
1632 case 'X':
1633 /* 0..9 */
1634 bitwise[6] = 0xff;
1635 bitwise[7] = 0xc0;
1636 return 0x0A00 | '0';
1637
1638 case 'z':
1639 case 'Z':
1640 /* 1..9 */
1641 bitwise[6] = 0x7f;
1642 bitwise[7] = 0xc0;
1643 return 0x0900 | '1';
1644
1645 case '.':
1646 /* wildcard */
1647 return 0x18000;
1648
1649 case '!':
1650 /* earlymatch */
1651 return 0x28000; /* less specific than '.' */
1652
1653 case '\0':
1654 /* empty string */
1655 *p = NULL;
1656 return 0x30000;
1657
1658 case '[':
1659 /* char set */
1660 break;
1661 }
1662 /* locate end of set */
1663 end = strchr(*p, ']');
1664
1665 if (!end) {
1666 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
1667 return 0x40000; /* XXX make this entry go last... */
1668 }
1669
1670 count = 0;
1671 cmin = 0xFF;
1672 for (; *p < end; ++*p) {
1673 unsigned char c1; /* first char in range */
1674 unsigned char c2; /* last char in range */
1675
1676 c1 = (*p)[0];
1677 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
1678 c2 = (*p)[2];
1679 *p += 2; /* skip a total of 3 chars */
1680 } else { /* individual character */
1681 c2 = c1;
1682 }
1683 if (c1 < cmin) {
1684 cmin = c1;
1685 }
1686 for (; c1 <= c2; ++c1) {
1687 unsigned char mask = 1 << ((BITS_PER - 1) - (c1 % BITS_PER));
1688
1689 /*
1690 * Note: If two character sets score the same, the one with the
1691 * lowest ASCII values will compare as coming first. Must fill
1692 * in most significant bits for lower ASCII values to accomplish
1693 * the desired sort order.
1694 */
1695 if (!(bitwise[c1 / BITS_PER] & mask)) {
1696 /* Add the character to the set. */
1697 bitwise[c1 / BITS_PER] |= mask;
1698 count += 0x100;
1699 }
1700 }
1701 }
1702 ++*p;
1703 } while (!count);/* While the char set was empty. */
1704 return count | cmin;
1705}
1706
1707/*!
1708 * \internal
1709 * \brief Comparison of exten patterns.
1710 *
1711 * \param left Pattern to compare.
1712 * \param right Pattern to compare.
1713 *
1714 * \retval <0 if left < right
1715 * \retval =0 if left == right
1716 * \retval >0 if left > right
1717 */
1718static int ext_cmp_pattern(const char *left, const char *right)
1719{
1720 int cmp;
1721 int left_pos;
1722 int right_pos;
1723
1724 for (;;) {
1725 unsigned char left_bitwise[32] = { 0, };
1726 unsigned char right_bitwise[32] = { 0, };
1727
1728 left_pos = ext_cmp_pattern_pos(&left, left_bitwise);
1729 right_pos = ext_cmp_pattern_pos(&right, right_bitwise);
1730 cmp = left_pos - right_pos;
1731 if (!cmp) {
1732 /*
1733 * Are the character sets different, even though they score the same?
1734 *
1735 * Note: Must swap left and right to get the sense of the
1736 * comparison correct. Otherwise, we would need to multiply by
1737 * -1 instead.
1738 */
1739 cmp = memcmp(right_bitwise, left_bitwise, ARRAY_LEN(left_bitwise));
1740 }
1741 if (cmp) {
1742 break;
1743 }
1744 if (!left) {
1745 /*
1746 * Get here only if both patterns ended at the same time. cmp
1747 * would be non-zero if only one pattern ended.
1748 */
1749 break;
1750 }
1751 }
1752 return cmp;
1753}
1754
1755/*!
1756 * \internal
1757 * \brief Comparison of dialplan extens for sorting purposes.
1758 *
1759 * \param left Exten/pattern to compare.
1760 * \param right Exten/pattern to compare.
1761 *
1762 * \retval <0 if left < right
1763 * \retval =0 if left == right
1764 * \retval >0 if left > right
1765 */
1766static int ext_cmp(const char *left, const char *right)
1767{
1768 /* Make sure non-pattern extens come first. */
1769 if (left[0] != '_') {
1770 if (right[0] == '_') {
1771 return -1;
1772 }
1773 /* Compare two non-pattern extens. */
1774 return ext_cmp_exten(left, right);
1775 }
1776 if (right[0] != '_') {
1777 return 1;
1778 }
1779
1780 /*
1781 * OK, we need full pattern sorting routine.
1782 *
1783 * Skip past the underscores
1784 */
1785 return ext_cmp_pattern(left + 1, right + 1);
1786}
1787
1788static int ext_fluff_count(const char *exten)
1789{
1790 int fluff = 0;
1791
1792 if (*exten != '_') {
1793 /* not a pattern, simple check. */
1794 while (*exten) {
1795 if (*exten == '-') {
1796 fluff++;
1797 }
1798 exten++;
1799 }
1800
1801 return fluff;
1802 }
1803
1804 /* do pattern check */
1805 while (*exten) {
1806 if (*exten == '-') {
1807 fluff++;
1808 } else if (*exten == '[') {
1809 /* skip set, dashes here matter. */
1810 exten = strchr(exten, ']');
1811
1812 if (!exten) {
1813 /* we'll end up warning about this later, don't spam logs */
1814 return fluff;
1815 }
1816 }
1817 exten++;
1818 }
1819
1820 return fluff;
1821}
1822
1823int ast_extension_cmp(const char *a, const char *b)
1824{
1825 int cmp;
1826
1827 cmp = ext_cmp(a, b);
1828 if (cmp < 0) {
1829 return -1;
1830 }
1831 if (cmp > 0) {
1832 return 1;
1833 }
1834 return 0;
1835}
1836
1837/*!
1838 * \internal
1839 * \brief used ast_extension_{match|close}
1840 * mode is as follows:
1841 * E_MATCH success only on exact match
1842 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
1843 * E_CANMATCH either of the above.
1844 * \retval 0 on no-match
1845 * \retval 1 on match
1846 * \retval 2 on early match.
1847 */
1848
1849static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
1850{
1851 mode &= E_MATCH_MASK; /* only consider the relevant bits */
1852
1853#ifdef NEED_DEBUG_HERE
1854 ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
1855#endif
1856
1857 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
1858 int lp = ext_cmp_exten_strlen(pattern);
1859 int ld = ext_cmp_exten_strlen(data);
1860
1861 if (lp < ld) { /* pattern too short, cannot match */
1862#ifdef NEED_DEBUG_HERE
1863 ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
1864#endif
1865 return 0;
1866 }
1867 /* depending on the mode, accept full or partial match or both */
1868 if (mode == E_MATCH) {
1869#ifdef NEED_DEBUG_HERE
1870 ast_log(LOG_NOTICE,"return (!ext_cmp_exten(%s,%s) when mode== E_MATCH)\n", pattern, data);
1871#endif
1872 return !ext_cmp_exten(pattern, data); /* 1 on match, 0 on fail */
1873 }
1874 if (ld == 0 || !ext_cmp_exten_partial(pattern, data)) { /* partial or full match */
1875#ifdef NEED_DEBUG_HERE
1876 ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
1877#endif
1878 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
1879 } else {
1880#ifdef NEED_DEBUG_HERE
1881 ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
1882#endif
1883 return 0;
1884 }
1885 }
1886 if (mode == E_MATCH && data[0] == '_') {
1887 /*
1888 * XXX It is bad design that we don't know if we should be
1889 * comparing data and pattern as patterns or comparing data if
1890 * it conforms to pattern when the function is called. First,
1891 * assume they are both patterns. If they don't match then try
1892 * to see if data conforms to the given pattern.
1893 *
1894 * note: if this test is left out, then _x. will not match _x. !!!
1895 */
1896#ifdef NEED_DEBUG_HERE
1897 ast_log(LOG_NOTICE, "Comparing as patterns first. pattern:%s data:%s\n", pattern, data);
1898#endif
1899 if (!ext_cmp_pattern(pattern + 1, data + 1)) {
1900#ifdef NEED_DEBUG_HERE
1901 ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
1902#endif
1903 return 1;
1904 }
1905 }
1906
1907 ++pattern; /* skip leading _ */
1908 /*
1909 * XXX below we stop at '/' which is a separator for the CID info. However we should
1910 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
1911 */
1912 for (;;) {
1913 const char *end;
1914
1915 /* Ignore '-' chars as eye candy fluff. */
1916 while (*data == '-') {
1917 ++data;
1918 }
1919 while (*pattern == '-') {
1920 ++pattern;
1921 }
1922 if (!*data || !*pattern || *pattern == '/') {
1923 break;
1924 }
1925
1926 switch (*pattern) {
1927 case '[': /* a range */
1928 ++pattern;
1929 end = strchr(pattern, ']'); /* XXX should deal with escapes ? */
1930 if (!end) {
1931 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
1932 return 0; /* unconditional failure */
1933 }
1934 if (pattern == end) {
1935 /* Ignore empty character sets. */
1936 ++pattern;
1937 continue;
1938 }
1939 for (; pattern < end; ++pattern) {
1940 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
1941 if (*data >= pattern[0] && *data <= pattern[2])
1942 break; /* match found */
1943 else {
1944 pattern += 2; /* skip a total of 3 chars */
1945 continue;
1946 }
1947 } else if (*data == pattern[0])
1948 break; /* match found */
1949 }
1950 if (pattern >= end) {
1951#ifdef NEED_DEBUG_HERE
1952 ast_log(LOG_NOTICE,"return (0) when pattern>=end\n");
1953#endif
1954 return 0;
1955 }
1956 pattern = end; /* skip and continue */
1957 break;
1958 case 'n':
1959 case 'N':
1960 if (*data < '2' || *data > '9') {
1961#ifdef NEED_DEBUG_HERE
1962 ast_log(LOG_NOTICE,"return (0) N is not matched\n");
1963#endif
1964 return 0;
1965 }
1966 break;
1967 case 'x':
1968 case 'X':
1969 if (*data < '0' || *data > '9') {
1970#ifdef NEED_DEBUG_HERE
1971 ast_log(LOG_NOTICE,"return (0) X is not matched\n");
1972#endif
1973 return 0;
1974 }
1975 break;
1976 case 'z':
1977 case 'Z':
1978 if (*data < '1' || *data > '9') {
1979#ifdef NEED_DEBUG_HERE
1980 ast_log(LOG_NOTICE,"return (0) Z is not matched\n");
1981#endif
1982 return 0;
1983 }
1984 break;
1985 case '.': /* Must match, even with more digits */
1986#ifdef NEED_DEBUG_HERE
1987 ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
1988#endif
1989 return 1;
1990 case '!': /* Early match */
1991#ifdef NEED_DEBUG_HERE
1992 ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
1993#endif
1994 return 2;
1995 default:
1996 if (*data != *pattern) {
1997#ifdef NEED_DEBUG_HERE
1998 ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
1999#endif
2000 return 0;
2001 }
2002 break;
2003 }
2004 ++data;
2005 ++pattern;
2006 }
2007 if (*data) /* data longer than pattern, no match */ {
2008#ifdef NEED_DEBUG_HERE
2009 ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
2010#endif
2011 return 0;
2012 }
2013
2014 /*
2015 * match so far, but ran off the end of data.
2016 * Depending on what is next, determine match or not.
2017 */
2018 if (*pattern == '\0' || *pattern == '/') { /* exact match */
2019#ifdef NEED_DEBUG_HERE
2020 ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
2021#endif
2022 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
2023 } else if (*pattern == '!') { /* early match */
2024#ifdef NEED_DEBUG_HERE
2025 ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
2026#endif
2027 return 2;
2028 } else { /* partial match */
2029#ifdef NEED_DEBUG_HERE
2030 ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
2031#endif
2032 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
2033 }
2034}
2035
2036/*
2037 * Wrapper around _extension_match_core() to do performance measurement
2038 * using the profiling code.
2039 */
2040static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2041{
2042 int i;
2043 static int prof_id = -2; /* marker for 'unallocated' id */
2044 if (prof_id == -2) {
2045 prof_id = ast_add_profile("ext_match", 0);
2046 }
2047 ast_mark(prof_id, 1);
2048 i = _extension_match_core(ast_strlen_zero(pattern) ? "" : pattern, ast_strlen_zero(data) ? "" : data, mode);
2049 ast_mark(prof_id, 0);
2050 return i;
2051}
2052
2053int ast_extension_match(const char *pattern, const char *extension)
2054{
2055 return extension_match_core(pattern, extension, E_MATCH);
2056}
2057
2058int ast_extension_close(const char *pattern, const char *data, int needmore)
2059{
2060 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
2061 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
2062 return extension_match_core(pattern, data, needmore);
2063}
2064
2066{
2067 struct ast_context *tmp;
2068 struct ast_context item = {
2069 .name = name,
2070 };
2071
2072 if (!name) {
2073 return NULL;
2074 }
2076 if (contexts_table) {
2078 } else {
2079 tmp = NULL;
2080 while ((tmp = ast_walk_contexts(tmp))) {
2081 if (!strcasecmp(name, tmp->name)) {
2082 break;
2083 }
2084 }
2085 }
2087 return tmp;
2088}
2089
2090#define STATUS_NO_CONTEXT 1
2091#define STATUS_NO_EXTENSION 2
2092#define STATUS_NO_PRIORITY 3
2093#define STATUS_NO_LABEL 4
2094#define STATUS_SUCCESS 5
2095
2096static int matchcid(const char *cidpattern, const char *callerid)
2097{
2098 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
2099 failing to get a number should count as a match, otherwise not */
2100
2101 if (ast_strlen_zero(callerid)) {
2102 return ast_strlen_zero(cidpattern) ? 1 : 0;
2103 }
2104
2105 return ast_extension_match(cidpattern, callerid);
2106}
2107
2109 struct ast_context *bypass, struct pbx_find_info *q,
2110 const char *context, const char *exten, int priority,
2111 const char *label, const char *callerid, enum ext_match_t action)
2112{
2113 int x, res;
2114 struct ast_context *tmp = NULL;
2115 struct ast_exten *e = NULL, *eroot = NULL;
2116 struct ast_exten pattern = {NULL, };
2117 struct scoreboard score = {0, };
2118 struct ast_str *tmpdata = NULL;
2119 int idx;
2120
2121 pattern.label = label;
2122 pattern.priority = priority;
2123#ifdef NEED_DEBUG_HERE
2124 ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
2125#endif
2126
2127 /* Initialize status if appropriate */
2128 if (q->stacklen == 0) {
2130 q->swo = NULL;
2131 q->data = NULL;
2132 q->foundcontext = NULL;
2133 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
2134 ast_log(LOG_WARNING, "Maximum PBX stack (%d) exceeded. Too many includes?\n", AST_PBX_MAX_STACK);
2135 return NULL;
2136 }
2137
2138 /* Check first to see if we've already been checked */
2139 for (x = 0; x < q->stacklen; x++) {
2140 if (!strcasecmp(q->incstack[x], context))
2141 return NULL;
2142 }
2143
2144 if (bypass) { /* bypass means we only look there */
2145 tmp = bypass;
2146 } else { /* look in contexts */
2147 tmp = find_context(context);
2148 if (!tmp) {
2149 return NULL;
2150 }
2151 }
2152
2153 if (q->status < STATUS_NO_EXTENSION)
2155
2156 /* Do a search for matching extension */
2157
2158 eroot = NULL;
2159 score.total_specificity = 0;
2160 score.exten = 0;
2161 score.total_length = 0;
2162 if (!tmp->pattern_tree && tmp->root_table) {
2164#ifdef NEED_DEBUG
2165 ast_debug(1, "Tree Created in context %s:\n", context);
2166 log_match_char_tree(tmp->pattern_tree," ");
2167#endif
2168 }
2169#ifdef NEED_DEBUG
2170 ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
2171 log_match_char_tree(tmp->pattern_tree, ":: ");
2172#endif
2173
2174 do {
2176 char *osw = ast_strdupa(overrideswitch), *name;
2177 struct ast_switch *asw;
2178 ast_switch_f *aswf = NULL;
2179 char *datap;
2180 int eval = 0;
2181
2182 name = strsep(&osw, "/");
2183 asw = pbx_findswitch(name);
2184
2185 if (!asw) {
2186 ast_log(LOG_WARNING, "No such switch '%s'\n", name);
2187 break;
2188 }
2189
2190 if (osw && strchr(osw, '$')) {
2191 eval = 1;
2192 }
2193
2194 if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2195 ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!\n");
2196 break;
2197 } else if (eval) {
2198 /* Substitute variables now */
2199 pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2200 datap = ast_str_buffer(tmpdata);
2201 } else {
2202 datap = osw;
2203 }
2204
2205 /* equivalent of extension_match_core() at the switch level */
2206 if (action == E_CANMATCH)
2207 aswf = asw->canmatch;
2208 else if (action == E_MATCHMORE)
2209 aswf = asw->matchmore;
2210 else /* action == E_MATCH */
2211 aswf = asw->exists;
2212 if (!aswf) {
2213 res = 0;
2214 } else {
2215 if (chan) {
2217 }
2218 res = aswf(chan, context, exten, priority, callerid, datap);
2219 if (chan) {
2221 }
2222 }
2223 if (res) { /* Got a match */
2224 q->swo = asw;
2225 q->data = datap;
2226 q->foundcontext = context;
2227 /* XXX keep status = STATUS_NO_CONTEXT ? */
2228 return NULL;
2229 }
2230 }
2231 } while (0);
2232
2234 new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
2235 eroot = score.exten;
2236
2237 if (score.last_char == '!' && action == E_MATCHMORE) {
2238 /* We match an extension ending in '!'.
2239 * The decision in this case is final and is NULL (no match).
2240 */
2241#ifdef NEED_DEBUG_HERE
2242 ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
2243#endif
2244 return NULL;
2245 }
2246
2247 if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
2249#ifdef NEED_DEBUG_HERE
2250 ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
2251#endif
2252 return score.canmatch_exten;
2253 }
2254
2255 if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
2256 if (score.node) {
2257 struct ast_exten *z = trie_find_next_match(score.node);
2258 if (z) {
2259#ifdef NEED_DEBUG_HERE
2260 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
2261#endif
2262 } else {
2263 if (score.canmatch_exten) {
2264#ifdef NEED_DEBUG_HERE
2265 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
2266#endif
2267 return score.canmatch_exten;
2268 } else {
2269#ifdef NEED_DEBUG_HERE
2270 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
2271#endif
2272 }
2273 }
2274 return z;
2275 }
2276#ifdef NEED_DEBUG_HERE
2277 ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
2278#endif
2279 return NULL; /* according to the code, complete matches are null matches in MATCHMORE mode */
2280 }
2281
2282 if (eroot) {
2283 /* found entry, now look for the right priority */
2284 if (q->status < STATUS_NO_PRIORITY)
2286 e = NULL;
2287 if (action == E_FINDLABEL && label ) {
2288 if (q->status < STATUS_NO_LABEL)
2290 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2291 } else {
2292 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2293 }
2294 if (e) { /* found a valid match */
2296 q->foundcontext = context;
2297#ifdef NEED_DEBUG_HERE
2298 ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
2299#endif
2300 return e;
2301 }
2302 }
2303 } else { /* the old/current default exten pattern match algorithm */
2304
2305 /* scan the list trying to match extension and CID */
2306 eroot = NULL;
2307 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
2308 int match = extension_match_core(eroot->exten, exten, action);
2309 /* 0 on fail, 1 on match, 2 on earlymatch */
2310
2311 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
2312 continue; /* keep trying */
2313 if (match == 2 && action == E_MATCHMORE) {
2314 /* We match an extension ending in '!'.
2315 * The decision in this case is final and is NULL (no match).
2316 */
2317 return NULL;
2318 }
2319 /* found entry, now look for the right priority */
2320 if (q->status < STATUS_NO_PRIORITY)
2322 e = NULL;
2323 if (action == E_FINDLABEL && label ) {
2324 if (q->status < STATUS_NO_LABEL)
2326 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2327 } else {
2328 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2329 }
2330 if (e) { /* found a valid match */
2332 q->foundcontext = context;
2333 return e;
2334 }
2335 }
2336 }
2337
2338 /* Check alternative switches */
2339 for (idx = 0; idx < ast_context_switches_count(tmp); idx++) {
2340 const struct ast_sw *sw = ast_context_switches_get(tmp, idx);
2342 ast_switch_f *aswf = NULL;
2343 const char *datap;
2344
2345 if (!asw) {
2346 ast_log(LOG_WARNING, "No such switch '%s'\n", ast_get_switch_name(sw));
2347 continue;
2348 }
2349
2350 /* Substitute variables now */
2351 if (ast_get_switch_eval(sw)) {
2352 if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2353 ast_log(LOG_WARNING, "Can't evaluate switch?!\n");
2354 continue;
2355 }
2357 ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2358 datap = ast_str_buffer(tmpdata);
2359 } else {
2360 datap = ast_get_switch_data(sw);
2361 }
2362
2363 /* equivalent of extension_match_core() at the switch level */
2364 if (action == E_CANMATCH)
2365 aswf = asw->canmatch;
2366 else if (action == E_MATCHMORE)
2367 aswf = asw->matchmore;
2368 else /* action == E_MATCH */
2369 aswf = asw->exists;
2370 if (!aswf)
2371 res = 0;
2372 else {
2373 if (chan)
2375 res = aswf(chan, context, exten, priority, callerid, datap);
2376 if (chan)
2378 }
2379 if (res) { /* Got a match */
2380 q->swo = asw;
2381 q->data = datap;
2382 q->foundcontext = context;
2383 /* XXX keep status = STATUS_NO_CONTEXT ? */
2384 return NULL;
2385 }
2386 }
2387 /* Technically we should be using tmp->name here, but if we used that we
2388 * would have to cast away the constness of the 'name' pointer and I do
2389 * not want to do that. */
2390 q->incstack[q->stacklen++] = tmp->data; /* Setup the stack */
2391 /* Now try any includes we have in this context */
2392 for (idx = 0; idx < ast_context_includes_count(tmp); idx++) {
2393 const struct ast_include *i = ast_context_includes_get(tmp, idx);
2394
2395 if (include_valid(i)) {
2396 if ((e = pbx_find_extension(chan, bypass, q, include_rname(i), exten, priority, label, callerid, action))) {
2397#ifdef NEED_DEBUG_HERE
2398 ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
2399#endif
2400 return e;
2401 }
2402 if (q->swo)
2403 return NULL;
2404 }
2405 }
2406 return NULL;
2407}
2408
2409static void exception_store_free(void *data)
2410{
2411 struct pbx_exception *exception = data;
2413 ast_free(exception);
2414}
2415
2417 .type = "EXCEPTION",
2418 .destroy = exception_store_free,
2419};
2420
2421/*!
2422 * \internal
2423 * \brief Set the PBX to execute the exception extension.
2424 *
2425 * \param chan Channel to raise the exception on.
2426 * \param reason Reason exception is raised.
2427 * \param priority Dialplan priority to set.
2428 *
2429 * \retval 0 on success.
2430 * \retval -1 on error.
2431 */
2432int raise_exception(struct ast_channel *chan, const char *reason, int priority)
2433{
2434 struct ast_datastore *ds;
2435 struct pbx_exception *exception;
2436
2437 ast_channel_lock(chan);
2439 if (!ds) {
2441 if (!ds) {
2442 ast_channel_unlock(chan);
2443 return -1;
2444 }
2445 if (!(exception = ast_calloc_with_stringfields(1, struct pbx_exception, 128))) {
2447 ast_channel_unlock(chan);
2448 return -1;
2449 }
2450 ds->data = exception;
2451 ast_channel_datastore_add(chan, ds);
2452 } else
2453 exception = ds->data;
2454
2455 ast_string_field_set(exception, reason, reason);
2457 ast_string_field_set(exception, exten, ast_channel_exten(chan));
2458 exception->priority = ast_channel_priority(chan);
2459 ast_channel_unlock(chan);
2460
2461 set_ext_pri(chan, "e", priority);
2462 return 0;
2463}
2464
2465static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
2466{
2467 struct ast_datastore *ds;
2468 struct pbx_exception *exception;
2469 int res = 0;
2470
2471 ast_channel_lock(chan);
2473 if (!ds || !ds->data) {
2474 ast_channel_unlock(chan);
2475 return -1;
2476 }
2477 exception = ds->data;
2478 if (!strcasecmp(data, "REASON"))
2479 ast_copy_string(buf, exception->reason, buflen);
2480 else if (!strcasecmp(data, "CONTEXT"))
2481 ast_copy_string(buf, exception->context, buflen);
2482 else if (!strncasecmp(data, "EXTEN", 5))
2483 ast_copy_string(buf, exception->exten, buflen);
2484 else if (!strcasecmp(data, "PRIORITY"))
2485 snprintf(buf, buflen, "%d", exception->priority);
2486 else
2487 res = -1;
2488
2489 ast_channel_unlock(chan);
2490 return res;
2491}
2492
2494 .name = "EXCEPTION",
2495 .read = acf_exception_read,
2496};
2497
2498/*!
2499 * \brief The return value depends on the action:
2500 *
2501 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
2502 * and return 0 on failure, -1 on match;
2503 * E_FINDLABEL maps the label to a priority, and returns
2504 * the priority on success, ... XXX
2505 * E_SPAWN, spawn an application,
2506 *
2507 * \retval 0 on success.
2508 * \retval -1 on failure.
2509 *
2510 * \note The channel is auto-serviced in this function, because doing an extension
2511 * match may block for a long time. For example, if the lookup has to use a network
2512 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
2513 * auto-service code will queue up any important signalling frames to be processed
2514 * after this is done.
2515 */
2516static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
2517 const char *context, const char *exten, int priority,
2518 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
2519{
2520 struct ast_exten *e;
2521 struct ast_app *app;
2522 char *substitute = NULL;
2523 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
2524 char passdata[EXT_DATA_SIZE];
2525 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
2526
2528
2529 if (!context) {
2530 context = con->name;
2531 }
2532
2533 if (found)
2534 *found = 0;
2535
2536 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
2537 if (e) {
2538 if (found)
2539 *found = 1;
2540 if (matching_action) {
2542 return -1; /* success, we found it */
2543 } else if (action == E_FINDLABEL) { /* map the label to a priority */
2544 int res = e->priority;
2545
2547
2548 /* the priority we were looking for */
2549 return res;
2550 } else { /* spawn */
2551 if (!e->cached_app)
2552 e->cached_app = pbx_findapp(e->app);
2553 app = e->cached_app;
2554 if (ast_strlen_zero(e->data)) {
2555 *passdata = '\0';
2556 } else {
2557 const char *tmp;
2558 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
2559 /* no variables to substitute, copy on through */
2560 ast_copy_string(passdata, e->data, sizeof(passdata));
2561 } else {
2562 /* save e->data on stack for later processing after lock released */
2563 substitute = ast_strdupa(e->data);
2564 }
2565 }
2567 if (!app) {
2568 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
2569 return -1;
2570 }
2574 return 0;
2575 }
2576 if (ast_channel_context(c) != context)
2577 ast_channel_context_set(c, context);
2578 if (ast_channel_exten(c) != exten)
2579 ast_channel_exten_set(c, exten);
2582 if (substitute) {
2583 pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
2584 }
2585 ast_debug(1, "Launching '%s'\n", app_name(app));
2586 if (VERBOSITY_ATLEAST(3)) {
2587 ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
2588 exten, context, priority,
2591 COLORIZE(COLOR_BRMAGENTA, 0, passdata),
2592 "in new stack");
2593 }
2594 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
2595 }
2596 } else if (q.swo) { /* not found here, but in another switch */
2597 if (found)
2598 *found = 1;
2600 if (matching_action) {
2601 return -1;
2602 } else {
2603 if (!q.swo->exec) {
2604 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
2605 return -1;
2606 }
2607 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
2608 }
2609 } else { /* not found anywhere, see what happened */
2611 /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
2612 switch (q.status) {
2613 case STATUS_NO_CONTEXT:
2614 if (!matching_action && !combined_find_spawn)
2615 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
2616 break;
2618 if (!matching_action && !combined_find_spawn)
2619 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
2620 break;
2621 case STATUS_NO_PRIORITY:
2622 if (!matching_action && !combined_find_spawn)
2623 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
2624 break;
2625 case STATUS_NO_LABEL:
2626 if (context && !combined_find_spawn)
2627 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", S_OR(label, ""), exten, S_OR(context, ""));
2628 break;
2629 default:
2630 ast_debug(1, "Shouldn't happen!\n");
2631 }
2632
2633 return (matching_action) ? 0 : -1;
2634 }
2635}
2636
2637/*! \brief Find hint for given extension in context */
2638static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
2639{
2640 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
2641 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
2642}
2643
2644static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
2645{
2646 struct ast_exten *e;
2648 e = ast_hint_extension_nolock(c, context, exten);
2650 return e;
2651}
2652
2653static int ast_remove_hint(struct ast_exten *e)
2654{
2655 if (!e) {
2656 return -1;
2657 }
2658
2661 }
2662
2663 return 0;
2664}
2665
2666static int ast_add_hint(struct ast_exten *e)
2667{
2668 if (!e) {
2669 return -1;
2670 }
2671
2674 }
2675
2676 return 0;
2677}
2678
2679/*! \brief Change hint for an extension */
2680static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2681{
2682 if (!oe || !ne) {
2683 return -1;
2684 }
2685
2688 }
2691 }
2692
2693 return 0;
2694}
2695
2696/*! \brief Get hint for channel */
2697int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2698{
2699 struct ast_exten *e = ast_hint_extension(c, context, exten);
2700
2701 if (e) {
2702 if (hint)
2703 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2704 if (name) {
2705 const char *tmp = ast_get_extension_app_data(e);
2706 if (tmp)
2707 ast_copy_string(name, tmp, namesize);
2708 }
2709 return -1;
2710 }
2711 return 0;
2712}
2713
2714/*! \brief Get hint for channel */
2715int 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)
2716{
2717 struct ast_exten *e = ast_hint_extension(c, context, exten);
2718
2719 if (!e) {
2720 return 0;
2721 }
2722
2723 if (hint) {
2724 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
2725 }
2726 if (name) {
2727 const char *tmp = ast_get_extension_app_data(e);
2728 if (tmp) {
2729 ast_str_set(name, namesize, "%s", tmp);
2730 }
2731 }
2732 return -1;
2733}
2734
2735int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2736{
2737 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
2738}
2739
2740int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2741{
2742 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
2743}
2744
2745int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2746{
2747 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
2748}
2749
2750int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2751{
2752 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
2753}
2754
2755int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2756{
2757 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
2758}
2759
2760int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
2761{
2762 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
2763}
2764
2765void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
2766{
2767 int autoloopflag;
2768 int found;
2769 int spawn_error;
2770
2771 ast_channel_lock(chan);
2772
2773 /*
2774 * Make sure that the channel is marked as hungup since we are
2775 * going to run the h exten on it.
2776 */
2778
2779 /* Set h exten location */
2780 if (context != ast_channel_context(chan)) {
2781 ast_channel_context_set(chan, context);
2782 }
2783 ast_channel_exten_set(chan, "h");
2784 ast_channel_priority_set(chan, 1);
2785
2786 /* Save autoloop flag */
2789 ast_channel_unlock(chan);
2790
2791 for (;;) {
2792 spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
2794 S_COR(ast_channel_caller(chan)->id.number.valid,
2795 ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
2796
2797 ast_channel_lock(chan);
2798 if (spawn_error) {
2799 /* The code after the loop needs the channel locked. */
2800 break;
2801 }
2803 ast_channel_unlock(chan);
2804 }
2805 if (found && spawn_error) {
2806 /* Something bad happened, or a hangup has been requested. */
2807 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
2810 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
2813 }
2814
2815 /* An "h" exten has been run, so indicate that one has been run. */
2817
2818 /* Restore autoloop flag */
2820 ast_channel_unlock(chan);
2821}
2822
2823/*! helper function to set extension and priority */
2824void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
2825{
2830}
2831
2832/*!
2833 * \brief collect digits from the channel into the buffer.
2834 * \param c, buf, buflen, pos
2835 * \param waittime is in milliseconds
2836 * \retval 0 on timeout or done.
2837 * \retval -1 on error.
2838*/
2839static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
2840{
2841 int digit;
2842
2843 buf[pos] = '\0'; /* make sure it is properly terminated */
2845 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
2846 /* As long as we're willing to wait, and as long as it's not defined,
2847 keep reading digits until we can't possibly get a right answer anymore. */
2848 digit = ast_waitfordigit(c, waittime);
2851 } else {
2852 if (!digit) /* No entry */
2853 break;
2854 if (digit < 0) /* Error, maybe a hangup */
2855 return -1;
2856 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
2857 buf[pos++] = digit;
2858 buf[pos] = '\0';
2859 }
2860 waittime = ast_channel_pbx(c)->dtimeoutms;
2861 }
2862 }
2863 return 0;
2864}
2865
2867 struct ast_pbx_args *args)
2868{
2869 int found = 0; /* set if we find at least one match */
2870 int res = 0;
2871 int autoloopflag;
2872 int error = 0; /* set an error conditions */
2873 struct ast_pbx *pbx;
2874 ast_callid callid;
2875
2876 /* A little initial setup here */
2877 if (ast_channel_pbx(c)) {
2878 ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
2879 /* XXX and now what ? */
2881 }
2882 if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
2883 return AST_PBX_FAILED;
2884 }
2885
2887 /* If the thread isn't already associated with a callid, we should create that association. */
2888 if (!callid) {
2889 /* Associate new PBX thread with the channel call id if it is available.
2890 * If not, create a new one instead.
2891 */
2892 callid = ast_channel_callid(c);
2893 if (!callid) {
2894 callid = ast_create_callid();
2895 if (callid) {
2897 ast_channel_callid_set(c, callid);
2899 }
2900 }
2902 callid = 0;
2903 }
2904
2905 ast_channel_pbx_set(c, pbx);
2906 /* Set reasonable defaults */
2907 ast_channel_pbx(c)->rtimeoutms = 10000;
2908 ast_channel_pbx(c)->dtimeoutms = 5000;
2909
2911 autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
2914
2916 /* If not successful fall back to 's' - but only if there is no given exten */
2917 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));
2918 /* XXX the original code used the existing priority in the call to
2919 * ast_exists_extension(), and reset it to 1 afterwards.
2920 * I believe the correct thing is to set it to 1 immediately.
2921 */
2922 set_ext_pri(c, "s", 1);
2923 }
2924
2925 for (;;) {
2926 char dst_exten[256]; /* buffer to accumulate digits */
2927 int pos = 0; /* XXX should check bounds */
2928 int digit = 0;
2929 int invalid = 0;
2930 int timeout = 0;
2931
2932 /* No digits pressed yet */
2933 dst_exten[pos] = '\0';
2934
2935 /* loop on priorities in this context/exten */
2938 &found, 1))) {
2939
2940 if (!ast_check_hangup(c)) {
2942 continue;
2943 }
2944
2945 /* Check softhangup flags. */
2948 continue;
2949 }
2952 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
2953 set_ext_pri(c, "T", 1);
2954 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2957 continue;
2958 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
2959 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
2960 raise_exception(c, "ABSOLUTETIMEOUT", 1);
2961 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2964 continue;
2965 }
2966
2967 /* Call timed out with no special extension to jump to. */
2968 error = 1;
2969 break;
2970 }
2971 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
2973 error = 1;
2974 break;
2975 } /* end while - from here on we can use 'break' to go out */
2976 if (found && res) {
2977 /* Something bad happened, or a hangup has been requested. */
2978 if (strchr("0123456789ABCDEF*#", res)) {
2979 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
2980 pos = 0;
2981 dst_exten[pos++] = digit = res;
2982 dst_exten[pos] = '\0';
2983 } else if (res == AST_PBX_INCOMPLETE) {
2984 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));
2985 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));
2986
2987 /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
2989 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
2990 invalid = 1;
2991 } else {
2992 ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
2993 digit = 1;
2994 pos = strlen(dst_exten);
2995 }
2996 } else {
2997 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));
2998 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));
2999
3000 if ((res == AST_PBX_ERROR)
3002 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3003 /* if we are already on the 'e' exten, don't jump to it again */
3004 if (!strcmp(ast_channel_exten(c), "e")) {
3005 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));
3006 error = 1;
3007 } else {
3008 raise_exception(c, "ERROR", 1);
3009 continue;
3010 }
3011 }
3012
3015 continue;
3016 }
3019 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3020 set_ext_pri(c, "T", 1);
3021 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
3024 continue;
3025 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
3026 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3027 raise_exception(c, "ABSOLUTETIMEOUT", 1);
3028 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
3031 continue;
3032 }
3033 /* Call timed out with no special extension to jump to. */
3034 }
3035 error = 1;
3036 break;
3037 }
3038 }
3039 if (error)
3040 break;
3041
3042 /*!\note
3043 * We get here on a failure of some kind: non-existing extension or
3044 * hangup. We have options, here. We can either catch the failure
3045 * and continue, or we can drop out entirely. */
3046
3047 if (invalid
3048 || (ast_strlen_zero(dst_exten) &&
3050 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
3051 /*!\note
3052 * If there is no match at priority 1, it is not a valid extension anymore.
3053 * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
3054 * neither exist.
3055 */
3057 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3058 ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
3060 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
3061 set_ext_pri(c, "i", 1);
3062 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
3063 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3064 raise_exception(c, "INVALID", 1);
3065 } else {
3066 ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
3068 error = 1; /* we know what to do with it */
3069 break;
3070 }
3072 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
3074 } else { /* keypress received, get more digits for a full extension */
3075 int waittime = 0;
3076 if (digit)
3077 waittime = ast_channel_pbx(c)->dtimeoutms;
3078 else if (!autofallthrough)
3079 waittime = ast_channel_pbx(c)->rtimeoutms;
3080 if (!waittime) {
3081 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
3082 if (!status)
3083 status = "UNKNOWN";
3084 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
3085 if (!strcasecmp(status, "CONGESTION"))
3086 res = indicate_congestion(c, "10");
3087 else if (!strcasecmp(status, "CHANUNAVAIL"))
3088 res = indicate_congestion(c, "10");
3089 else if (!strcasecmp(status, "BUSY"))
3090 res = indicate_busy(c, "10");
3091 error = 1; /* XXX disable message */
3092 break; /* exit from the 'for' loop */
3093 }
3094
3095 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
3096 break;
3097 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
3098 timeout = 1;
3099 if (!timeout
3100 && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
3101 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { /* Prepare the next cycle */
3102 set_ext_pri(c, dst_exten, 1);
3103 } else {
3104 /* No such extension */
3105 if (!timeout && !ast_strlen_zero(dst_exten)) {
3106 /* An invalid extension */
3108 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3109 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
3110 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
3111 set_ext_pri(c, "i", 1);
3112 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
3113 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3114 raise_exception(c, "INVALID", 1);
3115 } else {
3117 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
3118 dst_exten, ast_channel_context(c));
3119 found = 1; /* XXX disable message */
3120 break;
3121 }
3122 } else {
3123 /* A simple timeout */
3125 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3126 ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
3127 set_ext_pri(c, "t", 1);
3128 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
3129 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
3130 raise_exception(c, "RESPONSETIMEOUT", 1);
3131 } else {
3133 "Timeout, but no rule 't' or 'e' in context '%s'\n",
3135 found = 1; /* XXX disable message */
3136 break;
3137 }
3138 }
3139 }
3140 }
3141 }
3142
3143 if (!found && !error) {
3144 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
3145 }
3146
3147 if (!args || !args->no_hangup_chan) {
3151 S_COR(ast_channel_caller(c)->id.number.valid,
3152 ast_channel_caller(c)->id.number.str, NULL))) {
3154 }
3156 }
3157
3160 ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
3164
3165 if (!args || !args->no_hangup_chan) {
3166 ast_hangup(c);
3167 }
3168
3169 return AST_PBX_SUCCESS;
3170}
3171
3172/*!
3173 * \brief Increase call count for channel
3174 * \retval 0 on success
3175 * \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached
3176*/
3177static int increase_call_count(const struct ast_channel *c)
3178{
3179 int failed = 0;
3180 double curloadavg;
3181#if defined(HAVE_SYSINFO)
3182 struct sysinfo sys_info;
3183#endif
3184
3186 if (ast_option_maxcalls) {
3188 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", ast_option_maxcalls, ast_channel_name(c));
3189 failed = -1;
3190 }
3191 }
3192 if (ast_option_maxload) {
3193 getloadavg(&curloadavg, 1);
3194 if (curloadavg >= ast_option_maxload) {
3195 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", ast_option_maxload, ast_channel_name(c), curloadavg);
3196 failed = -1;
3197 }
3198 }
3199#if defined(HAVE_SYSINFO)
3200 if (option_minmemfree) {
3201 /* Make sure that the free system memory is above the configured low watermark */
3202 if (!sysinfo(&sys_info)) {
3203 /* Convert the amount of available RAM from mem_units to MB. The calculation
3204 * was done this way to avoid overflow problems */
3205 uint64_t curfreemem = sys_info.freeram + sys_info.bufferram;
3206 curfreemem *= sys_info.mem_unit;
3207 curfreemem /= 1024 * 1024;
3208 if (curfreemem < option_minmemfree) {
3209 ast_log(LOG_WARNING, "Available system memory (~%" PRIu64 "MB) is below the configured low watermark (%ldMB)\n",
3210 curfreemem, option_minmemfree);
3211 failed = -1;
3212 }
3213 }
3214 }
3215#endif
3216
3217 if (!failed) {
3218 countcalls++;
3219 totalcalls++;
3220 }
3222
3223 return failed;
3224}
3225
3226static void decrease_call_count(void)
3227{
3229 if (countcalls > 0)
3230 countcalls--;
3232}
3233
3234static void destroy_exten(struct ast_exten *e)
3235{
3236 if (e->priority == PRIORITY_HINT)
3237 ast_remove_hint(e);
3238
3239 if (e->peer_table)
3241 if (e->peer_label_table)
3243 if (e->datad)
3244 e->datad(e->data);
3245 ast_free(e);
3246}
3247
3248static void *pbx_thread(void *data)
3249{
3250 /* Oh joyous kernel, we're a new thread, with nothing to do but
3251 answer this channel and get it going.
3252 */
3253 /* NOTE:
3254 The launcher of this function _MUST_ increment 'countcalls'
3255 before invoking the function; it will be decremented when the
3256 PBX has finished running on the channel
3257 */
3258 struct ast_channel *c = data;
3259
3262
3263 pthread_exit(NULL);
3264
3265 return NULL;
3266}
3267
3269{
3270 pthread_t t;
3271
3272 if (!c) {
3273 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
3274 return AST_PBX_FAILED;
3275 }
3276
3277 if (!ast_fully_booted) {
3278 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
3279 return AST_PBX_FAILED;
3280 }
3281
3283 return AST_PBX_CALL_LIMIT;
3284
3285 /* Start a new thread, and get something handling this channel. */
3287 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
3289 return AST_PBX_FAILED;
3290 }
3291
3292 return AST_PBX_SUCCESS;
3293}
3294
3296{
3298
3299 if (!ast_fully_booted) {
3300 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
3301 return AST_PBX_FAILED;
3302 }
3303
3304 if (increase_call_count(c)) {
3305 return AST_PBX_CALL_LIMIT;
3306 }
3307
3308 res = __ast_pbx_run(c, args);
3309
3311
3312 return res;
3313}
3314
3316{
3317 return ast_pbx_run_args(c, NULL);
3318}
3319
3321{
3322 return countcalls;
3323}
3324
3326{
3327 return totalcalls;
3328}
3329
3331{
3332 int oldval = autofallthrough;
3333 autofallthrough = newval;
3334 return oldval;
3335}
3336
3338{
3339 int oldval = extenpatternmatchnew;
3340 extenpatternmatchnew = newval;
3341 return oldval;
3342}
3343
3344void pbx_set_overrideswitch(const char *newval)
3345{
3346 if (overrideswitch) {
3348 }
3349 if (!ast_strlen_zero(newval)) {
3350 overrideswitch = ast_strdup(newval);
3351 } else {
3353 }
3354}
3355
3356/*!
3357 * \brief lookup for a context with a given name,
3358 * \retval found context or NULL if not found.
3359 */
3360static struct ast_context *find_context(const char *context)
3361{
3362 struct ast_context item = {
3363 .name = context,
3364 };
3365
3367}
3368
3369/*!
3370 * \brief lookup for a context with a given name,
3371 * \retval with conlock held if found.
3372 * \retval NULL if not found.
3373 */
3374static struct ast_context *find_context_locked(const char *context)
3375{
3376 struct ast_context *c;
3377 struct ast_context item = {
3378 .name = context,
3379 };
3380
3383 if (!c) {
3385 }
3386
3387 return c;
3388}
3389
3390/*!
3391 * \brief Remove included contexts.
3392 * This function locks contexts list by &conlist, search for the right context
3393 * structure, leave context list locked and call ast_context_remove_include2
3394 * which removes include, unlock contexts list and return ...
3395 */
3396int ast_context_remove_include(const char *context, const char *include, const char *registrar)
3397{
3398 int ret = -1;
3399 struct ast_context *c;
3400
3401 c = find_context_locked(context);
3402 if (c) {
3403 /* found, remove include from this context ... */
3404 ret = ast_context_remove_include2(c, include, registrar);
3406 }
3407 return ret;
3408}
3409
3410/*!
3411 * \brief Locks context, remove included contexts, unlocks context.
3412 * When we call this function, &conlock lock must be locked, because when
3413 * we giving *con argument, some process can remove/change this context
3414 * and after that there can be segfault.
3415 *
3416 * \retval 0 on success.
3417 * \retval -1 on failure.
3418 */
3419int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
3420{
3421 int ret = -1;
3422 int idx;
3423
3424 ast_wrlock_context(con);
3425
3426 /* find our include */
3427 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
3428 struct ast_include *i = AST_VECTOR_GET(&con->includes, idx);
3429
3430 if (!strcmp(ast_get_include_name(i), include) &&
3431 (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) {
3432
3433 /* remove from list */
3434 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
3436
3437 /* free include and return */
3438 include_free(i);
3439 ret = 0;
3440 break;
3441 }
3442 }
3443
3444 ast_unlock_context(con);
3445
3446 return ret;
3447}
3448
3449/*!
3450 * \note This function locks contexts list by &conlist, search for the right context
3451 * structure, leave context list locked and call ast_context_remove_switch2
3452 * which removes switch, unlock contexts list and return ...
3453 */
3454int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
3455{
3456 int ret = -1; /* default error return */
3457 struct ast_context *c;
3458
3459 c = find_context_locked(context);
3460 if (c) {
3461 /* remove switch from this context ... */
3464 }
3465 return ret;
3466}
3467
3468/*!
3469 * \brief This function locks given context, removes switch, unlock context and
3470 * return.
3471 * \note When we call this function, &conlock lock must be locked, because when
3472 * we giving *con argument, some process can remove/change this context
3473 * and after that there can be segfault.
3474 *
3475 */
3476int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
3477{
3478 int idx;
3479 int ret = -1;
3480
3481 ast_wrlock_context(con);
3482
3483 /* walk switches */
3484 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
3485 struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx);
3486
3487 if (!strcmp(ast_get_switch_name(i), sw) &&
3488 !strcmp(ast_get_switch_data(i), data) &&
3489 (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) {
3490
3491 /* found, remove from list */
3492 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
3493 AST_VECTOR_REMOVE_ORDERED(&con->alts, idx);
3494
3495 /* free switch and return */
3496 sw_free(i);
3497 ret = 0;
3498 break;
3499 }
3500 }
3501
3502 ast_unlock_context(con);
3503
3504 return ret;
3505}
3506
3507/*! \note This function will lock conlock. */
3508int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
3509{
3511}
3512
3513int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
3514{
3515 int ret = -1; /* default error return */
3516 struct ast_context *c;
3517
3518 c = find_context_locked(context);
3519 if (c) { /* ... remove extension ... */
3521 matchcallerid, registrar, 0);
3523 }
3524
3525 return ret;
3526}
3527
3528/*!
3529 * \brief This functionc locks given context, search for the right extension and
3530 * fires out all peer in this extensions with given priority. If priority
3531 * is set to 0, all peers are removed. After that, unlock context and
3532 * return.
3533 * \note When do you want to call this function, make sure that &conlock is locked,
3534 * because some process can handle with your *con context before you lock
3535 * it.
3536 *
3537 */
3538int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
3539{
3541}
3542
3543int 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)
3544{
3545 struct ast_exten *exten, *prev_exten = NULL;
3546 struct ast_exten *peer;
3547 struct ast_exten ex, *exten2, *exten3;
3548 char dummy_name[1024];
3549 char dummy_cid[1024];
3550 struct ast_exten *previous_peer = NULL;
3551 struct ast_exten *next_peer = NULL;
3552 int found = 0;
3553
3554 if (!already_locked)
3555 ast_wrlock_context(con);
3556
3557#ifdef NEED_DEBUG
3558 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
3559#endif
3560#ifdef CONTEXT_DEBUG
3561 check_contexts(__FILE__, __LINE__);
3562#endif
3563 /* find this particular extension */
3564 ex.exten = dummy_name;
3565 ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1);
3566 ex.matchcid = matchcallerid;
3567 if (callerid) {
3568 ex.cidmatch = dummy_cid;
3569 ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1);
3570 } else {
3571 ex.cidmatch = NULL;
3572 }
3573 exten = ast_hashtab_lookup(con->root_table, &ex);
3574 if (exten) {
3575 if (priority == 0) {
3577 if (!exten2)
3578 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);
3579 if (con->pattern_tree) {
3580 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
3581
3582 if (x->exten) { /* this test for safety purposes */
3583 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
3584 x->exten = 0; /* get rid of what will become a bad pointer */
3585 } else {
3586 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
3587 }
3588 }
3589 } else {
3590 ex.priority = priority;
3591 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
3592 if (exten2) {
3593 if (exten2->label) { /* if this exten has a label, remove that, too */
3595 if (!exten3) {
3596 ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) "
3597 "from the peer_label_table of context %s, extension %s!\n",
3598 priority, exten2->label, con->name, exten2->name);
3599 }
3600 }
3601
3603 if (!exten3) {
3604 ast_log(LOG_ERROR, "Did not remove this priority (%d) from the "
3605 "peer_table of context %s, extension %s!\n",
3606 priority, con->name, exten2->name);
3607 }
3608 if (exten2 == exten && exten2->peer) {
3611 }
3612 if (ast_hashtab_size(exten->peer_table) == 0) {
3613 /* well, if the last priority of an exten is to be removed,
3614 then, the extension is removed, too! */
3616 if (!exten3) {
3617 ast_log(LOG_ERROR, "Did not remove this exten (%s) from the "
3618 "context root_table (%s) (priority %d)\n",
3619 exten->name, con->name, priority);
3620 }
3621 if (con->pattern_tree) {
3622 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
3623 if (x->exten) { /* this test for safety purposes */
3624 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
3625 x->exten = 0; /* get rid of what will become a bad pointer */
3626 }
3627 }
3628 }
3629 } else {
3630 ast_debug(3,"Could not find priority %d of exten %s in context %s!\n",
3631 priority, exten->name, con->name);
3632 }
3633 }
3634 } else {
3635 /* hmmm? this exten is not in this pattern tree? */
3636 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
3637 extension, con->name);
3638 }
3639#ifdef NEED_DEBUG
3640 if (con->pattern_tree) {
3641 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
3642 log_match_char_tree(con->pattern_tree, " ");
3643 }
3644#endif
3645
3646 /* scan the extension list to find first matching extension-registrar */
3647 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
3648 if (!strcmp(exten->exten, ex.exten) &&
3649 (!matchcallerid ||
3652 break;
3653 }
3654 }
3655 if (!exten) {
3656 /* we can't find right extension */
3657 if (!already_locked)
3658 ast_unlock_context(con);
3659 return -1;
3660 }
3661
3662 /* scan the priority list to remove extension with exten->priority == priority */
3663 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
3664 peer && !strcmp(peer->exten, ex.exten) &&
3665 (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, ex.cidmatch))) ;
3666 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
3667
3668 if ((priority == 0 || peer->priority == priority) &&
3669 (!registrar || !strcmp(peer->registrar, registrar) )) {
3670 found = 1;
3671
3672 /* we are first priority extension? */
3673 if (!previous_peer) {
3674 /*
3675 * We are first in the priority chain, so must update the extension chain.
3676 * The next node is either the next priority or the next extension
3677 */
3678 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
3679 if (peer->peer) {
3680 /* move the peer_table and peer_label_table down to the next peer, if
3681 it is there */
3684 peer->peer_table = NULL;
3686 }
3687 if (!prev_exten) { /* change the root... */
3688 con->root = next_node;
3689 } else {
3690 prev_exten->next = next_node; /* unlink */
3691 }
3692 if (peer->peer) { /* update the new head of the pri list */
3693 peer->peer->next = peer->next;
3694 }
3695 } else { /* easy, we are not first priority in extension */
3696 previous_peer->peer = peer->peer;
3697 }
3698
3699
3700 /* now, free whole priority extension */
3702 } else {
3703 previous_peer = peer;
3704 }
3705 }
3706 if (!already_locked)
3707 ast_unlock_context(con);
3708 return found ? 0 : -1;
3709}
3710
3711/*
3712 * Help for CLI commands ...
3713 */
3714
3715#if 0
3716/* This code can be used to test if the system survives running out of memory.
3717 * It might be an idea to put this in only if ENABLE_AUTODESTRUCT_TESTS is enabled.
3718 *
3719 * If you want to test this, these Linux sysctl flags might be appropriate:
3720 * vm.overcommit_memory = 2
3721 * vm.swappiness = 0
3722 *
3723 * <@Corydon76-home> I envision 'core eat disk space' and 'core eat file descriptors' now
3724 * <@mjordan> egads
3725 * <@mjordan> it's literally the 'big red' auto-destruct button
3726 * <@mjordan> if you were wondering who even builds such a thing.... well, now you know
3727 * ...
3728 * <@Corydon76-home> What about if they lived only if you defined TEST_FRAMEWORK? Shouldn't have those on production machines
3729 * <@mjordan> I think accompanied with an update to one of our README files that "no, really, TEST_FRAMEWORK isn't for you", I'd be fine
3730 */
3731static char *handle_eat_memory(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3732{
3733 void **blocks;
3734 int blocks_pos = 0;
3735 const int blocks_max = 50000;
3736 long long int allocated = 0;
3737 int sizes[] = {
3738 100 * 1024 * 1024,
3739 100 * 1024,
3740 2 * 1024,
3741 400,
3742 0
3743 };
3744 int i;
3745
3746 switch (cmd) {
3747 case CLI_INIT:
3748 /* To do: add method to free memory again? 5 minutes? */
3749 e->command = "core eat memory";
3750 e->usage =
3751 "Usage: core eat memory\n"
3752 " Eats all available memory so you can test if the system survives\n";
3753 return NULL;
3754 case CLI_GENERATE:
3755 return NULL;
3756 }
3757
3758 blocks = ast_malloc(sizeof(void*) * blocks_max);
3759 if (!blocks) {
3760 ast_log(LOG_ERROR, "Already out of mem?\n");
3761 return CLI_SUCCESS;
3762 }
3763
3764 for (i = 0; sizes[i]; ++i) {
3765 int alloc_size = sizes[i];
3766 ast_log(LOG_WARNING, "Allocating %d sized blocks (got %d blocks already)\n", alloc_size, blocks_pos);
3767 while (1) {
3768 void *block;
3769 if (blocks_pos >= blocks_max) {
3770 ast_log(LOG_ERROR, "Memory buffer too small? Run me again :)\n");
3771 break;
3772 }
3773
3774 block = ast_malloc(alloc_size);
3775 if (!block) {
3776 break;
3777 }
3778
3779 blocks[blocks_pos++] = block;
3780 allocated += alloc_size;
3781 }
3782 }
3783
3784 /* No freeing of the mem! */
3785 ast_log(LOG_WARNING, "Allocated %lld bytes total!\n", allocated);
3786 return CLI_SUCCESS;
3787}
3788#endif
3789
3790/*
3791 * 'show dialplan' CLI command implementation functions ...
3792 */
3793static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3794 int state)
3795{
3796 struct ast_context *c = NULL;
3797 char *ret = NULL;
3798 int which = 0;
3799 int wordlen;
3800
3801 /* we are do completion of [exten@]context on second position only */
3802 if (pos != 2)
3803 return NULL;
3804
3806
3807 wordlen = strlen(word);
3808
3809 /* walk through all contexts and return the n-th match */
3810 while ( (c = ast_walk_contexts(c)) ) {
3811 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
3813 break;
3814 }
3815 }
3816
3818
3819 return ret;
3820}
3821
3822/*! \brief Counters for the show dialplan manager command */
3831
3832/*! \brief helper function to print an extension */
3833static void print_ext(struct ast_exten *e, char * buf, int buflen)
3834{
3835 int prio = ast_get_extension_priority(e);
3836 if (prio == PRIORITY_HINT) {
3837 snprintf(buf, buflen, "hint: %s",
3839 } else {
3840 snprintf(buf, buflen, "%d. %s(%s)",
3841 prio, ast_get_extension_app(e),
3843 }
3844}
3845
3846/*! \brief Writes CLI output of a single extension for show dialplan */
3847static void show_dialplan_helper_extension_output(int fd, char *buf1, char *buf2, struct ast_exten *exten)
3848{
3850 ast_cli(fd, " %-17s %-45s [%s:%d]\n",
3851 buf1, buf2,
3854 return;
3855 }
3856
3857 ast_cli(fd, " %-17s %-45s [%s]\n",
3858 buf1, buf2, ast_get_extension_registrar(exten));
3859}
3860
3861/* XXX not verified */
3862static 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[])
3863{
3864 struct ast_context *c = NULL;
3865 int res = 0, old_total_exten = dpc->total_exten;
3866
3868
3869 /* walk all contexts ... */
3870 while ( (c = ast_walk_contexts(c)) ) {
3871 int idx;
3872 struct ast_exten *e;
3873#ifndef LOW_MEMORY
3874 char buf[1024], buf2[1024];
3875#else
3876 char buf[256], buf2[256];
3877#endif
3878 int context_info_printed = 0;
3879
3880 if (context && strcmp(ast_get_context_name(c), context))
3881 continue; /* skip this one, name doesn't match */
3882
3883 dpc->context_existence = 1;
3884
3886
3887 /* are we looking for exten too? if yes, we print context
3888 * only if we find our extension.
3889 * Otherwise print context even if empty ?
3890 * XXX i am not sure how the rinclude is handled.
3891 * I think it ought to go inside.
3892 */
3893 if (!exten) {
3894 dpc->total_context++;
3895 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3897 if (c->autohints) {
3898 ast_cli(fd, "Autohints support enabled\n");
3899 }
3900 context_info_printed = 1;
3901 }
3902
3903 /* walk extensions ... */
3904 e = NULL;
3905 while ( (e = ast_walk_context_extensions(c, e)) ) {
3906 struct ast_exten *p;
3907
3909 continue; /* skip, extension match failed */
3910
3911 dpc->extension_existence = 1;
3912
3913 /* may we print context info? */
3914 if (!context_info_printed) {
3915 dpc->total_context++;
3916 if (rinclude) { /* TODO Print more info about rinclude */
3917 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3919 } else {
3920 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3922 if (c->autohints) {
3923 ast_cli(fd, "Autohints support enabled\n");
3924 }
3925 }
3926 context_info_printed = 1;
3927 }
3928 dpc->total_prio++;
3929
3930 /* write extension name and first peer */
3931 if (e->matchcid == AST_EXT_MATCHCID_ON)
3932 snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
3933 else
3934 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
3935
3936 print_ext(e, buf2, sizeof(buf2));
3937
3939
3940 dpc->total_exten++;
3941 /* walk next extension peers */
3942 p = e; /* skip the first one, we already got it */
3943 while ( (p = ast_walk_extension_priorities(e, p)) ) {
3944 const char *el = ast_get_extension_label(p);
3945 dpc->total_prio++;
3946 if (el)
3947 snprintf(buf, sizeof(buf), " [%s]", el);
3948 else
3949 buf[0] = '\0';
3950 print_ext(p, buf2, sizeof(buf2));
3951
3953 }
3954 }
3955
3956 /* walk included and write info ... */
3957 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
3958 const struct ast_include *i = ast_context_includes_get(c, idx);
3959
3960 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
3961 if (exten) {
3962 /* Check all includes for the requested extension */
3963 if (includecount >= AST_PBX_MAX_STACK) {
3964 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
3965 } else {
3966 int dupe = 0;
3967 int x;
3968 for (x = 0; x < includecount; x++) {
3969 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3970 dupe++;
3971 break;
3972 }
3973 }
3974 if (!dupe) {
3975 includes[includecount] = ast_get_include_name(i);
3976 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3977 } else {
3978 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3979 }
3980 }
3981 } else {
3982 ast_cli(fd, " Include => %-45s [%s]\n",
3984 }
3985 }
3986
3987 /* walk ignore patterns and write info ... */
3988 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
3989 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
3990 const char *ipname = ast_get_ignorepat_name(ip);
3991 char ignorepat[AST_MAX_EXTENSION];
3992
3993 snprintf(buf, sizeof(buf), "'%s'", ipname);
3994 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3995 if (!exten || ast_extension_match(ignorepat, exten)) {
3996 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3998 }
3999 }
4000 if (!rinclude) {
4001 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
4002 const struct ast_sw *sw = ast_context_switches_get(c, idx);
4003
4004 snprintf(buf, sizeof(buf), "'%s/%s'",
4007 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
4009 }
4010 }
4011
4013
4014 /* if we print something in context, make an empty line */
4015 if (context_info_printed)
4016 ast_cli(fd, "\n");
4017 }
4019
4020 return (dpc->total_exten == old_total_exten) ? -1 : res;
4021}
4022
4023static 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[])
4024{
4025 struct ast_context *c = NULL;
4026 int res = 0, old_total_exten = dpc->total_exten;
4027
4028 ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
4029
4030 ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
4031 ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
4032 ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
4033 ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
4034 ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
4035 ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
4036 ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
4038
4039 /* walk all contexts ... */
4040 while ( (c = ast_walk_contexts(c)) ) {
4041 int context_info_printed = 0;
4042
4043 if (context && strcmp(ast_get_context_name(c), context))
4044 continue; /* skip this one, name doesn't match */
4045
4046 dpc->context_existence = 1;
4047
4048 if (!c->pattern_tree) {
4049 /* Ignore check_return warning from Coverity for ast_exists_extension below */
4050 ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
4051 }
4052
4054
4055 dpc->total_context++;
4056 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
4058 context_info_printed = 1;
4059
4060 if (c->pattern_tree)
4061 {
4062 cli_match_char_tree(c->pattern_tree, " ", fd);
4063 } else {
4064 ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
4065 }
4066
4068
4069 /* if we print something in context, make an empty line */
4070 if (context_info_printed)
4071 ast_cli(fd, "\n");
4072 }
4074
4075 return (dpc->total_exten == old_total_exten) ? -1 : res;
4076}
4077
4078static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4079{
4080 char *exten = NULL, *context = NULL;
4081 /* Variables used for different counters */
4082 struct dialplan_counters counters;
4083 const char *incstack[AST_PBX_MAX_STACK];
4084
4085 switch (cmd) {
4086 case CLI_INIT:
4087 e->command = "dialplan show";
4088 e->usage =
4089 "Usage: dialplan show [[exten@]context]\n"
4090 " Show dialplan\n";
4091 return NULL;
4092 case CLI_GENERATE:
4093 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
4094 }
4095
4096 memset(&counters, 0, sizeof(counters));
4097
4098 if (a->argc != 2 && a->argc != 3)
4099 return CLI_SHOWUSAGE;
4100
4101 /* we obtain [exten@]context? if yes, split them ... */
4102 if (a->argc == 3) {
4103 if (strchr(a->argv[2], '@')) { /* split into exten & context */
4104 context = ast_strdupa(a->argv[2]);
4105 exten = strsep(&context, "@");
4106 /* change empty strings to NULL */
4107 if (ast_strlen_zero(exten))
4108 exten = NULL;
4109 } else { /* no '@' char, only context given */
4110 context = ast_strdupa(a->argv[2]);
4111 }
4112 if (ast_strlen_zero(context))
4113 context = NULL;
4114 }
4115 /* else Show complete dial plan, context and exten are NULL */
4116 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
4117
4118 /* check for input failure and throw some error messages */
4119 if (context && !counters.context_existence) {
4120 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
4121 return CLI_FAILURE;
4122 }
4123
4124 if (exten && !counters.extension_existence) {
4125 if (context)
4126 ast_cli(a->fd, "There is no existence of %s@%s extension\n",
4127 exten, context);
4128 else
4129 ast_cli(a->fd,
4130 "There is no existence of '%s' extension in all contexts\n",
4131 exten);
4132 return CLI_FAILURE;
4133 }
4134
4135 ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
4136 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
4137 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
4138 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
4139
4140 /* everything ok */
4141 return CLI_SUCCESS;
4142}
4143
4144/*! \brief Send ack once */
4145static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4146{
4147 char *exten = NULL, *context = NULL;
4148 /* Variables used for different counters */
4149 struct dialplan_counters counters;
4150 const char *incstack[AST_PBX_MAX_STACK];
4151
4152 switch (cmd) {
4153 case CLI_INIT:
4154 e->command = "dialplan debug";
4155 e->usage =
4156 "Usage: dialplan debug [context]\n"
4157 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
4158 return NULL;
4159 case CLI_GENERATE:
4160 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
4161 }
4162
4163 memset(&counters, 0, sizeof(counters));
4164
4165 if (a->argc != 2 && a->argc != 3)
4166 return CLI_SHOWUSAGE;
4167
4168 /* we obtain [exten@]context? if yes, split them ... */
4169 /* note: we ignore the exten totally here .... */
4170 if (a->argc == 3) {
4171 if (strchr(a->argv[2], '@')) { /* split into exten & context */
4172 context = ast_strdupa(a->argv[2]);
4173 exten = strsep(&context, "@");
4174 /* change empty strings to NULL */
4175 if (ast_strlen_zero(exten))
4176 exten = NULL;
4177 } else { /* no '@' char, only context given */
4178 context = ast_strdupa(a->argv[2]);
4179 }
4180 if (ast_strlen_zero(context))
4181 context = NULL;
4182 }
4183 /* else Show complete dial plan, context and exten are NULL */
4184 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
4185
4186 /* check for input failure and throw some error messages */
4187 if (context && !counters.context_existence) {
4188 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
4189 return CLI_FAILURE;
4190 }
4191
4192
4193 ast_cli(a->fd,"-= %d %s. =-\n",
4194 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
4195
4196 /* everything ok */
4197 return CLI_SUCCESS;
4198}
4199
4200/*! \brief Send ack once */
4201static void manager_dpsendack(struct mansession *s, const struct message *m)
4202{
4203 astman_send_listack(s, m, "DialPlan list will follow", "start");
4204}
4205
4206/*! \brief Show dialplan extensions
4207 * XXX this function is similar but not exactly the same as the CLI's
4208 * show dialplan. Must check whether the difference is intentional or not.
4209 */
4210static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
4211 const char *actionidtext, const char *context,
4212 const char *exten, struct dialplan_counters *dpc,
4213 const struct ast_include *rinclude,
4214 int includecount, const char *includes[])
4215{
4216 struct ast_context *c;
4217 int res = 0, old_total_exten = dpc->total_exten;
4218
4219 if (ast_strlen_zero(exten))
4220 exten = NULL;
4221 if (ast_strlen_zero(context))
4222 context = NULL;
4223
4224 ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
4225
4226 /* try to lock contexts */
4227 if (ast_rdlock_contexts()) {
4228 astman_send_error(s, m, "Failed to lock contexts");
4229 ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
4230 return -1;
4231 }
4232
4233 c = NULL; /* walk all contexts ... */
4234 while ( (c = ast_walk_contexts(c)) ) {
4235 int idx;
4236 struct ast_exten *e;
4237
4238 if (context && strcmp(ast_get_context_name(c), context) != 0)
4239 continue; /* not the name we want */
4240
4241 dpc->context_existence = 1;
4242 dpc->total_context++;
4243
4244 ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
4245
4246 if (ast_rdlock_context(c)) { /* failed to lock */
4247 ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
4248 continue;
4249 }
4250
4251 /* XXX note- an empty context is not printed */
4252 e = NULL; /* walk extensions in context */
4253 while ( (e = ast_walk_context_extensions(c, e)) ) {
4254 struct ast_exten *p;
4255
4256 /* looking for extension? is this our extension? */
4258 /* not the one we are looking for, continue */
4259 ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
4260 continue;
4261 }
4262 ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
4263
4264 dpc->extension_existence = 1;
4265
4266 dpc->total_exten++;
4267
4268 p = NULL; /* walk next extension peers */
4269 while ( (p = ast_walk_extension_priorities(e, p)) ) {
4270 int prio = ast_get_extension_priority(p);
4271
4272 dpc->total_prio++;
4273 if (!dpc->total_items++)
4274 manager_dpsendack(s, m);
4275 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
4276 astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
4277
4278 /* XXX maybe make this conditional, if p != e ? */
4280 astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
4281
4282 if (prio == PRIORITY_HINT) {
4283 astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
4284 } else {
4285 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));
4286 }
4287 astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
4288 }
4289 }
4290
4291 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
4292 const struct ast_include *i = ast_context_includes_get(c, idx);
4293
4294 if (exten) {
4295 /* Check all includes for the requested extension */
4296 if (includecount >= AST_PBX_MAX_STACK) {
4297 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
4298 } else {
4299 int dupe = 0;
4300 int x;
4301 for (x = 0; x < includecount; x++) {
4302 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
4303 dupe++;
4304 break;
4305 }
4306 }
4307 if (!dupe) {
4308 includes[includecount] = ast_get_include_name(i);
4309 manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
4310 } else {
4311 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
4312 }
4313 }
4314 } else {
4315 if (!dpc->total_items++)
4316 manager_dpsendack(s, m);
4317 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
4318 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));
4319 astman_append(s, "\r\n");
4320 ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
4321 }
4322 }
4323
4324 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
4325 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
4326 const char *ipname = ast_get_ignorepat_name(ip);
4327 char ignorepat[AST_MAX_EXTENSION];
4328
4329 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
4330 if (!exten || ast_extension_match(ignorepat, exten)) {
4331 if (!dpc->total_items++)
4332 manager_dpsendack(s, m);
4333 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
4334 astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
4335 astman_append(s, "\r\n");
4336 }
4337 }
4338 if (!rinclude) {
4339 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
4340 const struct ast_sw *sw = ast_context_switches_get(c, idx);
4341
4342 if (!dpc->total_items++)
4343 manager_dpsendack(s, m);
4344 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
4345 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));
4346 astman_append(s, "\r\n");
4347 ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
4348 }
4349 }
4350
4352 }
4354
4355 if (dpc->total_exten == old_total_exten) {
4356 ast_debug(3, "manager_show_dialplan: Found nothing new\n");
4357 /* Nothing new under the sun */
4358 return -1;
4359 } else {
4360 return res;
4361 }
4362}
4363
4364/*! \brief Manager listing of dial plan */
4365static int manager_show_dialplan(struct mansession *s, const struct message *m)
4366{
4367 const char *exten, *context;
4368 const char *id = astman_get_header(m, "ActionID");
4369 const char *incstack[AST_PBX_MAX_STACK];
4370 char idtext[256];
4371
4372 /* Variables used for different counters */
4373 struct dialplan_counters counters;
4374
4375 if (!ast_strlen_zero(id))
4376 snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
4377 else
4378 idtext[0] = '\0';
4379
4380 memset(&counters, 0, sizeof(counters));
4381
4382 exten = astman_get_header(m, "Extension");
4383 context = astman_get_header(m, "Context");
4384
4385 manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL, 0, incstack);
4386
4387 if (!ast_strlen_zero(context) && !counters.context_existence) {
4388 char errorbuf[BUFSIZ];
4389
4390 snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
4391 astman_send_error(s, m, errorbuf);
4392 return 0;
4393 }
4394 if (!ast_strlen_zero(exten) && !counters.extension_existence) {
4395 char errorbuf[BUFSIZ];
4396
4397 if (!ast_strlen_zero(context))
4398 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
4399 else
4400 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
4401 astman_send_error(s, m, errorbuf);
4402 return 0;
4403 }
4404
4405 if (!counters.total_items) {
4406 manager_dpsendack(s, m);
4407 }
4408
4409 astman_send_list_complete_start(s, m, "ShowDialPlanComplete", counters.total_items);
4410 astman_append(s,
4411 "ListExtensions: %d\r\n"
4412 "ListPriorities: %d\r\n"
4413 "ListContexts: %d\r\n",
4414 counters.total_exten, counters.total_prio, counters.total_context);
4416
4417 /* everything ok */
4418 return 0;
4419}
4420
4421#ifdef AST_DEVMODE
4422static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4423{
4424 struct ast_devstate_aggregate agg;
4425 int i, j, exten, combined;
4426
4427 switch (cmd) {
4428 case CLI_INIT:
4429 e->command = "core show device2extenstate";
4430 e->usage =
4431 "Usage: core show device2extenstate\n"
4432 " Lists device state to extension state combinations.\n";
4433 case CLI_GENERATE:
4434 return NULL;
4435 }
4436 for (i = 0; i < AST_DEVICE_TOTAL; i++) {
4437 for (j = 0; j < AST_DEVICE_TOTAL; j++) {
4441 combined = ast_devstate_aggregate_result(&agg);
4442 exten = ast_devstate_to_extenstate(combined);
4443 ast_cli(a->fd, "\n Exten:%14s CombinedDevice:%12s Dev1:%12s Dev2:%12s", ast_extension_state2str(exten), ast_devstate_str(combined), ast_devstate_str(j), ast_devstate_str(i));
4444 }
4445 }
4446 ast_cli(a->fd, "\n");
4447 return CLI_SUCCESS;
4448}
4449#endif
4450
4451static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4452{
4453 int oldval = 0;
4454
4455 switch (cmd) {
4456 case CLI_INIT:
4457 e->command = "dialplan set extenpatternmatchnew true";
4458 e->usage =
4459 "Usage: dialplan set extenpatternmatchnew true|false\n"
4460 " Use the NEW extension pattern matching algorithm, true or false.\n";
4461 return NULL;
4462 case CLI_GENERATE:
4463 return NULL;
4464 }
4465
4466 if (a->argc != 4)
4467 return CLI_SHOWUSAGE;
4468
4469 oldval = pbx_set_extenpatternmatchnew(1);
4470
4471 if (oldval)
4472 ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
4473 else
4474 ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
4475
4476 return CLI_SUCCESS;
4477}
4478
4479static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4480{
4481 int oldval = 0;
4482
4483 switch (cmd) {
4484 case CLI_INIT:
4485 e->command = "dialplan set extenpatternmatchnew false";
4486 e->usage =
4487 "Usage: dialplan set extenpatternmatchnew true|false\n"
4488 " Use the NEW extension pattern matching algorithm, true or false.\n";
4489 return NULL;
4490 case CLI_GENERATE:
4491 return NULL;
4492 }
4493
4494 if (a->argc != 4)
4495 return CLI_SHOWUSAGE;
4496
4497 oldval = pbx_set_extenpatternmatchnew(0);
4498
4499 if (!oldval)
4500 ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
4501 else
4502 ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
4503
4504 return CLI_SUCCESS;
4505}
4506
4507/*
4508 * CLI entries for upper commands ...
4509 */
4510static struct ast_cli_entry pbx_cli[] = {
4511#if 0
4512 AST_CLI_DEFINE(handle_eat_memory, "Eats all available memory"),
4513#endif
4514#ifdef AST_DEVMODE
4515 AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
4516#endif
4517 AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
4518 AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
4519 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
4520 AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
4521};
4522
4524{
4525 struct ast_context *context = NULL;
4526 struct ast_exten *eroot = NULL, *e = NULL;
4527
4529 while ((context = ast_walk_contexts(context))) {
4530 while ((eroot = ast_walk_context_extensions(context, eroot))) {
4531 while ((e = ast_walk_extension_priorities(eroot, e))) {
4532 if (e->cached_app == app)
4533 e->cached_app = NULL;
4534 }
4535 }
4536 }
4538
4539 return;
4540}
4541
4542struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
4543{
4544 struct ast_context *tmp, **local_contexts;
4545 struct ast_context search = {
4546 .name = name,
4547 };
4548 size_t name_bytes = strlen(name);
4549 size_t registrar_bytes = strlen(registrar);
4550 int length = sizeof(struct ast_context) + name_bytes + registrar_bytes + 2;
4551
4552 if (!contexts_table) {
4553 /* Protect creation of contexts_table from reentrancy. */
4555 if (!contexts_table) {
4561 0);
4562 }
4564 }
4565
4566 if (!extcontexts) {
4569 tmp = ast_hashtab_lookup(contexts_table, &search);
4570 if (tmp) {
4571 tmp->refcount++;
4573 return tmp;
4574 }
4575 } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
4576 local_contexts = extcontexts;
4577 tmp = ast_hashtab_lookup(exttable, &search);
4578 if (tmp) {
4579 tmp->refcount++;
4580 return tmp;
4581 }
4582 }
4583
4584 if ((tmp = ast_calloc(1, length))) {
4585 ast_rwlock_init(&tmp->lock);
4586 tmp->name = memcpy(&tmp->data[0], name, name_bytes);
4587 tmp->registrar = memcpy(&tmp->data[name_bytes + 1], registrar, registrar_bytes);
4588 tmp->root = NULL;
4589 tmp->root_table = NULL;
4590 AST_VECTOR_INIT(&tmp->includes, 0);
4591 AST_VECTOR_INIT(&tmp->ignorepats, 0);
4592 AST_VECTOR_INIT(&tmp->alts, 0);
4593 tmp->refcount = 1;
4594
4595 /* The context 'name' must be stored at the beginning of 'data.' The
4596 * order of subsequent strings (currently only 'registrar') is not
4597 * relevant. */
4598 ast_assert(tmp->name == &tmp->data[0]);
4599 } else {
4600 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
4601 if (!extcontexts) {
4603 }
4604 return NULL;
4605 }
4606
4607 if (!extcontexts) {
4609 tmp->next = *local_contexts;
4610 *local_contexts = tmp;
4611 ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
4613 } else {
4615 tmp->next = *local_contexts;
4616 if (exttable)
4617 ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
4618
4619 *local_contexts = tmp;
4620 }
4621 ast_debug(1, "Registered extension context '%s'; registrar: %s, scope: %s\n", tmp->name, registrar,
4622 tmp->scope == AST_CONTEXT_SCOPE_LOCAL ? "local": "global");
4623 return tmp;
4624}
4625
4627{
4628 con->autohints = enabled;
4629
4630 if (con->scope == AST_CONTEXT_SCOPE_GLOBAL) {
4631 if (con->autohints) {
4633 } else {
4635 }
4636 }
4637}
4638
4639void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
4640
4642{
4643 int idx;
4644
4645 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);
4646 /* copy in the includes, switches, and ignorepats */
4647 /* walk through includes */
4648 for (idx = 0; idx < ast_context_includes_count(old); idx++) {
4649 const struct ast_include *i = ast_context_includes_get(old, idx);
4650
4651 if (!strcmp(ast_get_include_registrar(i), registrar)) {
4652 continue; /* not mine */
4653 }
4655 }
4656
4657 /* walk through switches */
4658 for (idx = 0; idx < ast_context_switches_count(old); idx++) {
4659 const struct ast_sw *sw = ast_context_switches_get(old, idx);
4660
4661 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
4662 continue; /* not mine */
4663 }
4665 }
4666
4667 /* walk thru ignorepats ... */
4668 for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) {
4669 const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx);
4670
4671 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) {
4672 continue; /* not mine */
4673 }
4675 }
4676}
4677
4678/* the purpose of this routine is to duplicate a context, with all its substructure,
4679 except for any extens that have a matching registrar */
4680static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
4681{
4682 struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
4683 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
4684 struct ast_hashtab_iter *exten_iter;
4685 struct ast_hashtab_iter *prio_iter;
4686 int insert_count = 0;
4687 int first = 1;
4688
4689 /* We'll traverse all the extensions/prios, and see which are not registrar'd with
4690 the current registrar, and copy them to the new context. If the new context does not
4691 exist, we'll create it "on demand". If no items are in this context to copy, then we'll
4692 only create the empty matching context if the old one meets the criteria */
4693
4694 if (context->root_table) {
4695 exten_iter = ast_hashtab_start_traversal(context->root_table);
4696 while ((exten_item=ast_hashtab_next(exten_iter))) {
4697 if (new) {
4698 new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
4699 } else {
4700 new_exten_item = NULL;
4701 }
4702 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
4703 while ((prio_item=ast_hashtab_next(prio_iter))) {
4704 int res1;
4705 char *dupdstr;
4706
4707 if (new_exten_item) {
4708 new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
4709 } else {
4710 new_prio_item = NULL;
4711 }
4712 if (strcmp(prio_item->registrar,registrar) == 0) {
4713 struct ast_exten *pattern_exten;
4714 struct pbx_find_info q = { .stacklen = 0 };
4715
4716 if (prio_item->priority != PRIORITY_HINT || prio_item->name[0] == '_' || new_prio_item || !new) {
4717 continue;
4718 }
4719
4720 /*
4721 * This hint no longer exists in the new context, but it may have been created as a result of
4722 * a pattern match so see if a pattern match matches it. If it does then we add it in to the new
4723 * context using the registrar of the pattern match.
4724 */
4725 pattern_exten = pbx_find_extension(NULL, new, &q, context->name,
4726 prio_item->name, PRIORITY_HINT, NULL, "", E_MATCH);
4727 if (pattern_exten && !strcmp(q.foundcontext, context->name)) {
4728 /*
4729 * This logic doesn't check whether it's a pattern match or not because if it was
4730 * an exact match we would have already skipped it above due to new_prio_item being
4731 * present. Logically it could only ever be a pattern match here.
4732 */
4733 dupdstr = ast_strdup(prio_item->data);
4734
4735 res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label,
4736 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar,
4737 prio_item->registrar_file, prio_item->registrar_line);
4738 }
4739
4740 continue;
4741 }
4742 /* make sure the new context exists, so we have somewhere to stick this exten/prio */
4743 if (!new) {
4744 new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
4745 if (new) {
4746 new->autohints = context->autohints;
4747 if (new->autohints) {
4749 }
4750 new->scope = AST_CONTEXT_SCOPE_GLOBAL;
4751 }
4752 }
4753
4754 /* copy in the includes, switches, and ignorepats */
4755 if (first) { /* but, only need to do this once */
4757 first = 0;
4758 }
4759
4760 if (!new) {
4761 ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
4762 ast_hashtab_end_traversal(prio_iter);
4763 ast_hashtab_end_traversal(exten_iter);
4764 return; /* no sense continuing. */
4765 }
4766 /* we will not replace existing entries in the new context with stuff from the old context.
4767 but, if this is because of some sort of registrar conflict, we ought to say something... */
4768
4769 dupdstr = ast_strdup(prio_item->data);
4770
4771 res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label,
4772 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar,
4773 prio_item->registrar_file, prio_item->registrar_line);
4774 if (!res1 && new_exten_item && new_prio_item){
4775 ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
4776 context->name, prio_item->name, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
4777 } else {
4778 /* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place,
4779 and no double frees take place, either! */
4780 insert_count++;
4781 }
4782 }
4783 ast_hashtab_end_traversal(prio_iter);
4784 }
4785 ast_hashtab_end_traversal(exten_iter);
4786 } else if (new) {
4787 /* If the context existed but had no extensions, we still want to merge
4788 * the includes, switches and ignore patterns.
4789 */
4791 }
4792
4793 if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
4794 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
4795 /* we could have given it the registrar of the other module who incremented the refcount,
4796 but that's not available, so we give it the registrar we know about */
4797 new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
4798
4799 if (new) {
4800 new->autohints = context->autohints;
4801 if (new->autohints) {
4803 }
4804 new->scope = AST_CONTEXT_SCOPE_GLOBAL;
4805 }
4806
4807 /* copy in the includes, switches, and ignorepats */
4809 }
4810}
4811
4812static int context_promote(struct ast_context *context)
4813{
4814 struct ast_exten *exten_item, *prio_item;
4815 struct ast_hashtab_iter *exten_iter;
4816 struct ast_hashtab_iter *prio_iter;
4817
4818 /* Contexts already promoted to global have been handled previously, so skip */
4819 if (context->scope == AST_CONTEXT_SCOPE_GLOBAL) {
4820 return 0;
4821 }
4822
4823 /* Enable or remove autohints as needed */
4824 if (context->autohints) {
4826 } else {
4828 }
4829
4830 /* Further handling requires extensions to exist */
4831 if (!context->root_table) {
4832 return 0;
4833 }
4834
4835 /*
4836 * Hints are stateless but extension state is not. To keep extension state up to date
4837 * we go through all the hints on contexts promoted from local scope to global scope and
4838 * inform extension state as it is purely driven based on global scope dialplan.
4839 */
4840 exten_iter = ast_hashtab_start_traversal(context->root_table);
4841 while ((exten_item = ast_hashtab_next(exten_iter))) {
4842 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
4843 while ((prio_item = ast_hashtab_next(prio_iter))) {
4844 if (prio_item->priority != PRIORITY_HINT) {
4845 continue;
4846 }
4847 pbx_extension_state_hint_set(prio_item, context);
4848 }
4849 ast_hashtab_end_traversal(prio_iter);
4850 }
4851 ast_hashtab_end_traversal(exten_iter);
4852
4853 context->scope = AST_CONTEXT_SCOPE_GLOBAL;
4854
4855 return 1;
4856}
4857
4858/* XXX this does not check that multiple contexts are merged */
4859void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
4860{
4861 double ft;
4862 struct ast_context *tmp;
4863 struct ast_context *oldcontextslist;
4864 struct ast_hashtab *oldtable;
4865 struct ast_hashtab_iter *iter;
4866 int ctx_count = 0, promoted_count = 0;
4867 struct timeval begintime;
4868 struct timeval writelocktime;
4869 struct timeval endlocktime;
4870 struct timeval enddeltime;
4871
4872 begintime = ast_tvnow();
4874
4875 if (!contexts_table) {
4876 /* Well, that's odd. There are no contexts. */
4877 contexts_table = exttable;
4878 contexts = *extcontexts;
4879
4881 while ((tmp = ast_hashtab_next(iter))) {
4882 context_promote(tmp);
4883 }
4885
4887 return;
4888 }
4889
4891 while ((tmp = ast_hashtab_next(iter))) {
4892 ++ctx_count;
4893 context_merge(extcontexts, exttable, tmp, registrar);
4894 }
4896
4897 writelocktime = ast_tvnow();
4898
4899 /* save the old table and list */
4900 oldtable = contexts_table;
4901 oldcontextslist = contexts;
4902
4903 /* move in the new table and list */
4904 contexts_table = exttable;
4905 contexts = *extcontexts;
4906
4908 while ((tmp = ast_hashtab_next(iter))) {
4909 promoted_count += context_promote(tmp);
4910 }
4912
4913 /* ctx_count is still the number of old contexts before the merge,
4914 * use the new count when we tell the user how many contexts exist. */
4915 ctx_count = ast_hashtab_size(contexts_table);
4916
4918
4919 endlocktime = ast_tvnow();
4920
4921 /*
4922 * The old list and hashtab no longer are relevant, delete them
4923 * while the rest of asterisk is now freely using the new stuff
4924 * instead.
4925 */
4926
4927 ast_hashtab_destroy(oldtable, NULL);
4928
4929 for (tmp = oldcontextslist; tmp; ) {
4930 struct ast_context *next; /* next starting point */
4931
4932 next = tmp->next;
4934 tmp = next;
4935 }
4936 enddeltime = ast_tvnow();
4937
4938 ft = ast_tvdiff_us(writelocktime, begintime);
4939 ft /= 1000000.0;
4940 ast_verb(5,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
4941
4942 ft = ast_tvdiff_us(endlocktime, writelocktime);
4943 ft /= 1000000.0;
4944 ast_verb(5,"Time to promote contexts and swap in new dialplan: %8.6f sec\n", ft);
4945
4946 ft = ast_tvdiff_us(enddeltime, endlocktime);
4947 ft /= 1000000.0;
4948 ast_verb(5,"Time to delete the old dialplan: %8.6f sec\n", ft);
4949
4950 ft = ast_tvdiff_us(enddeltime, begintime);
4951 ft /= 1000000.0;
4952 ast_verb(5,"Total time merge_contexts_delete: %8.6f sec\n", ft);
4953 ast_verb(5, "%s successfully loaded %d contexts after incorporating %d promoted contexts (enable debug for details).\n",
4954 registrar, ctx_count, promoted_count);
4955}
4956
4957/*
4958 * errno values
4959 * EBUSY - can't lock
4960 * ENOENT - no existence of context
4961 */
4962int ast_context_add_include(const char *context, const char *include, const char *registrar)
4963{
4964 int ret = -1;
4965 struct ast_context *c;
4966
4967 c = find_context_locked(context);
4968 if (c) {
4969 ret = ast_context_add_include2(c, include, registrar);
4971 }
4972 return ret;
4973}
4974
4975/*
4976 * errno values
4977 * ENOMEM - out of memory
4978 * EBUSY - can't lock
4979 * EEXIST - already included
4980 * EINVAL - there is no existence of context for inclusion
4981 */
4982int ast_context_add_include2(struct ast_context *con, const char *value,
4983 const char *registrar)
4984{
4985 struct ast_include *new_include;
4986 int idx;
4987
4988 /* allocate new include structure ... */
4989 new_include = include_alloc(value, registrar);
4990 if (!new_include) {
4991 return -1;
4992 }
4993
4994 ast_wrlock_context(con);
4995
4996 /* ... go to last include and check if context is already included too... */
4997 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
4998 const struct ast_include *i = ast_context_includes_get(con, idx);
4999
5000 if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) {
5001 include_free(new_include);
5002 ast_unlock_context(con);
5003 errno = EEXIST;
5004 return -1;
5005 }
5006 }
5007
5008 /* ... include new context into context list, unlock, return */
5009 if (AST_VECTOR_APPEND(&con->includes, new_include)) {
5010 include_free(new_include);
5011 ast_unlock_context(con);
5012 return -1;
5013 }
5014 ast_debug(1, "Including context '%s' in context '%s'\n",
5015 ast_get_include_name(new_include), ast_get_context_name(con));
5016
5017 ast_unlock_context(con);
5018
5019 return 0;
5020}
5021
5022/*
5023 * errno values
5024 * EBUSY - can't lock
5025 * ENOENT - no existence of context
5026 */
5027int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
5028{
5029 int ret = -1;
5030 struct ast_context *c;
5031
5032 c = find_context_locked(context);
5033 if (c) { /* found, add switch to this context */
5034 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
5036 }
5037 return ret;
5038}
5039
5040/*
5041 * errno values
5042 * ENOMEM - out of memory
5043 * EBUSY - can't lock
5044 * EEXIST - already included
5045 * EINVAL - there is no existence of context for inclusion
5046 */
5047int ast_context_add_switch2(struct ast_context *con, const char *value,
5048 const char *data, int eval, const char *registrar)
5049{
5050 int idx;
5051 struct ast_sw *new_sw;
5052
5053 /* allocate new sw structure ... */
5054 if (!(new_sw = sw_alloc(value, data, eval, registrar))) {
5055 return -1;
5056 }
5057
5058 /* ... try to lock this context ... */
5059 ast_wrlock_context(con);
5060
5061 /* ... go to last sw and check if context is already swd too... */
5062 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
5063 const struct ast_sw *i = ast_context_switches_get(con, idx);
5064
5065 if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) &&
5066 !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) {
5067 sw_free(new_sw);
5068 ast_unlock_context(con);
5069 errno = EEXIST;
5070 return -1;
5071 }
5072 }
5073
5074 /* ... sw new context into context list, unlock, return */
5075 if (AST_VECTOR_APPEND(&con->alts, new_sw)) {
5076 sw_free(new_sw);
5077 ast_unlock_context(con);
5078 return -1;
5079 }
5080
5081 ast_verb(3, "Including switch '%s/%s' in context '%s'\n",
5083
5084 ast_unlock_context(con);
5085
5086 return 0;
5087}
5088
5089/*
5090 * EBUSY - can't lock
5091 * ENOENT - there is not context existence
5092 */
5093int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
5094{
5095 int ret = -1;
5096 struct ast_context *c;
5097
5098 c = find_context_locked(context);
5099 if (c) {
5100 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
5102 }
5103 return ret;
5104}
5105
5106int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
5107{
5108 int idx;
5109
5110 ast_wrlock_context(con);
5111
5112 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
5113 struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx);
5114
5115 if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) &&
5118 ignorepat_free(ip);
5119 ast_unlock_context(con);
5120 return 0;
5121 }
5122 }
5123
5124 ast_unlock_context(con);
5125 errno = EINVAL;
5126 return -1;
5127}
5128
5129/*
5130 * EBUSY - can't lock
5131 * ENOENT - there is no existence of context
5132 */
5133int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
5134{
5135 int ret = -1;
5136 struct ast_context *c;
5137
5138 c = find_context_locked(context);
5139 if (c) {
5142 }
5143 return ret;
5144}
5145
5146int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
5147{
5148 struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar);
5149 int idx;
5150
5151 if (!ignorepat) {
5152 return -1;
5153 }
5154
5155 ast_wrlock_context(con);
5156 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
5157 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
5158
5159 if (!strcasecmp(ast_get_ignorepat_name(i), value)) {
5160 /* Already there */
5161 ast_unlock_context(con);
5162 ignorepat_free(ignorepat);
5163 errno = EEXIST;
5164 return -1;
5165 }
5166 }
5167 if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) {
5168 ignorepat_free(ignorepat);
5169 ast_unlock_context(con);
5170 return -1;
5171 }
5172 ast_unlock_context(con);
5173
5174 return 0;
5175}
5176
5177int ast_ignore_pattern(const char *context, const char *pattern)
5178{
5179 int ret = 0;
5180 struct ast_context *con;
5181
5183 con = ast_context_find(context);
5184 if (con) {
5185 int idx;
5186
5187 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
5188 const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx);
5189
5191 ret = 1;
5192 break;
5193 }
5194 }
5195 }
5197
5198 return ret;
5199}
5200
5201/*
5202 * EBUSY - can't lock
5203 * ENOENT - no existence of context
5204 *
5205 */
5206int ast_add_extension(const char *context, int replace, const char *extension,
5207 int priority, const char *label, const char *callerid,
5208 const char *application, void *data, void (*datad)(void *), const char *registrar)
5209{
5210 int ret = -1;
5211 struct ast_context *c;
5212
5213 c = find_context_locked(context);
5214 if (c) {
5215 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
5216 application, data, datad, registrar, NULL, 0);
5218 }
5219
5220 return ret;
5221}
5222
5223int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
5224{
5225 if (!chan)
5226 return -1;
5227
5228 ast_channel_lock(chan);
5229
5231 ast_channel_unlock(chan);
5232 return -1;
5233 }
5234 if (!ast_strlen_zero(context))
5235 ast_channel_context_set(chan, context);
5236 if (!ast_strlen_zero(exten))
5237 ast_channel_exten_set(chan, exten);
5238 if (priority > -1) {
5239 /* see flag description in channel.h for explanation */
5241 --priority;
5242 }
5244 }
5245
5246 ast_channel_unlock(chan);
5247
5248 return 0;
5249}
5250
5251int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
5252{
5253 struct ast_channel *newchan;
5254
5255 ast_channel_lock(chan);
5256 /* Channels in a bridge or running a PBX can be sent directly to the specified destination */
5257 if (ast_channel_is_bridged(chan) || ast_channel_pbx(chan)) {
5259 priority += 1;
5260 }
5263 ast_channel_unlock(chan);
5264 return 0;
5265 }
5266 ast_channel_unlock(chan);
5267
5268 /* Otherwise, we need to gain control of the channel first */
5269 newchan = ast_channel_yank(chan);
5270 if (!newchan) {
5271 ast_log(LOG_WARNING, "Unable to gain control of channel %s\n", ast_channel_name(chan));
5272 return -1;
5273 }
5275 if (ast_pbx_start(newchan)) {
5276 ast_hangup(newchan);
5277 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(newchan));
5278 return -1;
5279 }
5280
5281 return 0;
5282}
5283
5284int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
5285{
5286 struct ast_channel *chan;
5287 int res = -1;
5288
5289 if ((chan = ast_channel_get_by_name(channame))) {
5290 res = ast_async_goto(chan, context, exten, priority);
5291 chan = ast_channel_unref(chan);
5292 }
5293
5294 return res;
5295}
5296
5297/*!
5298 * \internal
5299 * \brief Copy a string skipping whitespace and optionally dashes.
5300 *
5301 * \param dst Destination buffer to copy src string.
5302 * \param src Null terminated string to copy.
5303 * \param dst_size Number of bytes in the dst buffer.
5304 * \param nofluff Nonzero if '-' chars are not copied.
5305 *
5306 * \return Number of bytes written to dst including null terminator.
5307 */
5308static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
5309{
5310 unsigned int count;
5311 unsigned int insquares;
5312 unsigned int is_pattern;
5313
5314 if (!dst_size--) {
5315 /* There really is no dst buffer */
5316 return 0;
5317 }
5318
5319 count = 0;
5320 insquares = 0;
5321 is_pattern = *src == '_';
5322 while (*src && count < dst_size) {
5323 if (*src == '[') {
5324 if (is_pattern) {
5325 insquares = 1;
5326 }
5327 } else if (*src == ']') {
5328 insquares = 0;
5329 } else if (*src == ' ' && !insquares) {
5330 ++src;
5331 continue;
5332 } else if (*src == '-' && !insquares && nofluff) {
5333 ++src;
5334 continue;
5335 }
5336 *dst++ = *src++;
5337 ++count;
5338 }
5339 *dst = '\0';
5340
5341 return count + 1;
5342}
5343
5344/*!
5345 * \brief add the extension in the priority chain.
5346 * \retval 0 on success.
5347 * \retval -1 on failure.
5348*/
5349static int add_priority(struct ast_context *con, struct ast_exten *tmp,
5350 struct ast_exten *el, struct ast_exten *e, int replace)
5351{
5352 struct ast_exten *ep;
5353 struct ast_exten *eh=e;
5354 int repeated_label = 0; /* Track if this label is a repeat, assume no. */
5355
5356 for (ep = NULL; e ; ep = e, e = e->peer) {
5357 if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
5358 if (strcmp(e->name, tmp->name)) {
5360 "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
5361 tmp->name, tmp->priority, con->name, tmp->label, e->name, e->priority);
5362 } else {
5364 "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
5365 tmp->name, tmp->priority, con->name, tmp->label, e->priority);
5366 }
5367 repeated_label = 1;
5368 }
5369 if (e->priority >= tmp->priority) {
5370 break;
5371 }
5372 }
5373
5374 if (repeated_label) { /* Discard the label since it's a repeat. */
5375 tmp->label = NULL;
5376 }
5377
5378 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
5380
5381 if (tmp->label) {
5383 }
5384 ep->peer = tmp;
5385 return 0; /* success */
5386 }
5387 if (e->priority == tmp->priority) {
5388 /* Can't have something exactly the same. Is this a
5389 replacement? If so, replace, otherwise, bonk. */
5390 if (!replace) {
5391 if (strcmp(e->name, tmp->name)) {
5393 "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
5394 tmp->name, tmp->priority, con->name, e->name);
5395 } else {
5397 "Unable to register extension '%s' priority %d in '%s', already in use\n",
5398 tmp->name, tmp->priority, con->name);
5399 }
5400
5401 return -1;
5402 }
5403 /* we are replacing e, so copy the link fields and then update
5404 * whoever pointed to e to point to us
5405 */
5406 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
5407 tmp->peer = e->peer; /* always meaningful */
5408 if (ep) { /* We're in the peer list, just insert ourselves */
5410
5411 if (e->label) {
5413 }
5414
5416 if (tmp->label) {
5418 }
5419
5420 ep->peer = tmp;
5421 } else if (el) { /* We're the first extension. Take over e's functions */
5422 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
5423 tmp->peer_table = e->peer_table;
5427 if (e->label) {
5429 }
5430 if (tmp->label) {
5432 }
5433
5436 el->next = tmp;
5437 /* The pattern trie points to this exten; replace the pointer,
5438 and all will be well */
5439 if (x) { /* if the trie isn't formed yet, don't sweat this */
5440 if (x->exten) { /* this test for safety purposes */
5441 x->exten = tmp; /* replace what would become a bad pointer */
5442 } else {
5443 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
5444 }
5445 }
5446 } else { /* We're the very first extension. */
5447 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
5450 tmp->peer_table = e->peer_table;
5454 if (e->label) {
5456 }
5457 if (tmp->label) {
5459 }
5460
5463 con->root = tmp;
5464 /* The pattern trie points to this exten; replace the pointer,
5465 and all will be well */
5466 if (x) { /* if the trie isn't formed yet; no problem */
5467 if (x->exten) { /* this test for safety purposes */
5468 x->exten = tmp; /* replace what would become a bad pointer */
5469 } else {
5470 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
5471 }
5472 }
5473 }
5474 if (tmp->priority == PRIORITY_HINT)
5475 ast_change_hint(e,tmp);
5476 /* Destroy the old one */
5477 if (e->datad)
5478 e->datad(e->data);
5479 ast_free(e);
5480 } else { /* Slip ourselves in just before e */
5481 tmp->peer = e;
5482 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
5483 if (ep) { /* Easy enough, we're just in the peer list */
5484 if (tmp->label) {
5486 }
5488 ep->peer = tmp;
5489 } else { /* we are the first in some peer list, so link in the ext list */
5490 tmp->peer_table = e->peer_table;
5492 e->peer_table = 0;
5493 e->peer_label_table = 0;
5495 if (tmp->label) {
5497 }
5500 if (el)
5501 el->next = tmp; /* in the middle... */
5502 else
5503 con->root = tmp; /* ... or at the head */
5504 e->next = NULL; /* e is no more at the head, so e->next must be reset */
5505 }
5506 /* And immediately return success. */
5507 if (tmp->priority == PRIORITY_HINT) {
5508 ast_add_hint(tmp);
5509 }
5510 }
5511 return 0;
5512}
5513
5514/*! \brief
5515 * Main interface to add extensions to the list for out context.
5516 *
5517 * We sort extensions in order of matching preference, so that we can
5518 * stop the search as soon as we find a suitable match.
5519 * This ordering also takes care of wildcards such as '.' (meaning
5520 * "one or more of any character") and '!' (which is 'earlymatch',
5521 * meaning "zero or more of any character" but also impacts the
5522 * return value from CANMATCH and EARLYMATCH.
5523 *
5524 * The extension match rules defined in the devmeeting 2006.05.05 are
5525 * quite simple: WE SELECT THE LONGEST MATCH.
5526 * In detail, "longest" means the number of matched characters in
5527 * the extension. In case of ties (e.g. _XXX and 333) in the length
5528 * of a pattern, we give priority to entries with the smallest cardinality
5529 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
5530 * while the latter has 7, etc.
5531 * In case of same cardinality, the first element in the range counts.
5532 * If we still have a tie, any final '!' will make this as a possibly
5533 * less specific pattern.
5534 *
5535 * EBUSY - can't lock
5536 * EEXIST - extension with the same priority exist and no replace is set
5537 *
5538 */
5540 int replace, const char *extension, int priority, const char *label, const char *callerid,
5541 const char *application, void *data, void (*datad)(void *),
5542 const char *registrar, const char *registrar_file, int registrar_line)
5543{
5544 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
5545 application, data, datad, registrar, registrar_file, registrar_line, 1);
5546}
5547
5549 int replace, const char *extension, int priority, const char *label, const char *callerid,
5550 const char *application, void *data, void (*datad)(void *),
5551 const char *registrar, const char *registrar_file, int registrar_line)
5552{
5553 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
5554 application, data, datad, registrar, registrar_file, registrar_line, 0);
5555}
5556
5557
5558/*!
5559 * \brief Same as ast_add_extension2() but controls the context locking.
5560 *
5561 * \details
5562 * Does all the work of ast_add_extension2, but adds an arg to
5563 * determine if context locking should be done.
5564 */
5566 int replace, const char *extension, int priority, const char *label, const char *callerid,
5567 const char *application, void *data, void (*datad)(void *),
5568 const char *registrar, const char *registrar_file, int registrar_line, int lock_context)
5569{
5570 /*
5571 * Sort extensions (or patterns) according to the rules indicated above.
5572 * These are implemented by the function ext_cmp()).
5573 * All priorities for the same ext/pattern/cid are kept in a list,
5574 * using the 'peer' field as a link field..
5575 */
5576 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
5577 int res;
5578 int length;
5579 char *p;
5580 char expand_buf[VAR_BUF_SIZE];
5581 struct ast_exten dummy_exten = {0};
5582 char dummy_name[1024];
5583 int exten_fluff;
5584 int callerid_fluff;
5585
5587 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",
5588 con->name);
5589 /* We always need to deallocate 'data' on failure */
5590 if (datad) {
5591 datad(data);
5592 }
5593 return -1;
5594 }
5595
5596 /* If we are adding a hint evaluate in variables and global variables */
5597 if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
5598 int inhibited;
5600
5601 if (c) {
5604 }
5605
5606 /*
5607 * We can allow dangerous functions when adding a hint since
5608 * altering dialplan is itself a privileged activity. Otherwise,
5609 * we could never execute dangerous functions.
5610 */
5612 pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
5613 if (0 < inhibited) {
5615 }
5616
5617 application = expand_buf;
5618 if (c) {
5620 }
5621 }
5622
5623 if (priority == PRIORITY_HINT) {
5624 /* Fluff in a hint is fine. This prevents the removal of dashes from dynamically
5625 * created hints during a reload. */
5626 exten_fluff = 0;
5627 } else {
5628 exten_fluff = ext_fluff_count(extension);
5629 }
5630
5631 callerid_fluff = callerid ? ext_fluff_count(callerid) : 0;
5632
5633 length = sizeof(struct ast_exten);
5634 length += strlen(extension) + 1;
5635 if (exten_fluff) {
5636 length += strlen(extension) + 1 - exten_fluff;
5637 }
5638 length += strlen(application) + 1;
5639 if (label) {
5640 length += strlen(label) + 1;
5641 }
5642 if (callerid) {
5643 length += strlen(callerid) + 1;
5644 if (callerid_fluff) {
5645 length += strlen(callerid) + 1 - callerid_fluff;
5646 }
5647 } else {
5648 length ++; /* just the '\0' */
5649 }
5650 if (registrar_file) {
5651 length += strlen(registrar_file) + 1;
5652 }
5653
5654 /* Be optimistic: Build the extension structure first */
5655 tmp = ast_calloc(1, length);
5656 if (!tmp) {
5657 /* We always need to deallocate 'data' on failure */
5658 if (datad) {
5659 datad(data);
5660 }
5661 return -1;
5662 }
5663
5664 if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
5665 label = 0;
5666
5667 /* use p as dst in assignments, as the fields are const char * */
5668 p = tmp->stuff;
5669 if (label) {
5670 tmp->label = p;
5671 strcpy(p, label);
5672 p += strlen(label) + 1;
5673 }
5674 tmp->name = p;
5675 p += ext_strncpy(p, extension, strlen(extension) + 1, 0);
5676 if (exten_fluff) {
5677 tmp->exten = p;
5678 p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
5679 } else {
5680 /* no fluff, we don't need a copy. */
5681 tmp->exten = tmp->name;
5682 }
5683 tmp->priority = priority;
5684 tmp->cidmatch_display = tmp->cidmatch = p; /* but use p for assignments below */
5685
5686 /* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */
5687 if (callerid) {
5688 p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
5689 if (callerid_fluff) {
5690 tmp->cidmatch = p;
5691 p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
5692 }
5694 } else {
5695 *p++ = '\0';
5697 }
5698
5699 if (registrar_file) {
5700 tmp->registrar_file = p;
5701 strcpy(p, registrar_file);
5702 p += strlen(registrar_file) + 1;
5703 } else {
5704 tmp->registrar_file = NULL;
5705 }
5706
5707 tmp->app = p;
5708 strcpy(p, application);
5709 tmp->parent = con;
5710 tmp->data = data;
5711 tmp->datad = datad;
5712 tmp->registrar = registrar;
5714
5715 if (lock_context) {
5716 ast_wrlock_context(con);
5717 }
5718
5719 if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
5720 an extension, and the trie exists, then we need to incrementally add this pattern to it. */
5721 ext_strncpy(dummy_name, tmp->exten, sizeof(dummy_name), 1);
5722 dummy_exten.exten = dummy_name;
5723 dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
5724 dummy_exten.cidmatch = 0;
5725 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
5726 if (!tmp2) {
5727 /* hmmm, not in the trie; */
5728 add_exten_to_pattern_tree(con, tmp, 0);
5729 ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
5730 }
5731 }
5732 res = 0; /* some compilers will think it is uninitialized otherwise */
5733 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
5734 res = ext_cmp(e->exten, tmp->exten);
5735 if (res == 0) { /* extension match, now look at cidmatch */
5737 res = 0;
5739 res = 1;
5741 res = -1;
5742 else
5743 res = ext_cmp(e->cidmatch, tmp->cidmatch);
5744 }
5745 if (res >= 0)
5746 break;
5747 }
5748 if (e && res == 0) { /* exact match, insert in the priority chain */
5749 res = add_priority(con, tmp, el, e, replace);
5750 if (res < 0) {
5751 if (con->pattern_tree) {
5752 struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
5753
5754 if (x->exten) {
5755 x->deleted = 1;
5756 x->exten = 0;
5757 }
5758
5760 }
5761
5762 if (tmp->datad) {
5763 tmp->datad(tmp->data);
5764 /* if you free this, null it out */
5765 tmp->data = NULL;
5766 }
5767
5768 ast_free(tmp);
5769 }
5770 if (lock_context) {
5771 ast_unlock_context(con);
5772 }
5773 if (res < 0) {
5774 errno = EEXIST;
5775 return -1;
5776 }
5777 } else {
5778 /*
5779 * not an exact match, this is the first entry with this pattern,
5780 * so insert in the main list right before 'e' (if any)
5781 */
5782 tmp->next = e;
5788 0);
5794 0);
5795
5796 if (el) { /* there is another exten already in this context */
5797 el->next = tmp;
5798 } else { /* this is the first exten in this context */
5799 if (!con->root_table) {
5805 0);
5806 }
5807 con->root = tmp;
5808 }
5809 if (label) {
5811 }
5814
5815 if (lock_context) {
5816 ast_unlock_context(con);
5817 }
5818 if (tmp->priority == PRIORITY_HINT) {
5819 ast_add_hint(tmp);
5820 }
5821 }
5822 if (DEBUG_ATLEAST(1)) {
5823 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
5824 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
5825 tmp->name, tmp->priority, tmp->cidmatch_display, con->name, con);
5826 } else {
5827 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s (%p)\n",
5828 tmp->name, tmp->priority, con->name, con);
5829 }
5830 }
5831
5832 return 0;
5833}
5834
5835/*! \brief Structure which contains information about an outgoing dial */
5837 /*! \brief Dialing structure being used */
5839 /*! \brief Condition for synchronous dialing */
5841 /*! \brief Application to execute */
5843 /*! \brief Application data to pass to application */
5844 char *appdata;
5845 /*! \brief Dialplan context */
5847 /*! \brief Dialplan extension */
5849 /*! \brief Dialplan priority */
5851 /*! \brief Result of the dial operation when dialed is set */
5853 /*! \brief Set when dialing is completed */
5854 unsigned int dialed:1;
5855 /*! \brief Set if we've spawned a thread to do our work */
5856 unsigned int in_separate_thread:1;
5857};
5858
5859/*! \brief Destructor for outgoing structure */
5860static void pbx_outgoing_destroy(void *obj)
5861{
5862 struct pbx_outgoing *outgoing = obj;
5863
5864 if (outgoing->dial) {
5866 }
5867
5868 ast_cond_destroy(&outgoing->cond);
5869
5870 ast_free(outgoing->appdata);
5871}
5872
5873/*! \brief Internal function which dials an outgoing leg and sends it to a provided extension or application */
5874static void *pbx_outgoing_exec(void *data)
5875{
5876 RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
5877 enum ast_dial_result res;
5878 struct ast_channel *chan;
5879
5880 res = ast_dial_run(outgoing->dial, NULL, 0);
5881
5882 if (outgoing->in_separate_thread) {
5883 /* Notify anyone interested that dialing is complete */
5885 outgoing->dial_res = res;
5886 outgoing->dialed = 1;
5887 ast_cond_signal(&outgoing->cond);
5889 } else {
5890 /* We still need the dial result, but we don't need to lock */
5891 outgoing->dial_res = res;
5892 }
5893
5894 /* If the outgoing leg was not answered we can immediately return and go no further */
5895 if (res != AST_DIAL_RESULT_ANSWERED) {
5896 return NULL;
5897 }
5898
5899 /* We steal the channel so we get ownership of when it is hung up */
5900 chan = ast_dial_answered_steal(outgoing->dial);
5901
5902 if (!ast_strlen_zero(outgoing->app)) {
5903 struct ast_app *app = pbx_findapp(outgoing->app);
5904
5905 if (app) {
5906 ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
5907 ast_channel_name(chan));
5908 pbx_exec(chan, app, outgoing->appdata);
5909 } else {
5910 ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app);
5911 }
5912
5913 ast_hangup(chan);
5914 } else {
5917 }
5918
5921 }
5922
5923 if (outgoing->priority > 0) {
5925 }
5926
5927 if (ast_pbx_run(chan)) {
5928 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan));
5929 ast_hangup(chan);
5930 }
5931 }
5932
5933 return NULL;
5934}
5935
5936/*! \brief Internal dialing state callback which causes early media to trigger an answer */
5937static void pbx_outgoing_state_callback(struct ast_dial *dial)
5938{
5939 struct ast_channel *channel;
5940
5942 return;
5943 }
5944
5945 if (!(channel = ast_dial_get_channel(dial, 0))) {
5946 return;
5947 }
5948
5949 ast_verb(4, "Treating progress as answer on '%s' due to early media option\n",
5950 ast_channel_name(channel));
5951
5953}
5954
5955/*!
5956 * \brief Attempt to convert disconnect cause to old originate reason.
5957 *
5958 * \todo XXX The old originate reasons need to be trashed and replaced
5959 * with normal disconnect cause codes if the call was not answered.
5960 * The internal consumers of the reason values would also need to be
5961 * updated: app_originate, call files, and AMI OriginateResponse.
5962 */
5963static enum ast_control_frame_type pbx_dial_reason(enum ast_dial_result dial_result, int cause)
5964{
5965 enum ast_control_frame_type pbx_reason;
5966
5967 if (dial_result == AST_DIAL_RESULT_ANSWERED) {
5968 /* Remote end answered. */
5969 pbx_reason = AST_CONTROL_ANSWER;
5970 } else if (dial_result == AST_DIAL_RESULT_HANGUP) {
5971 /* Caller hungup */
5972 pbx_reason = AST_CONTROL_HANGUP;
5973 } else {
5974 switch (cause) {
5976 pbx_reason = AST_CONTROL_BUSY;
5977 break;
5984 pbx_reason = AST_CONTROL_CONGESTION;
5985 break;
5988 /* Remote end was ringing (but isn't anymore) */
5989 pbx_reason = AST_CONTROL_RINGING;
5990 break;
5992 default:
5993 /* Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?) */
5994 pbx_reason = 0;
5995 break;
5996 }
5997 }
5998
5999 return pbx_reason;
6000}
6001
6002static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
6003 const char *addr, int timeout, const char *context, const char *exten, int priority,
6004 const char *app, const char *appdata, int *reason, int synchronous,
6005 const char *cid_num, const char *cid_name, struct ast_variable *vars,
6006 const char *account, struct ast_channel **locked_channel, int early_media,
6007 const struct ast_assigned_ids *assignedids, const char *predial_callee)
6008{
6010 struct ast_channel *dialed;
6011 pthread_t thread;
6012 char tmp_cid_name[128];
6013 char tmp_cid_num[128];
6014
6016 if (!outgoing) {
6017 return -1;
6018 }
6019 ast_cond_init(&outgoing->cond, NULL);
6020
6021 if (!ast_strlen_zero(app)) {
6023 outgoing->appdata = ast_strdup(appdata);
6024 } else {
6028 }
6029
6030 if (!(outgoing->dial = ast_dial_create())) {
6031 return -1;
6032 }
6033
6034 if (ast_dial_append(outgoing->dial, type, addr, assignedids)) {
6035 return -1;
6036 }
6037
6038 ast_dial_set_global_timeout(outgoing->dial, timeout);
6039
6040 if (!ast_strlen_zero(predial_callee)) {
6041 /* note casting to void * here to suppress compiler warning message (passing const to non-const function) */
6042 ast_dial_option_global_enable(outgoing->dial, AST_DIAL_OPTION_PREDIAL, (void *)predial_callee);
6043 }
6044
6045 if (ast_dial_prerun(outgoing->dial, NULL, cap)) {
6046 if (synchronous && reason) {
6048 ast_dial_reason(outgoing->dial, 0));
6049 }
6050 return -1;
6051 }
6052
6054 if (!dialed) {
6055 return -1;
6056 }
6057
6058 if (vars) {
6060 }
6062 if (!ast_strlen_zero(account)) {
6064 ast_channel_accountcode_set(dialed, account);
6065 ast_channel_peeraccount_set(dialed, account);
6067 }
6069
6070 if (!ast_strlen_zero(predial_callee)) {
6071 char *tmp = NULL;
6072 /*
6073 * The predial sub routine may have set callerid so set this into the new channel
6074 * Note... cid_num and cid_name parameters to this function will always be NULL if
6075 * predial_callee is non-NULL so we are not overwriting anything here.
6076 */
6078 if (tmp) {
6079 ast_copy_string(tmp_cid_num, tmp, sizeof(tmp_cid_num));
6080 cid_num = tmp_cid_num;
6081 }
6083 if (tmp) {
6084 ast_copy_string(tmp_cid_name, tmp, sizeof(tmp_cid_name));
6085 cid_name = tmp_cid_name;
6086 }
6087 }
6089
6090 if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
6092
6093 /*
6094 * It seems strange to set the CallerID on an outgoing call leg
6095 * to whom we are calling, but this function's callers are doing
6096 * various Originate methods. This call leg goes to the local
6097 * user. Once the called party answers, the dialplan needs to
6098 * be able to access the CallerID from the CALLERID function as
6099 * if the called party had placed this call.
6100 */
6101 ast_set_callerid(dialed, cid_num, cid_name, cid_num);
6102
6104 if (!ast_strlen_zero(cid_num)) {
6105 connected.id.number.valid = 1;
6106 connected.id.number.str = (char *) cid_num;
6108 }
6109 if (!ast_strlen_zero(cid_name)) {
6110 connected.id.name.valid = 1;
6111 connected.id.name.str = (char *) cid_name;
6113 }
6115 }
6116
6117 if (early_media) {
6119 }
6120
6121 if (locked_channel) {
6122 /*
6123 * Keep a dialed channel ref since the caller wants
6124 * the channel returned. We must get the ref before
6125 * spawning off pbx_outgoing_exec().
6126 */
6127 ast_channel_ref(dialed);
6128 if (!synchronous) {
6129 /*
6130 * Lock it now to hold off pbx_outgoing_exec() in case the
6131 * calling function needs the channel state/snapshot before
6132 * dialing actually happens.
6133 */
6134 ast_channel_lock(dialed);
6135 }
6136 }
6137
6138 /* This extra reference is dereferenced by pbx_outgoing_exec */
6139 ao2_ref(outgoing, +1);
6140
6141 if (synchronous == AST_OUTGOING_WAIT_COMPLETE) {
6142 /*
6143 * Because we are waiting until this is complete anyway, there is no
6144 * sense in creating another thread that we will just need to wait
6145 * for, so instead we commandeer the current thread.
6146 */
6148 } else {
6149 outgoing->in_separate_thread = 1;
6150
6152 ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
6153 ao2_ref(outgoing, -1);
6154 if (locked_channel) {
6155 if (!synchronous) {
6156 ast_channel_unlock(dialed);
6157 }
6158 ast_channel_unref(dialed);
6159 }
6160 return -1;
6161 }
6162
6163 if (synchronous) {
6165 /* Wait for dialing to complete */
6166 while (!outgoing->dialed) {
6168 }
6170 }
6171 }
6172
6173 if (synchronous) {
6174 /* Determine the outcome of the dialing attempt up to it being answered. */
6175 if (reason) {
6176 *reason = pbx_dial_reason(outgoing->dial_res,
6177 ast_dial_reason(outgoing->dial, 0));
6178 }
6179
6180 if (outgoing->dial_res != AST_DIAL_RESULT_ANSWERED) {
6181 /* The dial operation failed. */
6182 if (locked_channel) {
6183 ast_channel_unref(dialed);
6184 }
6185 return -1;
6186 }
6187 if (locked_channel) {
6188 ast_channel_lock(dialed);
6189 }
6190 }
6191
6192 if (locked_channel) {
6193 *locked_channel = dialed;
6194 }
6195 return 0;
6196}
6197
6198int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
6199 int timeout, const char *context, const char *exten, int priority, int *reason,
6200 int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
6201 const char *account, struct ast_channel **locked_channel, int early_media,
6202 const struct ast_assigned_ids *assignedids)
6203{
6204 return ast_pbx_outgoing_exten_predial(type, cap, addr, timeout, context, exten, priority, reason,
6205 synchronous, cid_num, cid_name, vars, account, locked_channel, early_media, assignedids, NULL);
6206}
6207
6208int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr,
6209 int timeout, const char *context, const char *exten, int priority, int *reason,
6210 int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
6211 const char *account, struct ast_channel **locked_channel, int early_media,
6212 const struct ast_assigned_ids *assignedids, const char *predial_callee)
6213{
6214 int res;
6215 int my_reason;
6216
6217 if (!reason) {
6218 reason = &my_reason;
6219 }
6220 *reason = 0;
6221 if (locked_channel) {
6222 *locked_channel = NULL;
6223 }
6224
6225 res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
6226 NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
6227 early_media, assignedids, predial_callee);
6228
6229 if (res < 0 /* Call failed to get connected for some reason. */
6230 && 0 < synchronous
6231 && ast_exists_extension(NULL, context, "failed", 1, NULL)) {
6232 struct ast_channel *failed;
6233
6234 /* We do not have to worry about a locked_channel if dialing failed. */
6235 ast_assert(!locked_channel || !*locked_channel);
6236
6237 /*!
6238 * \todo XXX Not good. The channel name is not unique if more than
6239 * one originate fails at a time.
6240 */
6241 failed = ast_channel_alloc(0, AST_STATE_DOWN, cid_num, cid_name, account,
6242 "failed", context, NULL, NULL, 0, "OutgoingSpoolFailed");
6243 if (failed) {
6244 char failed_reason[12];
6245
6246 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
6247 pbx_builtin_setvar_helper(failed, "REASON", failed_reason);
6248 ast_channel_unlock(failed);
6249 ast_set_variables(failed, vars);
6250
6251 if (ast_pbx_run(failed)) {
6252 ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n",
6253 ast_channel_name(failed));
6254 ast_hangup(failed);
6255 }
6256 }
6257 }
6258
6259 return res;
6260}
6261
6262int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
6263 int timeout, const char *app, const char *appdata, int *reason, int synchronous,
6264 const char *cid_num, const char *cid_name, struct ast_variable *vars,
6265 const char *account, struct ast_channel **locked_channel,
6266 const struct ast_assigned_ids *assignedids)
6267{
6268 return ast_pbx_outgoing_app_predial(type, cap, addr, timeout, app, appdata, reason, synchronous,
6269 cid_num, cid_name, vars, account, locked_channel, assignedids, NULL);
6270}
6271
6272int ast_pbx_outgoing_app_predial(const char *type, struct ast_format_cap *cap, const char *addr,
6273 int timeout, const char *app, const char *appdata, int *reason, int synchronous,
6274 const char *cid_num, const char *cid_name, struct ast_variable *vars,
6275 const char *account, struct ast_channel **locked_channel,
6276 const struct ast_assigned_ids *assignedids, const char *predial_callee)
6277{
6278 if (reason) {
6279 *reason = 0;
6280 }
6281 if (locked_channel) {
6282 *locked_channel = NULL;
6283 }
6284 if (ast_strlen_zero(app)) {
6285 return -1;
6286 }
6287
6288 return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
6289 reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
6290 assignedids, predial_callee);
6291}
6292
6293/* this is the guts of destroying a context --
6294 freeing up the structure, traversing and destroying the
6295 extensions, switches, ignorepats, includes, etc. etc. */
6296
6298{
6299 struct ast_exten *e, *el, *en;
6300 struct ast_context *tmp = con;
6301
6302 if (con->scope == AST_CONTEXT_SCOPE_GLOBAL && con->autohints) {
6304 }
6305
6306 /* Free includes */
6309
6310 /* Free ignorepats */
6313
6314 /* Free switches */
6316 AST_VECTOR_FREE(&tmp->alts);
6317
6318 /* destroy the hash tabs */
6319 if (tmp->root_table) {
6321 }
6322 /* and destroy the pattern tree */
6323 if (tmp->pattern_tree)
6325
6326 for (e = tmp->root; e;) {
6327 for (en = e->peer; en;) {
6328 el = en;
6329 en = en->peer;
6331 }
6332 el = e;
6333 e = e->next;
6335 }
6336 tmp->root = NULL;
6337 ast_rwlock_destroy(&tmp->lock);
6338 ast_free(tmp);
6339}
6340
6341
6342void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
6343{
6344 struct ast_context *tmp, *tmpl=NULL;
6345 struct ast_exten *exten_item, *prio_item;
6346
6347 for (tmp = list; tmp; ) {
6348 struct ast_context *next = NULL; /* next starting point */
6349 /* The following code used to skip forward to the next
6350 context with matching registrar, but this didn't
6351 make sense; individual priorities registrar'd to
6352 the matching registrar could occur in any context! */
6353 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
6354 if (con) {
6355 for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
6356 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
6357 if ( !strcasecmp(tmp->name, con->name) ) {
6358 break; /* found it */
6359 }
6360 }
6361 }
6362
6363 if (!tmp) /* not found, we are done */
6364 break;
6365 ast_wrlock_context(tmp);
6366
6367 if (registrar) {
6368 /* then search thru and remove any extens that match registrar. */
6369 struct ast_hashtab_iter *exten_iter;
6370 struct ast_hashtab_iter *prio_iter;
6371 int idx;
6372
6373 /* remove any ignorepats whose registrar matches */
6374 for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) {
6375 struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx);
6376
6377 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
6379 ignorepat_free(ip);
6380 }
6381 }
6382 /* remove any includes whose registrar matches */
6383 for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) {
6384 struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx);
6385
6386 if (!strcmp(ast_get_include_registrar(i), registrar)) {
6388 include_free(i);
6389 }
6390 }
6391 /* remove any switches whose registrar matches */
6392 for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) {
6393 struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx);
6394
6395 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
6396 AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx);
6397 sw_free(sw);
6398 }
6399 }
6400
6401 if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
6402 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
6403 while ((exten_item=ast_hashtab_next(exten_iter))) {
6404 int end_traversal = 1;
6405
6406 /*
6407 * If the extension could not be removed from the root_table due to
6408 * a loaded PBX app, it can exist here but have its peer_table be
6409 * destroyed due to a previous pass through this function.
6410 */
6411 if (!exten_item->peer_table) {
6412 continue;
6413 }
6414
6415 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
6416 while ((prio_item=ast_hashtab_next(prio_iter))) {
6418 char cidmatch[AST_MAX_EXTENSION];
6419 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
6420 continue;
6421 }
6422 ast_verb(5, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
6423 tmp->name, prio_item->name, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
6424 ast_copy_string(extension, prio_item->exten, sizeof(extension));
6425 if (prio_item->cidmatch) {
6426 ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
6427 }
6428 end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
6429 }
6430 /* Explanation:
6431 * ast_context_remove_extension_callerid2 will destroy the extension that it comes across. This
6432 * destruction includes destroying the exten's peer_table, which we are currently traversing. If
6433 * ast_context_remove_extension_callerid2 ever should return '0' then this means we have destroyed
6434 * the hashtable which we are traversing, and thus calling ast_hashtab_end_traversal will result
6435 * in reading invalid memory. Thus, if we detect that we destroyed the hashtable, then we will simply
6436 * free the iterator
6437 */
6438 if (end_traversal) {
6439 ast_hashtab_end_traversal(prio_iter);
6440 } else {
6441 ast_free(prio_iter);
6442 }
6443 }
6444 ast_hashtab_end_traversal(exten_iter);
6445 }
6446
6447 /* delete the context if it's registrar matches, is empty, has refcount of 1, */
6448 /* it's not empty, if it has includes, ignorepats, or switches that are registered from
6449 another registrar. It's not empty if there are any extensions */
6450 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)) {
6451 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
6452 ast_hashtab_remove_this_object(contexttab, tmp);
6453
6454 next = tmp->next;
6455 if (tmpl)
6456 tmpl->next = next;
6457 else
6458 contexts = next;
6459 /* Okay, now we're safe to let it go -- in a sense, we were
6460 ready to let it go as soon as we locked it. */
6461 ast_unlock_context(tmp);
6463 } else {
6464 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
6465 tmp->refcount, tmp->root);
6466 ast_unlock_context(tmp);
6467 next = tmp->next;
6468 tmpl = tmp;
6469 }
6470 } else if (con) {
6471 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
6472 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
6473 ast_hashtab_remove_this_object(contexttab, tmp);
6474
6475 next = tmp->next;
6476 if (tmpl)
6477 tmpl->next = next;
6478 else
6479 contexts = next;
6480 /* Okay, now we're safe to let it go -- in a sense, we were
6481 ready to let it go as soon as we locked it. */
6482 ast_unlock_context(tmp);
6484 }
6485
6486 /* if we have a specific match, we are done, otherwise continue */
6487 tmp = con ? NULL : next;
6488 }
6489}
6490
6491int ast_context_destroy_by_name(const char *context, const char *registrar)
6492{
6493 struct ast_context *con;
6494 int ret = -1;
6495
6497 con = ast_context_find(context);
6498 if (con) {
6500 ret = 0;
6501 }
6503
6504 return ret;
6505}
6506
6513
6514void wait_for_hangup(struct ast_channel *chan, const void *data)
6515{
6516 int res;
6517 struct ast_frame *f;
6518 double waitsec;
6519 int waittime;
6520
6521 if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
6522 waitsec = -1;
6523 if (waitsec > -1) {
6524 waittime = waitsec * 1000.0;
6525 ast_safe_sleep_without_silence(chan, waittime);
6526 } else do {
6527 res = ast_waitfor(chan, -1);
6528 if (res < 0)
6529 return;
6530 f = ast_read(chan);
6531 if (f)
6532 ast_frfree(f);
6533 } while(f);
6534}
6535
6536/*!
6537 * \ingroup functions
6538 */
6539static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
6540{
6541 struct ast_tm tm;
6542 struct timeval tv;
6543 char *remainder, result[30], timezone[80];
6544
6545 /* Turn off testing? */
6546 if (!pbx_checkcondition(value)) {
6547 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
6548 return 0;
6549 }
6550
6551 /* Parse specified time */
6552 if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
6553 return -1;
6554 }
6555 sscanf(remainder, "%79s", timezone);
6556 tv = ast_mktime(&tm, S_OR(timezone, NULL));
6557
6558 snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
6559 pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
6560 return 0;
6561}
6562
6564 .name = "TESTTIME",
6565 .write = testtime_write,
6566};
6567
6568int pbx_checkcondition(const char *condition)
6569{
6570 int res;
6571 if (ast_strlen_zero(condition)) { /* NULL or empty strings are false */
6572 return 0;
6573 } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
6574 return res;
6575 } else { /* Strings are true */
6576 return 1;
6577 }
6578}
6579
6580/*!
6581 * \internal
6582 * \brief Clean up resources on Asterisk shutdown.
6583 *
6584 * \note Cleans up resources allocated in load_pbx
6585 */
6593
6594int load_pbx(void)
6595{
6596 int res = 0;
6597
6599
6600 /* Initialize the PBX */
6601 ast_verb(1, "Asterisk PBX Core Initializing\n");
6602
6603 ast_verb(5, "Registering builtin functions:\n");
6607
6608 /* Register manager application */
6610
6611 if (res) {
6612 return -1;
6613 }
6614
6615 return 0;
6616}
6617
6618/*
6619 * Lock context list functions ...
6620 */
6622{
6623 return ast_mutex_lock(&conlock);
6624}
6625
6627{
6628 return ast_mutex_lock(&conlock);
6629}
6630
6632{
6633 return ast_mutex_unlock(&conlock);
6634}
6635
6636/*
6637 * Lock context ...
6638 */
6640{
6641 return ast_rwlock_wrlock(&con->lock);
6642}
6643
6645{
6646 return ast_rwlock_rdlock(&con->lock);
6647}
6648
6650{
6651 return ast_rwlock_unlock(&con->lock);
6652}
6653
6654/*
6655 * Name functions ...
6656 */
6657const char *ast_get_context_name(struct ast_context *con)
6658{
6659 return con ? con->name : NULL;
6660}
6661
6663{
6664 return exten ? exten->parent : NULL;
6665}
6666
6667const char *ast_get_extension_name(struct ast_exten *exten)
6668{
6669 return exten ? exten->name : NULL;
6670}
6671
6672const char *ast_get_extension_label(struct ast_exten *exten)
6673{
6674 return exten ? exten->label : NULL;
6675}
6676
6678{
6679 return exten ? exten->priority : -1;
6680}
6681
6682/*
6683 * Registrar info functions ...
6684 */
6686{
6687 return c ? c->registrar : NULL;
6688}
6689
6691{
6692 return e ? e->registrar : NULL;
6693}
6694
6696{
6697 return e ? e->registrar_file : NULL;
6698}
6699
6701{
6702 return e ? e->registrar_line : 0;
6703}
6704
6706{
6707 return e ? e->matchcid : 0;
6708}
6709
6711{
6712 return e ? e->cidmatch_display : NULL;
6713}
6714
6715const char *ast_get_extension_app(struct ast_exten *e)
6716{
6717 return e ? e->app : NULL;
6718}
6719
6721{
6722 return e ? e->data : NULL;
6723}
6724
6725int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c,
6726 const char *context, const char *exten, int priority)
6727{
6728 struct ast_exten *e;
6729 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
6731 e = pbx_find_extension(c, NULL, &q, context, exten, priority, NULL, "", E_MATCH);
6732 if (e) {
6733 if (buf) {
6734 const char *tmp = ast_get_extension_app_data(e);
6735 if (tmp) {
6736 ast_copy_string(buf, tmp, bufsize);
6737 }
6738 }
6740 return 0;
6741 }
6743 return -1;
6744}
6745
6746/*
6747 * Walking functions ...
6748 */
6750{
6751 return con ? con->next : contexts;
6752}
6753
6755 struct ast_exten *exten)
6756{
6757 if (!exten)
6758 return con ? con->root : NULL;
6759 else
6760 return exten->next;
6761}
6762
6763const struct ast_sw *ast_walk_context_switches(const struct ast_context *con,
6764 const struct ast_sw *sw)
6765{
6766 if (sw) {
6767 int idx;
6768 int next = 0;
6769
6770 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
6771 const struct ast_sw *s = ast_context_switches_get(con, idx);
6772
6773 if (next) {
6774 return s;
6775 }
6776
6777 if (sw == s) {
6778 next = 1;
6779 }
6780 }
6781
6782 return NULL;
6783 }
6784
6785 if (!ast_context_switches_count(con)) {
6786 return NULL;
6787 }
6788
6789 return ast_context_switches_get(con, 0);
6790}
6791
6793{
6794 return AST_VECTOR_SIZE(&con->alts);
6795}
6796
6797const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx)
6798{
6799 return AST_VECTOR_GET(&con->alts, idx);
6800}
6801
6803 struct ast_exten *priority)
6804{
6805 return priority ? priority->peer : exten;
6806}
6807
6808const struct ast_include *ast_walk_context_includes(const struct ast_context *con,
6809 const struct ast_include *inc)
6810{
6811 if (inc) {
6812 int idx;
6813 int next = 0;
6814
6815 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
6816 const struct ast_include *include = AST_VECTOR_GET(&con->includes, idx);
6817
6818 if (next) {
6819 return include;
6820 }
6821
6822 if (inc == include) {
6823 next = 1;
6824 }
6825 }
6826
6827 return NULL;
6828 }
6829
6830 if (!ast_context_includes_count(con)) {
6831 return NULL;
6832 }
6833
6834 return ast_context_includes_get(con, 0);
6835}
6836
6838{
6839 return AST_VECTOR_SIZE(&con->includes);
6840}
6841
6842const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx)
6843{
6844 return AST_VECTOR_GET(&con->includes, idx);
6845}
6846
6848 const struct ast_ignorepat *ip)
6849{
6850 if (!con) {
6851 return NULL;
6852 }
6853
6854 if (ip) {
6855 int idx;
6856 int next = 0;
6857
6858 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6859 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
6860
6861 if (next) {
6862 return i;
6863 }
6864
6865 if (ip == i) {
6866 next = 1;
6867 }
6868 }
6869
6870 return NULL;
6871 }
6872
6873 if (!ast_context_ignorepats_count(con)) {
6874 return NULL;
6875 }
6876
6877 return ast_context_ignorepats_get(con, 0);
6878}
6879
6881{
6882 return AST_VECTOR_SIZE(&con->ignorepats);
6883}
6884
6885const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx)
6886{
6887 return AST_VECTOR_GET(&con->ignorepats, idx);
6888}
6889
6891{
6892 int idx;
6893 int res = 0;
6894 int includecount = ast_context_includes_count(con);
6895
6896 if (includecount >= AST_PBX_MAX_STACK) {
6897 ast_log(LOG_WARNING, "Context %s contains too many includes (%d). Maximum is %d.\n",
6898 ast_get_context_name(con), includecount, AST_PBX_MAX_STACK);
6899 }
6900
6901 for (idx = 0; idx < includecount; idx++) {
6902 const struct ast_include *inc = ast_context_includes_get(con, idx);
6903
6904 if (ast_context_find(include_rname(inc))) {
6905 continue;
6906 }
6907
6908 res = -1;
6909 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
6911 break;
6912 }
6913
6914 return res;
6915}
6916
6917
6918static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
6919{
6920 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
6921
6922 if (!chan)
6923 return -2;
6924
6925 if (context == NULL)
6927 if (exten == NULL)
6928 exten = ast_channel_exten(chan);
6929
6930 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
6932 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)))
6933 return goto_func(chan, context, exten, priority);
6934 else {
6935 return AST_PBX_GOTO_FAILED;
6936 }
6937}
6938
6939int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
6940{
6941 return __ast_goto_if_exists(chan, context, exten, priority, 0);
6942}
6943
6944int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
6945{
6946 return __ast_goto_if_exists(chan, context, exten, priority, 1);
6947}
6948
6949int pbx_parse_location(struct ast_channel *chan, char **contextp, char **extenp, char **prip, int *ipri, int *mode, char *rest)
6950{
6951 char *context, *exten, *pri;
6952 /* do the strsep before here, so we don't have to alloc and free */
6953 if (!*extenp) {
6954 /* Only a priority in this one */
6955 *prip = *contextp;
6956 *extenp = NULL;
6957 *contextp = NULL;
6958 } else if (!*prip) {
6959 /* Only an extension and priority in this one */
6960 *prip = *extenp;
6961 *extenp = *contextp;
6962 *contextp = NULL;
6963 }
6964 context = *contextp;
6965 exten = *extenp;
6966 pri = *prip;
6967 if (mode) {
6968 if (*pri == '+') {
6969 *mode = 1;
6970 pri++;
6971 } else if (*pri == '-') {
6972 *mode = -1;
6973 pri++;
6974 }
6975 }
6976 if ((rest && sscanf(pri, "%30d%1s", ipri, rest) != 1) || sscanf(pri, "%30d", ipri) != 1) {
6978 exten ? exten : ast_channel_exten(chan), pri,
6979 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
6980 if (*ipri < 1) {
6981 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
6982 return -1;
6983 } else if (mode) {
6984 *mode = 0;
6985 }
6986 }
6987 return 0;
6988}
6989
6990static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
6991{
6992 char *exten, *pri, *context;
6993 char *stringp;
6994 int ipri;
6995 int mode = 0;
6996 char rest[2] = "";
6997
6998 if (ast_strlen_zero(goto_string)) {
6999 ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
7000 return -1;
7001 }
7002 stringp = ast_strdupa(goto_string);
7003 context = strsep(&stringp, ","); /* guaranteed non-null */
7004 exten = strsep(&stringp, ",");
7005 pri = strsep(&stringp, ",");
7006
7007 if (pbx_parse_location(chan, &context, &exten, &pri, &ipri, &mode, rest)) {
7008 return -1;
7009 }
7010 /* At this point we have a priority and maybe an extension and a context */
7011
7012 if (mode)
7013 ipri = ast_channel_priority(chan) + (ipri * mode);
7014
7015 if (async)
7016 ast_async_goto(chan, context, exten, ipri);
7017 else
7018 ast_explicit_goto(chan, context, exten, ipri);
7019
7020 return 0;
7021
7022}
7023
7024int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
7025{
7026 return pbx_parseable_goto(chan, goto_string, 0);
7027}
7028
7029int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
7030{
7031 return pbx_parseable_goto(chan, goto_string, 1);
7032}
7033
7034/*!
7035 * \internal
7036 * \brief Clean up resources on Asterisk shutdown
7037 */
7038static void pbx_shutdown(void)
7039{
7040 if (contexts_table) {
7042 }
7043}
7044
7046{
7048 return 0;
7049}
Prototypes for public functions only of internal interest,.
void ast_context_destroy(void)
Definition ael_main.c:414
void ast_context_verify_includes(void)
Definition ael_main.c:395
void ast_merge_contexts_and_delete(void)
Definition ael_main.c:389
struct ast_context * ast_walk_contexts(void)
Definition ael_main.c:401
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
static const char app[]
char digit
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
pthread_t thread
Definition app_sla.c:335
struct sla_ringing_trunk * first
Definition app_sla.c:338
struct sla_ringing_trunk * last
Definition app_sla.c:338
#define var
Definition ast_expr2f.c:605
int getloadavg(double *list, int nelem)
char * strsep(char **str, const char *delims)
static EditLine * el
Definition asterisk.c:348
Asterisk main include file. File version handling, generic pbx functions.
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
Definition astman.c:92
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
int64_t ast_mark(int, int start1_stop0)
Definition astman.c:103
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition astmm.c:1739
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition astobj2.c:476
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED
Definition callerid.h:437
Internal Asterisk hangup causes.
#define AST_CAUSE_SWITCH_CONGESTION
Definition causes.h:123
#define AST_CAUSE_UNALLOCATED
Definition causes.h:98
#define AST_CAUSE_DESTINATION_OUT_OF_ORDER
Definition causes.h:115
#define AST_CAUSE_NORMAL_TEMPORARY_FAILURE
Definition causes.h:122
#define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION
Definition causes.h:120
#define AST_CAUSE_CALL_REJECTED
Definition causes.h:111
#define AST_CAUSE_NETWORK_OUT_OF_ORDER
Definition causes.h:121
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition causes.h:114
#define AST_CAUSE_NO_ANSWER
Definition causes.h:109
#define AST_CAUSE_USER_BUSY
Definition causes.h:107
Call Detail Record API.
static int priority
static int connected
Definition cdr_pgsql.c:73
static PGresult * result
Definition cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition chan_iax2.c:2401
static const char type[]
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3179
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition channel.c:2423
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2540
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition channel.h:1299
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.
Definition channel.c:8484
#define ast_channel_lock(chan)
Definition channel.h:2983
@ AST_FLAG_BRIDGE_HANGUP_RUN
Definition channel.h:1038
@ AST_FLAG_IN_AUTOLOOP
Definition channel.h:1017
@ AST_FLAG_ORIGINATED
Definition channel.h:1059
void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
adds a list of channel variables to a channel
Definition channel.c:8291
struct ast_channel * ast_channel_yank(struct ast_channel *yankee)
Gain control of a channel in the system.
Definition channel.c:10773
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition channel.c:1289
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3008
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
ast_callid ast_channel_callid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
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.
Definition channel.c:7370
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:446
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition channel.c:10725
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2462
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
#define AST_MAX_CONTEXT
Definition channel.h:135
void ast_channel_context_set(struct ast_channel *chan, const char *value)
@ AST_SOFTHANGUP_ASYNCGOTO
Definition channel.h:1146
@ AST_SOFTHANGUP_HANGUP_EXEC
Definition channel.h:1174
@ AST_SOFTHANGUP_TIMEOUT
Definition channel.h:1158
@ AST_SOFTHANGUP_APPUNLOAD
Definition channel.h:1163
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition channel.h:1328
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition channel.c:2449
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
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.
Definition channel.c:2032
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
void ast_channel_priority_set(struct ast_channel *chan, int value)
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.
Definition channel.c:1566
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition channel.h:2984
#define AST_MAX_EXTENSION
Definition channel.h:134
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
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.
Definition channel.c:2390
@ AST_STATE_DOWN
size_t current
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
short word
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
@ AST_DEVICE_TOTAL
Definition devicestate.h:62
Dialing API.
enum ast_dial_result ast_dial_state(struct ast_dial *dial)
Return state of dial.
Definition dial.c:1011
ast_dial_result
List of return codes for dial run API calls.
Definition dial.h:54
@ AST_DIAL_RESULT_FAILED
Definition dial.h:56
@ AST_DIAL_RESULT_HANGUP
Definition dial.h:63
@ AST_DIAL_RESULT_ANSWERED
Definition dial.h:61
@ AST_DIAL_RESULT_PROGRESS
Definition dial.h:59
void ast_dial_set_state_callback(struct ast_dial *dial, ast_dial_state_callback callback)
Set a callback for state changes.
Definition dial.c:1272
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
Append a channel.
Definition dial.c:280
struct ast_dial * ast_dial_create(void)
New dialing structure.
Definition dial.c:223
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.
Definition dial.c:431
void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout)
Set the maximum time (globally) allowed for trying to ring phones.
Definition dial.c:1287
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
Definition dial.c:938
struct ast_channel * ast_dial_answered_steal(struct ast_dial *dial)
Steal the channel that answered.
Definition dial.c:992
int ast_dial_reason(struct ast_dial *dial, int num)
Get the reason an outgoing channel has failed.
Definition dial.c:1250
@ AST_DIAL_OPTION_PREDIAL
Definition dial.h:47
struct ast_channel * ast_dial_get_channel(struct ast_dial *dial, int num)
Get the dialing channel, if prerun has been executed.
Definition dial.c:1261
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition dial.c:1094
int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data)
Enables an option globally.
Definition dial.c:1148
static int enabled
Definition dnsmgr.c:91
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
pthread_rwlock_t ast_rwlock_t
Definition extconf.c:514
#define AST_PBX_MAX_STACK
Definition extconf.h:225
ext_match_t
Definition extconf.h:214
@ E_MATCH_MASK
Definition extconf.h:218
@ E_MATCH
Definition extconf.h:217
@ E_CANMATCH
Definition extconf.h:216
@ E_FINDLABEL
Definition extconf.h:220
@ E_MATCHMORE
Definition extconf.h:215
@ E_SPAWN
Definition extconf.h:219
void pbx_extension_state_hint_set(struct ast_exten *exten, struct ast_context *context)
void pbx_extension_state_hint_remove(struct ast_exten *exten, struct ast_context *context)
static const char registrar[]
The static registrar for the added dialplan hints.
void pbx_extension_state_autohint_set(struct ast_context *context)
void pbx_extension_state_autohint_remove(struct ast_context *context, unsigned int forced)
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition format_mp3.c:68
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:2042
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:2000
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:2078
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1661
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2086
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1921
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7716
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
int indicate_busy(struct ast_channel *chan, const char *data)
int indicate_congestion(struct ast_channel *chan, const char *data)
static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
Definition pbx.c:6539
int ast_option_maxcalls
Definition options.c:80
double ast_option_maxload
Definition options.c:78
long option_minmemfree
Definition options.c:87
#define bc
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
#define ast_hashtab_start_traversal(tab)
Definition hashtab.h:356
#define ast_hashtab_insert_safe(tab, obj)
Definition hashtab.h:316
unsigned int ast_hashtab_hash_int(const int num)
Definition hashtab.c:205
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,...
Definition hashtab.c:789
void ast_hashtab_destroy(struct ast_hashtab *tab, void(*objdestroyfunc)(void *obj))
This func will free the hash table and all its memory.
Definition hashtab.c:363
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition hashtab.c:127
void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
end the traversal, free the iterator, unlock if necc.
Definition hashtab.c:674
#define ast_hashtab_insert_immediate(tab, obj)
Insert without checking.
Definition hashtab.h:290
int ast_hashtab_size(struct ast_hashtab *tab)
Returns the number of elements stored in the hashtab.
Definition hashtab.c:577
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.
Definition hashtab.c:683
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
Definition hashtab.c:486
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
Definition hashtab.h:254
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.
Definition hashtab.c:563
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...
Definition hashtab.c:84
void * ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
Looks up the object, removes the corresponding bucket.
Definition hashtab.c:746
unsigned int ast_hashtab_hash_string(const void *obj)
Hashes a string to a number.
Definition hashtab.c:153
static char prefix[MAX_PREFIX]
Definition http.c:145
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
Configuration File Parser.
#define ast_frfree(fr)
ast_control_frame_type
Internal control frame subtype field values.
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HANGUP
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
ast_callid ast_read_threadstorage_callid(void)
extracts the callid from the thread
Definition logger.c:2268
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition logger.c:2290
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition logger.c:2263
unsigned int ast_callid
#define LOG_DEBUG
#define VERBOSITY_ATLEAST(level)
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
Tone Indication Support.
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition localtime.c:2357
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....
Definition localtime.c:2550
Asterisk locking-related definitions:
#define ast_rwlock_wrlock(a)
Definition lock.h:243
#define ast_cond_destroy(cond)
Definition lock.h:209
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_rwlock_rdlock(a)
Definition lock.h:242
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition lock.h:231
pthread_cond_t ast_cond_t
Definition lock.h:185
#define ast_rwlock_destroy(rwlock)
Definition lock.h:240
#define ast_rwlock_unlock(a)
Definition lock.h:241
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define ast_cond_signal(cond)
Definition lock.h:210
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:204
#define EVENT_FLAG_CONFIG
Definition manager.h:82
Asterisk module definitions.
Music on hold handling.
#define ast_fully_booted
Definition options.h:127
Asterisk file paths, configured in asterisk.conf.
void * ast_get_extension_app_data(struct ast_exten *e)
Definition pbx.c:6720
static void pbx_outgoing_state_callback(struct ast_dial *dial)
Internal dialing state callback which causes early media to trigger an answer.
Definition pbx.c:5937
static int hashtab_compare_extens(const void *ha_a, const void *ah_b)
Definition pbx.c:347
const struct ast_sw * ast_context_switches_get(const struct ast_context *con, int idx)
Definition pbx.c:6797
static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
Definition pbx.c:695
void unreference_cached_app(struct ast_app *app)
Definition pbx.c:4523
void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
Definition pbx.c:6342
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.
Definition pbx.c:5206
static int totalcalls
Definition pbx.c:423
int ast_context_destroy_by_name(const char *context, const char *registrar)
Destroy a context by name.
Definition pbx.c:6491
static int manager_show_dialplan(struct mansession *s, const struct message *m)
Manager listing of dial plan.
Definition pbx.c:4365
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
Remove an ignorepat.
Definition pbx.c:5093
static int countcalls
Definition pbx.c:422
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.
Definition pbx.c:2740
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.
Definition pbx.c:5963
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)
Definition pbx.c:6208
static struct ast_exten * trie_find_next_match(struct match_char *node)
Definition pbx.c:791
int ast_get_extension_priority(struct ast_exten *exten)
Definition pbx.c:6677
int ast_wrlock_contexts(void)
Write locks the context list.
Definition pbx.c:6621
static void pbx_destroy(struct ast_pbx *p)
Definition pbx.c:616
void ast_context_set_autohints(struct ast_context *con, int enabled)
Enable or disable autohints support on a context.
Definition pbx.c:4626
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition pbx.c:337
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.
Definition pbx.c:3476
int ast_pbx_outgoing_app_predial(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, const char *predial_callee)
Definition pbx.c:6272
int ast_get_extension_registrar_line(struct ast_exten *e)
Get line number of configuration file used by registrar to register this extension.
Definition pbx.c:6700
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...
Definition pbx.c:3538
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.
Definition pbx.c:5565
int ast_get_extension_matchcid(struct ast_exten *e)
Definition pbx.c:6705
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition pbx.c:6808
int ast_async_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition pbx.c:6944
static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
Definition pbx.c:2465
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.
Definition pbx.c:6262
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition pbx.c:3295
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)
Definition pbx.c:862
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition pbx.c:6639
void wait_for_hangup(struct ast_channel *chan, const void *data)
Definition pbx.c:6514
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
Definition pbx.c:375
static int ext_cmp(const char *left, const char *right)
Definition pbx.c:1766
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.
Definition pbx.c:5349
int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
Add an ignorepat.
Definition pbx.c:5133
static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
Definition pbx.c:742
const char * ast_get_extension_app(struct ast_exten *e)
Definition pbx.c:6715
static void destroy_pattern_tree(struct match_char *pattern_tree)
Definition pbx.c:1419
int ast_context_add_include(const char *context, const char *include, const char *registrar)
Add a context include.
Definition pbx.c:4962
static int extenpatternmatchnew
Definition pbx.c:418
static char * complete_show_dialplan_context(const char *line, const char *word, int pos, int state)
Definition pbx.c:3793
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.
Definition pbx.c:5539
static void decrease_call_count(void)
Definition pbx.c:3226
int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition pbx.c:5106
static void * pbx_outgoing_exec(void *data)
Internal function which dials an outgoing leg and sends it to a provided extension or application.
Definition pbx.c:5874
static const struct ast_datastore_info exception_store_info
Definition pbx.c:2416
static int ext_fluff_count(const char *exten)
Definition pbx.c:1788
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition pbx.c:3315
static struct ast_hashtab * contexts_table
Definition pbx.c:426
static unsigned int hashtab_hash_extens(const void *obj)
Definition pbx.c:395
#define BITS_PER
static int ext_cmp_exten_strlen(const char *str)
Definition pbx.c:1443
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition pbx.c:2108
static unsigned int hashtab_hash_priority(const void *obj)
Definition pbx.c:405
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition pbx.c:6710
#define STATUS_NO_LABEL
Definition pbx.c:2093
static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
Definition pbx.c:5308
int ast_active_calls(void)
Retrieve the number of active calls.
Definition pbx.c:3320
#define STATUS_NO_EXTENSION
Definition pbx.c:2091
static ast_mutex_t maxcalllock
Definition pbx.c:421
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition pbx.c:389
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition pbx.c:2065
static int ext_cmp_exten(const char *left, const char *right)
Definition pbx.c:1516
static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
Definition pbx.c:4641
static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
Definition pbx.c:6918
static int autofallthrough
Definition pbx.c:417
static void exception_store_free(void *data)
Definition pbx.c:2409
static struct match_char * already_in_tree(struct match_char *current, char *pat, int is_pattern)
Definition pbx.c:1028
static char * handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition pbx.c:4479
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition pbx.c:2735
static int compare_char(const void *a, const void *b)
Definition pbx.c:328
int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition pbx.c:5146
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.
Definition pbx.c:4542
static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
Definition pbx.c:4680
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.
Definition pbx.c:3847
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.
Definition pbx.c:6949
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.
Definition pbx.c:6198
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
Definition pbx.c:3325
static void manager_dpsendack(struct mansession *s, const struct message *m)
Send ack once.
Definition pbx.c:4201
static void create_match_char_tree(struct ast_context *con)
Definition pbx.c:1396
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition pbx.c:3508
static ast_mutex_t conlock
Lock for the ast_context list.
Definition pbx.c:434
static struct match_char * add_pattern_node(struct ast_context *con, struct match_char *current, const struct pattern_node *pattern, int is_pattern, int already, struct match_char **nextcharptr)
Definition pbx.c:1090
int raise_exception(struct ast_channel *chan, const char *reason, int priority)
Definition pbx.c:2432
const char * ast_get_context_registrar(struct ast_context *c)
Definition pbx.c:6685
int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
Add a switch.
Definition pbx.c:5027
#define NEW_MATCHER_RECURSE
void pbx_set_overrideswitch(const char *newval)
Definition pbx.c:3344
int ast_unlock_context(struct ast_context *con)
Definition pbx.c:6649
static void unload_pbx(void)
Definition pbx.c:6586
static int increase_call_count(const struct ast_channel *c)
Increase call count for channel.
Definition pbx.c:3177
int ast_extension_close(const char *pattern, const char *data, int needmore)
Definition pbx.c:2058
const char * ast_get_extension_label(struct ast_exten *exten)
Definition pbx.c:6672
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition pbx.c:3374
int pbx_set_extenpatternmatchnew(int newval)
Definition pbx.c:3337
static void pbx_outgoing_destroy(void *obj)
Destructor for outgoing structure.
Definition pbx.c:5860
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,...
Definition pbx.c:3419
static char * overrideswitch
Definition pbx.c:419
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition pbx.c:6939
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
Definition pbx.c:6662
static int ast_remove_hint(struct ast_exten *e)
Definition pbx.c:2653
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
Definition pbx.c:2765
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition pbx.c:4982
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)
Definition pbx.c:3543
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.
Definition pbx.c:2750
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)
Definition pbx.c:2760
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition pbx.c:2053
static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, 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, int early_media, const struct ast_assigned_ids *assignedids, const char *predial_callee)
Definition pbx.c:6002
int ast_pbx_init(void)
Definition pbx.c:7045
static void print_ext(struct ast_exten *e, char *buf, int buflen)
helper function to print an extension
Definition pbx.c:3833
static char * handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Send ack once.
Definition pbx.c:4145
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...
Definition pbx.c:1603
int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
Remove a switch.
Definition pbx.c:3454
#define MAX_EXTENBUF_SIZE
Definition pbx.c:1288
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition pbx.c:3268
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[])
Definition pbx.c:4023
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition pbx.c:5223
static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
Definition pbx.c:6990
int ast_rdlock_contexts(void)
Read locks the context list.
Definition pbx.c:6626
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition pbx.c:7029
#define STATUS_NO_CONTEXT
Definition pbx.c:2090
static int matchcid(const char *cidpattern, const char *callerid)
Definition pbx.c:2096
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.
Definition pbx.c:2745
static struct match_char * add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
Definition pbx.c:1289
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition pbx.c:5177
int ast_context_ignorepats_count(const struct ast_context *con)
Definition pbx.c:6880
int ast_extension_cmp(const char *a, const char *b)
Determine if one extension should match before another.
Definition pbx.c:1823
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition pbx.c:6842
static struct ast_custom_function testtime_function
Definition pbx.c:6563
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition pbx.c:1849
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
Definition pbx.c:382
static struct ast_context * contexts
Definition pbx.c:425
#define EXT_DATA_SIZE
Definition pbx.c:182
const struct ast_sw * ast_walk_context_switches(const struct ast_context *con, const struct ast_sw *sw)
Definition pbx.c:6763
static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, struct ast_pbx_args *args)
Definition pbx.c:2866
static const char * get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
Definition pbx.c:1144
#define STATUS_NO_PRIORITY
Definition pbx.c:2092
const char * ast_get_context_name(struct ast_context *con)
Definition pbx.c:6657
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.
Definition pbx.c:6725
int load_pbx(void)
Definition pbx.c:6594
static const char * candidate_exten_advance(const char *str)
Definition pbx.c:850
static struct ast_exten * ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
Definition pbx.c:2644
ast_context_scope
Definition pbx.c:196
@ AST_CONTEXT_SCOPE_GLOBAL
Definition pbx.c:198
@ AST_CONTEXT_SCOPE_LOCAL
Definition pbx.c:197
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)
Definition pbx.c:2755
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.
Definition pbx.c:2697
static struct ast_cli_entry pbx_cli[]
Definition pbx.c:4510
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition pbx.c:6568
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[])
Definition pbx.c:3862
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...
Definition pbx.c:3396
const struct ast_ignorepat * ast_walk_context_ignorepats(const struct ast_context *con, const struct ast_ignorepat *ip)
Definition pbx.c:6847
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.
Definition pbx.c:2638
static void pbx_shutdown(void)
Definition pbx.c:7038
const struct ast_ignorepat * ast_context_ignorepats_get(const struct ast_context *con, int idx)
Definition pbx.c:6885
static int ext_cmp_pattern(const char *left, const char *right)
Definition pbx.c:1718
static char * handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition pbx.c:4451
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition pbx.c:6802
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.
Definition pbx.c:5548
static char * handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition pbx.c:4078
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
Change hint for an extension.
Definition pbx.c:2680
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.
Definition pbx.c:5251
static void destroy_exten(struct ast_exten *e)
Definition pbx.c:3234
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)
Definition pbx.c:5047
static struct ast_context * find_context(const char *context)
lookup for a context with a given name,
Definition pbx.c:3360
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:
Definition pbx.c:2516
static int ast_add_hint(struct ast_exten *e)
Definition pbx.c:2666
static unsigned int hashtab_hash_labels(const void *obj)
Definition pbx.c:411
int ast_unlock_contexts(void)
Unlocks contexts.
Definition pbx.c:6631
static struct ast_custom_function exception_function
Definition pbx.c:2493
#define STATUS_SUCCESS
Definition pbx.c:2094
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
Definition pbx.c:6754
int ast_context_switches_count(const struct ast_context *con)
Definition pbx.c:6792
#define NEW_MATCHER_CHK_MATCH
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition pbx.c:7024
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.
Definition pbx.c:2715
int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
Definition pbx.c:3513
int pbx_set_autofallthrough(int newval)
Definition pbx.c:3330
static int context_promote(struct ast_context *context)
Definition pbx.c:4812
int ast_context_includes_count(const struct ast_context *con)
Definition pbx.c:6837
static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
collect digits from the channel into the buffer.
Definition pbx.c:2839
static void * pbx_thread(void *data)
Definition pbx.c:3248
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...
Definition pbx.c:4210
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.
Definition pbx.c:5284
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition pbx.c:2040
static struct ast_exten * get_canmatch_exten(struct match_char *node)
Definition pbx.c:772
const char * ast_get_extension_name(struct ast_exten *exten)
Definition pbx.c:6667
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
Definition pbx.c:1049
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition pbx.c:6644
const char * ast_get_extension_registrar_file(struct ast_exten *e)
Get name of configuration file used by registrar to register this extension.
Definition pbx.c:6695
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition pbx.c:6690
static void __ast_internal_context_destroy(struct ast_context *con)
Definition pbx.c:6297
static int ext_cmp_exten_partial(const char *left, const char *right)
Definition pbx.c:1473
#define INC_DST_OVERFLOW_CHECK
void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
Definition pbx.c:2824
Core PBX routines and definitions.
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
ast_pbx_result
The result codes when starting the PBX on a channel with ast_pbx_start.
Definition pbx.h:372
@ AST_PBX_FAILED
Definition pbx.h:374
@ AST_PBX_CALL_LIMIT
Definition pbx.h:375
@ AST_PBX_SUCCESS
Definition pbx.h:373
int ast_thread_inhibit_escalations_swap(int inhibit)
Swap the current thread escalation inhibit setting.
@ AST_OUTGOING_WAIT_COMPLETE
Definition pbx.h:1146
#define AST_MAX_APP
Definition pbx.h:40
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
Map devstate to an extension state.
@ AST_EXT_MATCHCID_ON
Definition pbx.h:79
@ AST_EXT_MATCHCID_OFF
Definition pbx.h:78
@ AST_EXT_MATCHCID_ANY
Definition pbx.h:80
const char * ast_get_switch_name(const struct ast_sw *sw)
Definition pbx_sw.c:48
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
const char * ast_get_switch_data(const struct ast_sw *sw)
Definition pbx_sw.c:53
#define AST_PBX_INCOMPLETE
Definition pbx.h:51
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition pbx_app.c:483
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.
const char * ast_get_include_name(const struct ast_include *include)
Definition pbx_include.c:50
const char * ast_get_ignorepat_registrar(const struct ast_ignorepat *ip)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
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.
Definition pbx.h:158
#define AST_PBX_ERROR
Definition pbx.h:50
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
#define PRIORITY_HINT
Definition pbx.h:54
#define AST_PBX_GOTO_FAILED
Definition pbx.h:42
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition ael_main.c:165
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
Run all hangup handlers on the channel.
int ast_get_switch_eval(const struct ast_sw *sw)
Definition pbx_sw.c:58
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
const char * ast_get_include_registrar(const struct ast_include *i)
Definition pbx_include.c:60
const char * ast_get_ignorepat_name(const struct ast_ignorepat *ip)
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
const char * ast_get_switch_registrar(const struct ast_sw *sw)
Definition pbx_sw.c:63
const char * app_name(struct ast_app *app)
Definition pbx_app.c:475
static struct ast_context * local_contexts
Definition pbx_config.c:117
void ignorepat_free(struct ast_ignorepat *ip)
struct ast_ignorepat * ignorepat_alloc(const char *value, const char *registrar)
void include_free(struct ast_include *inc)
int include_valid(const struct ast_include *inc)
Definition pbx_include.c:65
struct ast_include * include_alloc(const char *value, const char *registrar)
Definition pbx_include.c:74
const char * include_rname(const struct ast_include *inc)
Definition pbx_include.c:55
Private include file for pbx.
struct ast_switch * pbx_findswitch(const char *sw)
Definition pbx_switch.c:40
struct ast_sw * sw_alloc(const char *value, const char *data, int eval, const char *registrar)
Definition pbx_sw.c:68
void sw_free(struct ast_sw *sw)
Definition pbx_sw.c:101
#define VAR_BUF_SIZE
Definition pbx_private.h:76
static struct @522 args
#define NULL
Definition resample.c:96
Say numbers and dates (maybe words one day too)
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_alloca(init_len)
Definition strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
size_t attribute_pure ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition strings.h:742
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition strings.h:909
const char * name
ast_app: A registered application
Definition pbx_app.c:45
Structure to pass both assignedid values to channel drivers.
Definition channel.h:606
Main Channel structure associated with a channel.
char exten[AST_MAX_EXTENSION]
const char * data
struct ast_party_dialed dialed
Dialed/Called information.
char context[AST_MAX_CONTEXT]
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
ast_context: An extension context
Definition pbx.c:254
struct ast_sws alts
Definition pbx.c:265
struct ast_exten * root
Definition pbx.c:259
enum ast_context_scope scope
Definition pbx.c:266
struct match_char * pattern_tree
Definition pbx.c:261
int refcount
Definition pbx.c:267
struct ast_ignorepats ignorepats
Definition pbx.c:264
struct ast_includes includes
Definition pbx.c:263
int autohints
Definition pbx.c:268
const char * registrar
Definition pbx.c:256
char data[]
Definition pbx.c:275
struct ast_context * next
Definition pbx.c:262
struct ast_hashtab * root_table
Definition pbx.c:260
ast_rwlock_t lock
Definition pbx.c:258
const char * name
Definition pbx.c:255
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * name
Definition pbx.h:119
Structure for a data store type.
Definition datastore.h:31
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66
You shouldn't care about the contents of this struct.
Main dialing structure. Contains global options, channels being dialed, and more!
Definition dial.c:48
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition pbx.c:207
const char * cidmatch_display
Definition pbx.c:212
char * exten
Definition pbx.c:208
struct ast_hashtab * peer_label_table
Definition pbx.c:222
struct ast_hashtab * peer_table
Definition pbx.c:221
char stuff[0]
Definition pbx.c:227
const char * app
Definition pbx.c:216
const char * registrar_file
Definition pbx.c:224
struct ast_app * cached_app
Definition pbx.c:217
char * name
Definition pbx.c:209
const char * registrar
Definition pbx.c:223
const char * cidmatch
Definition pbx.c:211
int registrar_line
Definition pbx.c:225
struct ast_context * parent
Definition pbx.c:215
struct ast_exten * peer
Definition pbx.c:220
void * data
Definition pbx.c:218
struct ast_exten * next
Definition pbx.c:226
int priority
Definition pbx.c:213
void(* datad)(void *)
Definition pbx.c:219
const char * label
Definition pbx.c:214
int matchcid
Definition pbx.c:210
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Data structure associated with a single frame of data.
union ast_frame::@237 data
an iterator for traversing the buckets
Definition hashtab.h:106
ast_ignorepat: Ignore patterns in dial plan
const char pattern[0]
struct ast_ignorepat * next
Definition extconf.c:2386
ast_include: include= support in extensions.conf
Definition pbx_include.c:37
struct ast_include * next
Definition extconf.c:2368
Connected Line/Party information.
Definition channel.h:458
Options for ast_pbx_run()
Definition pbx.h:409
Definition pbx.h:216
int rtimeoutms
Definition pbx.h:218
int dtimeoutms
Definition pbx.h:217
Support for dynamic strings.
Definition strings.h:623
ast_sw: Switch statement in extensions.conf
Definition pbx_sw.c:37
int eval
Definition pbx_sw.c:43
const char * data
Definition pbx_sw.c:42
struct ast_sw * next
Definition pbx_sw.c:44
ast_switch_f * canmatch
Definition pbx.h:168
ast_switch_f * exists
Definition pbx.h:167
ast_switch_f * exec
Definition pbx.h:169
ast_switch_f * matchmore
Definition pbx.h:170
const char * name
Definition pbx.h:164
Structure for variables, used for configurations and for channel variables.
Counters for the show dialplan manager command.
Definition pbx.c:3823
int total_context
Definition pbx.c:3825
int context_existence
Definition pbx.c:3828
int extension_existence
Definition pbx.c:3829
structure to hold extensions
In case you didn't read that giant block of text above the mansession_session struct,...
Definition manager.c:323
match_char: forms a syntax tree for quick matching of extension patterns
Definition pbx.c:232
int deleted
Definition pbx.c:234
int is_pattern
Definition pbx.c:233
struct match_char * alt_char
Definition pbx.c:236
int specificity
Definition pbx.c:235
char x[1]
Definition pbx.c:239
struct match_char * next_char
Definition pbx.c:237
struct ast_exten * exten
Definition pbx.c:238
Number structure.
const ast_string_field app
Definition pbx_spool.c:95
const ast_string_field context
Definition pbx_spool.c:95
const ast_string_field exten
Definition pbx_spool.c:95
int priority
Definition pbx_spool.c:96
char buf[256]
Definition pbx.c:1087
int specif
Definition pbx.c:1085
const ast_string_field context
Definition pbx.c:283
const ast_string_field exten
Definition pbx.c:283
int priority
Definition pbx.c:285
const ast_string_field reason
Definition pbx.c:283
struct ast_switch * swo
Definition extconf.h:239
char * incstack[AST_PBX_MAX_STACK]
Definition extconf.h:236
const char * foundcontext
Definition extconf.h:241
const char * data
Definition extconf.h:240
Structure which contains information about an outgoing dial.
Definition pbx.c:5836
int dial_res
Result of the dial operation when dialed is set.
Definition pbx.c:5852
ast_cond_t cond
Condition for synchronous dialing.
Definition pbx.c:5840
char app[AST_MAX_APP]
Application to execute.
Definition pbx.c:5842
unsigned int in_separate_thread
Set if we've spawned a thread to do our work.
Definition pbx.c:5856
struct ast_dial * dial
Dialing structure being used.
Definition pbx.c:5838
unsigned int dialed
Set when dialing is completed.
Definition pbx.c:5854
char exten[AST_MAX_EXTENSION]
Dialplan extension.
Definition pbx.c:5848
char context[AST_MAX_CONTEXT]
Dialplan context.
Definition pbx.c:5846
int priority
Dialplan priority.
Definition pbx.c:5850
char * appdata
Application data to pass to application.
Definition pbx.c:5844
int canmatch
Definition pbx.c:247
int total_length
Definition pbx.c:245
int total_specificity
Definition pbx.c:244
char last_char
Definition pbx.c:246
struct match_char * node
Definition pbx.c:248
struct ast_exten * exten
Definition pbx.c:250
struct ast_exten * canmatch_exten
Definition pbx.c:249
const char * name
int value
Definition syslog.c:37
Handy terminal functions for vt* terms.
#define COLOR_BRCYAN
Definition term.h:63
#define COLORIZE(fg, bg, str)
Definition term.h:72
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition term.h:71
#define COLOR_BRMAGENTA
Definition term.h:61
static struct aco_type item
static struct test_val b
static struct test_val a
static struct test_val c
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Time-related functions and macros.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition time.h:87
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
int error(const char *format,...)
Utility functions.
#define ast_test_flag(p, flag)
Definition utils.h:64
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ast_set2_flag(p, value, flag)
Definition utils.h:95
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_pthread_create_detached(a, b, c, d)
Definition utils.h:628
#define ast_set_flag(p, flag)
Definition utils.h:71
#define ARRAY_LEN(a)
Definition utils.h:706
Vector container support.
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition vector.h:459
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition vector.h:873
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691
Asterisk XML Documentation API.