Asterisk - The Open Source Telephony Project GIT-master-43bf8a4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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"
57#define SAY_STUBS /* generate declarations and stubs for say methods */
58#include "asterisk/say.h"
59#include "asterisk/utils.h"
60#include "asterisk/causes.h"
62#include "asterisk/app.h"
65#include "asterisk/hashtab.h"
66#include "asterisk/module.h"
69#include "asterisk/xmldoc.h"
70#include "asterisk/astobj2.h"
72#include "asterisk/dial.h"
73#include "asterisk/vector.h"
74#include "pbx_private.h"
75
76/*!
77 * \note I M P O R T A N T :
78 *
79 * The speed of extension handling will likely be among the most important
80 * aspects of this PBX. The switching scheme as it exists right now isn't
81 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
82 * of priorities, but a constant search time here would be great ;-)
83 *
84 * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
85 * here, and shows a fairly flat (constant) search time, even for over
86 * 10000 patterns.
87 *
88 * Also, using a hash table for context/priority name lookup can help prevent
89 * the find_extension routines from absorbing exponential cpu cycles as the number
90 * of contexts/priorities grow. I've previously tested find_extension with red-black trees,
91 * which have O(log2(n)) speed. Right now, I'm using hash tables, which do
92 * searches (ideally) in O(1) time. While these techniques do not yield much
93 * speed in small dialplans, they are worth the trouble in large dialplans.
94 *
95 */
96
97/*** DOCUMENTATION
98 <function name="EXCEPTION" language="en_US">
99 <since>
100 <version>1.6.0</version>
101 </since>
102 <synopsis>
103 Retrieve the details of the current dialplan exception.
104 </synopsis>
105 <syntax>
106 <parameter name="field" required="true">
107 <para>The following fields are available for retrieval:</para>
108 <enumlist>
109 <enum name="reason">
110 <para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
111 value set by the RaiseException() application</para>
112 </enum>
113 <enum name="context">
114 <para>The context executing when the exception occurred.</para>
115 </enum>
116 <enum name="exten">
117 <para>The extension executing when the exception occurred.</para>
118 </enum>
119 <enum name="priority">
120 <para>The numeric priority executing when the exception occurred.</para>
121 </enum>
122 </enumlist>
123 </parameter>
124 </syntax>
125 <description>
126 <para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
127 </description>
128 <see-also>
129 <ref type="application">RaiseException</ref>
130 </see-also>
131 </function>
132 <function name="TESTTIME" language="en_US">
133 <since>
134 <version>1.8.0</version>
135 </since>
136 <synopsis>
137 Sets a time to be used with the channel to test logical conditions.
138 </synopsis>
139 <syntax>
140 <parameter name="date" required="true" argsep=" ">
141 <para>Date in ISO 8601 format</para>
142 </parameter>
143 <parameter name="time" required="true" argsep=" ">
144 <para>Time in HH:MM:SS format (24-hour time)</para>
145 </parameter>
146 <parameter name="zone" required="false">
147 <para>Timezone name</para>
148 </parameter>
149 </syntax>
150 <description>
151 <para>To test dialplan timing conditions at times other than the current time, use
152 this function to set an alternate date and time. For example, you may wish to evaluate
153 whether a location will correctly identify to callers that the area is closed on Christmas
154 Day, when Christmas would otherwise fall on a day when the office is normally open.</para>
155 </description>
156 <see-also>
157 <ref type="application">GotoIfTime</ref>
158 </see-also>
159 </function>
160 <manager name="ShowDialPlan" language="en_US">
161 <since>
162 <version>1.6.0</version>
163 </since>
164 <synopsis>
165 Show dialplan contexts and extensions
166 </synopsis>
167 <syntax>
168 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
169 <parameter name="Extension">
170 <para>Show a specific extension.</para>
171 </parameter>
172 <parameter name="Context">
173 <para>Show a specific context.</para>
174 </parameter>
175 </syntax>
176 <description>
177 <para>Show dialplan contexts and extensions. Be aware that showing the full dialplan
178 may take a lot of capacity.</para>
179 </description>
180 </manager>
181 <manager name="ExtensionStateList" language="en_US">
182 <since>
183 <version>13.0.0</version>
184 </since>
185 <synopsis>
186 List the current known extension states.
187 </synopsis>
188 <syntax>
189 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
190 </syntax>
191 <description>
192 <para>This will list out all known extension states in a
193 sequence of <replaceable>ExtensionStatus</replaceable> events.
194 When finished, a <replaceable>ExtensionStateListComplete</replaceable> event
195 will be emitted.</para>
196 </description>
197 <see-also>
198 <ref type="manager">ExtensionState</ref>
199 <ref type="function">HINT</ref>
200 <ref type="function">EXTENSION_STATE</ref>
201 </see-also>
202 <responses>
203 <list-elements>
204 <xi:include xpointer="xpointer(/docs/managerEvent[@name='ExtensionStatus'])" />
205 </list-elements>
206 <managerEvent name="ExtensionStateListComplete" language="en_US">
207 <managerEventInstance class="EVENT_FLAG_COMMAND">
208 <since>
209 <version>13.0.0</version>
210 </since>
211 <synopsis>
212 Indicates the end of the list the current known extension states.
213 </synopsis>
214 <syntax>
215 <parameter name="EventList">
216 <para>Conveys the status of the event list.</para>
217 </parameter>
218 <parameter name="ListItems">
219 <para>Conveys the number of statuses reported.</para>
220 </parameter>
221 </syntax>
222 </managerEventInstance>
223 </managerEvent>
224 </responses>
225 </manager>
226 ***/
227
228#ifdef LOW_MEMORY
229#define EXT_DATA_SIZE 256
230#else
231#define EXT_DATA_SIZE 8192
232#endif
233
234#define SWITCH_DATA_LENGTH 256
235
236#define VAR_NORMAL 1
237#define VAR_SOFTTRAN 2
238#define VAR_HARDTRAN 3
239
240struct ast_context;
241struct ast_app;
242
245
246/*!
247 \brief ast_exten: An extension
248 The dialplan is saved as a linked list with each context
249 having it's own linked list of extensions - one item per
250 priority.
251*/
252struct ast_exten {
253 char *exten; /*!< Clean Extension id */
254 char *name; /*!< Extension name (may include '-' eye candy) */
255 int matchcid; /*!< Match caller id ? */
256 const char *cidmatch; /*!< Caller id to match for this extension */
257 const char *cidmatch_display; /*!< Caller id to match (display version) */
258 int priority; /*!< Priority */
259 const char *label; /*!< Label */
260 struct ast_context *parent; /*!< The context this extension belongs to */
261 const char *app; /*!< Application to execute */
262 struct ast_app *cached_app; /*!< Cached location of application */
263 void *data; /*!< Data to use (arguments) */
264 void (*datad)(void *); /*!< Data destructor */
265 struct ast_exten *peer; /*!< Next higher priority with our extension */
266 struct ast_hashtab *peer_table; /*!< Priorities list in hashtab form -- only on the head of the peer list */
267 struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
268 const char *registrar; /*!< Registrar */
269 const char *registrar_file; /*!< File name used to register extension */
270 int registrar_line; /*!< Line number the extension was registered in text */
271 struct ast_exten *next; /*!< Extension with a greater ID */
272 char stuff[0];
273};
274
275/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
277{
278 int is_pattern; /* the pattern started with '_' */
279 int deleted; /* if this is set, then... don't return it */
280 int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
283 struct ast_exten *exten; /* attached to last char of a pattern for exten */
284 char x[1]; /* the pattern itself-- matches a single char */
285};
286
287struct scoreboard /* make sure all fields are 0 before calling new_find_extension */
288{
291 char last_char; /* set to ! or . if they are the end of the pattern */
292 int canmatch; /* if the string to match was just too short */
296};
297
298/*! \brief ast_context: An extension context */
300 const char *name;
301 const char *registrar;
302
303 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
304 struct ast_exten *root; /*!< The root of the list of extensions */
305 struct ast_hashtab *root_table; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */
306 struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */
307 struct ast_context *next; /*!< Link them together */
308 struct ast_includes includes; /*!< Include other contexts */
309 struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */
310 struct ast_sws alts; /*!< Alternative switches */
311 int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */
312 int autohints; /*!< Whether autohints support is enabled or not */
313
314 /*!
315 * Buffer to hold the name & registrar character data.
316 *
317 * The context name *must* be stored first in this buffer.
318 */
319 char data[];
320};
321
322/*! \brief ast_state_cb: An extension state notify register item */
324 /*! Watcher ID returned when registered. */
325 int id;
326 /*! Arbitrary data passed for callbacks. */
327 void *data;
328 /*! Flag if this callback is an extended callback containing detailed device status */
330 /*! Callback when state changes. */
332 /*! Callback when destroyed so any resources given by the registerer can be freed. */
334 /*! \note Only used by ast_merge_contexts_and_delete */
336};
337
338/*!
339 * \brief Structure for dial plan hints
340 *
341 * \note Hints are pointers from an extension in the dialplan to
342 * one or more devices (tech/name)
343 *
344 * See \ref AstExtState
345 */
346struct ast_hint {
347 /*!
348 * \brief Hint extension
349 *
350 * \note
351 * Will never be NULL while the hint is in the hints container.
352 */
354 struct ao2_container *callbacks; /*!< Device state callback container for this extension */
355
356 /*! Dev state variables */
357 int laststate; /*!< Last known device state */
358
359 /*! Presence state variables */
360 int last_presence_state; /*!< Last known presence state */
361 char *last_presence_subtype; /*!< Last known presence subtype string */
362 char *last_presence_message; /*!< Last known presence message string */
363
364 char context_name[AST_MAX_CONTEXT];/*!< Context of destroyed hint extension. */
365 char exten_name[AST_MAX_EXTENSION];/*!< Extension of destroyed hint extension. */
366
367 AST_VECTOR(, char *) devices; /*!< Devices associated with the hint */
368};
369
370STASIS_MESSAGE_TYPE_DEFN_LOCAL(hint_change_message_type);
371STASIS_MESSAGE_TYPE_DEFN_LOCAL(hint_remove_message_type);
372
373#define HINTDEVICE_DATA_LENGTH 16
375
376/* --- Hash tables of various objects --------*/
377#ifdef LOW_MEMORY
378#define HASH_EXTENHINT_SIZE 17
379#else
380#define HASH_EXTENHINT_SIZE 563
381#endif
382
383
384/*! \brief Container for hint devices */
386
387/*!
388 * \brief Structure for dial plan hint devices
389 * \note hintdevice is one device pointing to a hint.
390 */
392 /*!
393 * \brief Hint this hintdevice belongs to.
394 * \note Holds a reference to the hint object.
395 */
396 struct ast_hint *hint;
397 /*! Name of the hint device. */
398 char hintdevice[1];
399};
400
401/*! \brief Container for autohint contexts */
403
404/*!
405 * \brief Structure for dial plan autohints
406 */
408 /*! \brief Name of the registrar */
410 /*! \brief Name of the context */
411 char context[1];
412};
413
414/*!
415 * \note Using the device for hash
416 */
417static int hintdevice_hash_cb(const void *obj, const int flags)
418{
419 const struct ast_hintdevice *ext;
420 const char *key;
421
422 switch (flags & OBJ_SEARCH_MASK) {
423 case OBJ_SEARCH_KEY:
424 key = obj;
425 break;
427 ext = obj;
428 key = ext->hintdevice;
429 break;
430 default:
431 ast_assert(0);
432 return 0;
433 }
434
435 return ast_str_case_hash(key);
436}
437
438/*!
439 * \note Devices on hints are not unique so no CMP_STOP is returned
440 * Dont use ao2_find against hintdevices container cause there always
441 * could be more than one result.
442 */
443static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
444{
445 struct ast_hintdevice *left = obj;
446 struct ast_hintdevice *right = arg;
447 const char *right_key = arg;
448 int cmp;
449
450 switch (flags & OBJ_SEARCH_MASK) {
452 right_key = right->hintdevice;
453 /* Fall through */
454 case OBJ_SEARCH_KEY:
455 cmp = strcasecmp(left->hintdevice, right_key);
456 break;
458 /*
459 * We could also use a partial key struct containing a length
460 * so strlen() does not get called for every comparison instead.
461 */
462 cmp = strncmp(left->hintdevice, right_key, strlen(right_key));
463 break;
464 default:
465 ast_assert(0);
466 cmp = 0;
467 break;
468 }
469 return cmp ? 0 : CMP_MATCH;
470}
471
472/*!
473 * \note Using the context name for hash
474 */
475static int autohint_hash_cb(const void *obj, const int flags)
476{
477 const struct ast_autohint *autohint;
478 const char *key;
479
480 switch (flags & OBJ_SEARCH_MASK) {
481 case OBJ_SEARCH_KEY:
482 key = obj;
483 break;
485 autohint = obj;
486 key = autohint->context;
487 break;
488 default:
489 ast_assert(0);
490 return 0;
491 }
492
493 return ast_str_case_hash(key);
494}
495
496static int autohint_cmp(void *obj, void *arg, int flags)
497{
498 struct ast_autohint *left = obj;
499 struct ast_autohint *right = arg;
500 const char *right_key = arg;
501 int cmp;
502
503 switch (flags & OBJ_SEARCH_MASK) {
505 right_key = right->context;
506 /* Fall through */
507 case OBJ_SEARCH_KEY:
508 cmp = strcasecmp(left->context, right_key);
509 break;
511 /*
512 * We could also use a partial key struct containing a length
513 * so strlen() does not get called for every comparison instead.
514 */
515 cmp = strncmp(left->context, right_key, strlen(right_key));
516 break;
517 default:
518 ast_assert(0);
519 cmp = 0;
520 break;
521 }
522 return cmp ? 0 : CMP_MATCH | CMP_STOP;
523}
524
525/*! \internal \brief \c ao2_callback function to remove hintdevices */
526static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags)
527{
528 struct ast_hintdevice *candidate = obj;
529 char *device = arg;
530 struct ast_hint *hint = data;
531
532 if (!strcasecmp(candidate->hintdevice, device)
533 && candidate->hint == hint) {
534 return CMP_MATCH;
535 }
536 return 0;
537}
538
539static int remove_hintdevice(struct ast_hint *hint)
540{
541 while (AST_VECTOR_SIZE(&hint->devices) > 0) {
542 char *device = AST_VECTOR_GET(&hint->devices, 0);
543
545 hintdevice_remove_cb, device, hint, "Remove device from container");
547 ast_free(device);
548 }
549
550 return 0;
551}
552
553static char *parse_hint_device(struct ast_str *hint_args);
554/*!
555 * \internal
556 * \brief Destroy the given hintdevice object.
557 *
558 * \param obj Hint device to destroy.
559 */
560static void hintdevice_destroy(void *obj)
561{
562 struct ast_hintdevice *doomed = obj;
563
564 if (doomed->hint) {
565 ao2_ref(doomed->hint, -1);
566 doomed->hint = NULL;
567 }
568}
569
570/*! \brief add hintdevice structure and link it into the container.
571 */
572static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
573{
574 struct ast_str *str;
575 char *parse;
576 char *cur;
577 struct ast_hintdevice *device;
578 int devicelength;
579
580 if (!hint || !devicelist) {
581 /* Trying to add garbage? Don't bother. */
582 return 0;
583 }
584 if (!(str = ast_str_thread_get(&hintdevice_data, 16))) {
585 return -1;
586 }
587 ast_str_set(&str, 0, "%s", devicelist);
588 parse = ast_str_buffer(str);
589
590 /* Spit on '&' and ',' to handle presence hints as well */
591 while ((cur = strsep(&parse, "&,"))) {
592 char *device_name;
593
594 devicelength = strlen(cur);
595 if (!devicelength) {
596 continue;
597 }
598
599 device_name = ast_strdup(cur);
600 if (!device_name) {
601 return -1;
602 }
603
604 device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
605 "allocating a hintdevice structure");
606 if (!device) {
607 ast_free(device_name);
608 return -1;
609 }
610 strcpy(device->hintdevice, cur);
611 ao2_ref(hint, +1);
612 device->hint = hint;
613 if (AST_VECTOR_APPEND(&hint->devices, device_name)) {
614 ast_free(device_name);
615 ao2_ref(device, -1);
616 return -1;
617 }
618 ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
619 ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
620 }
621
622 return 0;
623}
624
625
626static const struct cfextension_states {
628 const char * const text;
629} extension_states[] = {
630 { AST_EXTENSION_NOT_INUSE, "Idle" },
631 { AST_EXTENSION_INUSE, "InUse" },
632 { AST_EXTENSION_BUSY, "Busy" },
633 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
634 { AST_EXTENSION_RINGING, "Ringing" },
635 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
636 { AST_EXTENSION_ONHOLD, "Hold" },
637 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
639
642 AST_STRING_FIELD(context); /*!< Context associated with this exception */
643 AST_STRING_FIELD(exten); /*!< Exten associated with this exception */
644 AST_STRING_FIELD(reason); /*!< The exception reason */
645 );
646
647 int priority; /*!< Priority associated with this exception */
648};
649
650static int matchcid(const char *cidpattern, const char *callerid);
651#ifdef NEED_DEBUG
652static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
653#endif
654static void new_find_extension(const char *str, struct scoreboard *score,
655 struct match_char *tree, int length, int spec, const char *callerid,
656 const char *label, enum ext_match_t action);
657static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
658static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
659 struct ast_exten *e1, int findonly);
660static void create_match_char_tree(struct ast_context *con);
661static struct ast_exten *get_canmatch_exten(struct match_char *node);
662static void destroy_pattern_tree(struct match_char *pattern_tree);
663static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
664static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
665static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
666static unsigned int hashtab_hash_extens(const void *obj);
667static unsigned int hashtab_hash_priority(const void *obj);
668static unsigned int hashtab_hash_labels(const void *obj);
669static void __ast_internal_context_destroy( struct ast_context *con);
670static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
671 int priority, const char *label, const char *callerid,
672 const char *application, void *data, void (*datad)(void *), const char *registrar);
673static int ast_add_extension2_lockopt(struct ast_context *con,
674 int replace, const char *extension, int priority, const char *label, const char *callerid,
675 const char *application, void *data, void (*datad)(void *),
676 const char *registrar, const char *registrar_file, int registrar_line,
677 int lock_context);
678static struct ast_context *find_context_locked(const char *context);
679static struct ast_context *find_context(const char *context);
681static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff);
682
683/*!
684 * \internal
685 * \brief Character array comparison function for qsort.
686 *
687 * \param a Left side object.
688 * \param b Right side object.
689 *
690 * \retval <0 if a < b
691 * \retval =0 if a = b
692 * \retval >0 if a > b
693 */
694static int compare_char(const void *a, const void *b)
695{
696 const unsigned char *ac = a;
697 const unsigned char *bc = b;
698
699 return *ac - *bc;
700}
701
702/* labels, contexts are case sensitive priority numbers are ints */
703int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
704{
705 const struct ast_context *ac = ah_a;
706 const struct ast_context *bc = ah_b;
707 if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
708 return 1;
709 /* assume context names are registered in a string table! */
710 return strcmp(ac->name, bc->name);
711}
712
713static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
714{
715 const struct ast_exten *ac = ah_a;
716 const struct ast_exten *bc = ah_b;
717 int x = strcmp(ac->exten, bc->exten);
718 if (x) { /* if exten names are diff, then return */
719 return x;
720 }
721
722 /* but if they are the same, do the cidmatch values match? */
723 /* not sure which side may be using ast_ext_matchcid_types, so check both */
724 if (ac->matchcid == AST_EXT_MATCHCID_ANY || bc->matchcid == AST_EXT_MATCHCID_ANY) {
725 return 0;
726 }
727 if (ac->matchcid == AST_EXT_MATCHCID_OFF && bc->matchcid == AST_EXT_MATCHCID_OFF) {
728 return 0;
729 }
730 if (ac->matchcid != bc->matchcid) {
731 return 1;
732 }
733 /* all other cases already disposed of, match now required on callerid string (cidmatch) */
734 /* although ast_add_extension2_lockopt() enforces non-zero ptr, caller may not have */
735 if (ast_strlen_zero(ac->cidmatch) && ast_strlen_zero(bc->cidmatch)) {
736 return 0;
737 }
738 return strcmp(ac->cidmatch, bc->cidmatch);
739}
740
741static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
742{
743 const struct ast_exten *ac = ah_a;
744 const struct ast_exten *bc = ah_b;
745 return ac->priority != bc->priority;
746}
747
748static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
749{
750 const struct ast_exten *ac = ah_a;
751 const struct ast_exten *bc = ah_b;
752 return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
753}
754
755unsigned int ast_hashtab_hash_contexts(const void *obj)
756{
757 const struct ast_context *ac = obj;
758 return ast_hashtab_hash_string(ac->name);
759}
760
761static unsigned int hashtab_hash_extens(const void *obj)
762{
763 const struct ast_exten *ac = obj;
764 unsigned int x = ast_hashtab_hash_string(ac->exten);
765 unsigned int y = 0;
766 if (ac->matchcid == AST_EXT_MATCHCID_ON)
768 return x+y;
769}
770
771static unsigned int hashtab_hash_priority(const void *obj)
772{
773 const struct ast_exten *ac = obj;
774 return ast_hashtab_hash_int(ac->priority);
775}
776
777static unsigned int hashtab_hash_labels(const void *obj)
778{
779 const struct ast_exten *ac = obj;
780 return ast_hashtab_hash_string(S_OR(ac->label, ""));
781}
782
783static int autofallthrough = 1;
784static int extenpatternmatchnew = 0;
785static char *overrideswitch = NULL;
786
787/*! \brief Subscription for device state change events */
789/*! \brief Subscription for presence state change events */
791
793static int countcalls;
794static int totalcalls;
795
796static struct ast_context *contexts;
798
799/*!
800 * \brief Lock for the ast_context list
801 * \note
802 * This lock MUST be recursive, or a deadlock on reload may result. See
803 * https://issues.asterisk.org/view.php?id=17643
804 */
806
807/*!
808 * \brief Lock to hold off restructuring of hints by ast_merge_contexts_and_delete.
809 */
811
812static int stateid = 1;
813/*!
814 * \note When holding this container's lock, do _not_ do
815 * anything that will cause conlock to be taken, unless you
816 * _already_ hold it. The ast_merge_contexts_and_delete function
817 * will take the locks in conlock/hints order, so any other
818 * paths that require both locks must also take them in that
819 * order.
820 */
821static struct ao2_container *hints;
822
823static struct ao2_container *statecbs;
824
825#ifdef CONTEXT_DEBUG
826
827/* these routines are provided for doing run-time checks
828 on the extension structures, in case you are having
829 problems, this routine might help you localize where
830 the problem is occurring. It's kinda like a debug memory
831 allocator's arena checker... It'll eat up your cpu cycles!
832 but you'll see, if you call it in the right places,
833 right where your problems began...
834*/
835
836/* you can break on the check_contexts_trouble()
837routine in your debugger to stop at the moment
838there's a problem */
839void check_contexts_trouble(void);
840
841void check_contexts_trouble(void)
842{
843 int x = 1;
844 x = 2;
845}
846
847int check_contexts(char *, int);
848
849int check_contexts(char *file, int line )
850{
851 struct ast_hashtab_iter *t1;
852 struct ast_context *c1, *c2;
853 int found = 0;
854 struct ast_exten *e1, *e2, *e3;
855 struct ast_exten ex;
856
857 /* try to find inconsistencies */
858 /* is every context in the context table in the context list and vice-versa ? */
859
860 if (!contexts_table) {
861 ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
862 usleep(500000);
863 }
864
866 while( (c1 = ast_hashtab_next(t1))) {
867 for(c2=contexts;c2;c2=c2->next) {
868 if (!strcmp(c1->name, c2->name)) {
869 found = 1;
870 break;
871 }
872 }
873 if (!found) {
874 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
875 check_contexts_trouble();
876 }
877 }
879 for(c2=contexts;c2;c2=c2->next) {
880 c1 = find_context_locked(c2->name);
881 if (!c1) {
882 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
883 check_contexts_trouble();
884 } else
886 }
887
888 /* loop thru all contexts, and verify the exten structure compares to the
889 hashtab structure */
890 for(c2=contexts;c2;c2=c2->next) {
891 c1 = find_context_locked(c2->name);
892 if (c1) {
894
895 /* is every entry in the root list also in the root_table? */
896 for(e1 = c1->root; e1; e1=e1->next)
897 {
898 char dummy_name[1024];
899 ex.exten = dummy_name;
900 ex.matchcid = e1->matchcid;
901 ex.cidmatch = e1->cidmatch;
902 ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
903 e2 = ast_hashtab_lookup(c1->root_table, &ex);
904 if (!e2) {
905 if (e1->matchcid == AST_EXT_MATCHCID_ON) {
906 ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records "
907 "the exten %s (CID match: %s) but it is not in its root_table\n",
908 file, line, c2->name, dummy_name, e1->cidmatch_display);
909 } else {
910 ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records "
911 "the exten %s but it is not in its root_table\n",
912 file, line, c2->name, dummy_name);
913 }
914 check_contexts_trouble();
915 }
916 }
917
918 /* is every entry in the root_table also in the root list? */
919 if (!c2->root_table) {
920 if (c2->root) {
921 ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
922 usleep(500000);
923 }
924 } else {
926 while( (e2 = ast_hashtab_next(t1)) ) {
927 for(e1=c2->root;e1;e1=e1->next) {
928 if (!strcmp(e1->exten, e2->exten)) {
929 found = 1;
930 break;
931 }
932 }
933 if (!found) {
934 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);
935 check_contexts_trouble();
936 }
937
938 }
940 }
941 }
942 /* is every priority reflected in the peer_table at the head of the list? */
943
944 /* is every entry in the root list also in the root_table? */
945 /* are the per-extension peer_tables in the right place? */
946
947 for(e1 = c2->root; e1; e1 = e1->next) {
948
949 for(e2=e1;e2;e2=e2->peer) {
950 ex.priority = e2->priority;
951 if (e2 != e1 && e2->peer_table) {
952 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 );
953 check_contexts_trouble();
954 }
955
956 if (e2 != e1 && e2->peer_label_table) {
957 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 );
958 check_contexts_trouble();
959 }
960
961 if (e2 == e1 && !e2->peer_table){
962 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 );
963 check_contexts_trouble();
964 }
965
966 if (e2 == e1 && !e2->peer_label_table) {
967 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 );
968 check_contexts_trouble();
969 }
970
971
972 e3 = ast_hashtab_lookup(e1->peer_table, &ex);
973 if (!e3) {
974 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 );
975 check_contexts_trouble();
976 }
977 }
978
979 if (!e1->peer_table){
980 ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
981 usleep(500000);
982 }
983
984 /* is every entry in the peer_table also in the peer list? */
986 while( (e2 = ast_hashtab_next(t1)) ) {
987 for(e3=e1;e3;e3=e3->peer) {
988 if (e3->priority == e2->priority) {
989 found = 1;
990 break;
991 }
992 }
993 if (!found) {
994 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 );
995 check_contexts_trouble();
996 }
997 }
999 }
1000 }
1001 return 0;
1002}
1003#endif
1004
1005static void pbx_destroy(struct ast_pbx *p)
1006{
1007 ast_free(p);
1008}
1009
1010/* form a tree that fully describes all the patterns in a context's extensions
1011 * in this tree, a "node" represents an individual character or character set
1012 * meant to match the corresponding character in a dial string. The tree
1013 * consists of a series of match_char structs linked in a chain
1014 * via the alt_char pointers. More than one pattern can share the same parts of the
1015 * tree as other extensions with the same pattern to that point.
1016 * My first attempt to duplicate the finding of the 'best' pattern was flawed in that
1017 * I misunderstood the general algorithm. I thought that the 'best' pattern
1018 * was the one with lowest total score. This was not true. Thus, if you have
1019 * patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
1020 * the "best" match because it has fewer X's, and is therefore more specific,
1021 * but this is not how the old algorithm works. It sorts matching patterns
1022 * in a similar collating sequence as sorting alphabetic strings, from left to
1023 * right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
1024 * because "1" is more specific than "X".
1025 * So, to accommodate this philosophy, I sort the tree branches along the alt_char
1026 * line so they are lowest to highest in specificity numbers. This way, as soon
1027 * as we encounter our first complete match, we automatically have the "best"
1028 * match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
1029 * If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
1030 * they are welcome to revert pbx to before 1 Apr 2008.
1031 * As an example, consider these 4 extensions:
1032 * (a) NXXNXXXXXX
1033 * (b) 307754XXXX
1034 * (c) fax
1035 * (d) NXXXXXXXXX
1036 *
1037 * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
1038 * most numbers. For all numbers beginning with 307754, (b) should always win.
1039 *
1040 * These pattern should form a (sorted) tree that looks like this:
1041 * { "3" } --next--> { "0" } --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
1042 * |
1043 * |alt
1044 * |
1045 * { "f" } --next--> { "a" } --next--> { "x" exten_match: (c) }
1046 * { "N" } --next--> { "X" } --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
1047 * | |
1048 * | |alt
1049 * |alt |
1050 * | { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
1051 * |
1052 * NULL
1053 *
1054 * In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
1055 * fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
1056 *
1057 * traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern, it calls itself
1058 * on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
1059 * We pass a pointer to a scoreboard down through, also.
1060 * The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
1061 * The first complete match ends the traversal, which should make this version of the pattern matcher faster
1062 * the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
1063 * these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
1064 * according to the sort criteria.
1065 * Hope the limit on stack depth won't be a problem... this routine should
1066 * be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
1067 *
1068 * In the above example, with the number "3077549999" as the pattern, the traverser could match extensions a, b and d. All are
1069 * of length 10; they have total specificities of 24580, 10246, and 25090, respectively, not that this matters
1070 * at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
1071 * left the specificity totals in the code as an artifact; at some point, I will strip it out.
1072 *
1073 * Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
1074 * because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
1075 * can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
1076 * more times faster in extreme cases.
1077 *
1078 * MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
1079 * can have patterns in your CID field as well.
1080 *
1081 * */
1082
1083
1084static 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)
1085{
1086 /* if this extension is marked as deleted, then skip this -- if it never shows
1087 on the scoreboard, it will never be found, nor will halt the traversal. */
1088 if (deleted)
1089 return;
1090 board->total_specificity = spec;
1091 board->total_length = length;
1092 board->exten = exten;
1093 board->last_char = last;
1094 board->node = node;
1095#ifdef NEED_DEBUG_HERE
1096 ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
1097#endif
1098}
1099
1100#ifdef NEED_DEBUG
1101static void log_match_char_tree(struct match_char *node, char *prefix)
1102{
1103 char extenstr[40];
1104 struct ast_str *my_prefix = ast_str_alloca(1024);
1105
1106 extenstr[0] = '\0';
1107
1108 if (node && node->exten)
1109 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1110
1111 if (strlen(node->x) > 1) {
1112 ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
1113 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
1114 node->exten ? node->exten->exten : "", extenstr);
1115 } else {
1116 ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
1117 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
1118 node->exten ? node->exten->exten : "", extenstr);
1119 }
1120
1121 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
1122
1123 if (node->next_char)
1124 log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
1125
1126 if (node->alt_char)
1127 log_match_char_tree(node->alt_char, prefix);
1128}
1129#endif
1130
1131static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
1132{
1133 char extenstr[40];
1134 struct ast_str *my_prefix = ast_str_alloca(1024);
1135
1136 extenstr[0] = '\0';
1137
1138 if (node->exten) {
1139 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1140 }
1141
1142 if (strlen(node->x) > 1) {
1143 ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1144 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1145 node->exten ? node->exten->name : "", extenstr);
1146 } else {
1147 ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1148 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1149 node->exten ? node->exten->name : "", extenstr);
1150 }
1151
1152 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
1153
1154 if (node->next_char)
1155 cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
1156
1157 if (node->alt_char)
1158 cli_match_char_tree(node->alt_char, prefix, fd);
1159}
1160
1162{
1163 /* find the exten at the end of the rope */
1164 struct match_char *node2 = node;
1165
1166 for (node2 = node; node2; node2 = node2->next_char) {
1167 if (node2->exten) {
1168#ifdef NEED_DEBUG_HERE
1169 ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
1170#endif
1171 return node2->exten;
1172 }
1173 }
1174#ifdef NEED_DEBUG_HERE
1175 ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
1176#endif
1177 return 0;
1178}
1179
1181{
1182 struct match_char *m3;
1183 struct match_char *m4;
1184 struct ast_exten *e3;
1185
1186 if (node && node->x[0] == '.' && !node->x[1]) { /* dot and ! will ALWAYS be next match in a matchmore */
1187 return node->exten;
1188 }
1189
1190 if (node && node->x[0] == '!' && !node->x[1]) {
1191 return node->exten;
1192 }
1193
1194 if (!node || !node->next_char) {
1195 return NULL;
1196 }
1197
1198 m3 = node->next_char;
1199
1200 if (m3->exten) {
1201 return m3->exten;
1202 }
1203 for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
1204 if (m4->exten) {
1205 return m4->exten;
1206 }
1207 }
1208 for (m4 = m3; m4; m4 = m4->alt_char) {
1209 e3 = trie_find_next_match(m3);
1210 if (e3) {
1211 return e3;
1212 }
1213 }
1214
1215 return NULL;
1216}
1217
1218#ifdef DEBUG_THIS
1219static char *action2str(enum ext_match_t action)
1220{
1221 switch (action) {
1222 case E_MATCH:
1223 return "MATCH";
1224 case E_CANMATCH:
1225 return "CANMATCH";
1226 case E_MATCHMORE:
1227 return "MATCHMORE";
1228 case E_FINDLABEL:
1229 return "FINDLABEL";
1230 case E_SPAWN:
1231 return "SPAWN";
1232 default:
1233 return "?ACTION?";
1234 }
1235}
1236
1237#endif
1238
1239static const char *candidate_exten_advance(const char *str)
1240{
1241 str++;
1242 while (*str == '-') {
1243 str++;
1244 }
1245 return str;
1246}
1247
1248#define MORE(s) (*candidate_exten_advance(s))
1249#define ADVANCE(s) candidate_exten_advance(s)
1250
1251static 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)
1252{
1253 struct match_char *p; /* note minimal stack storage requirements */
1254 struct ast_exten pattern = { .label = label };
1255#ifdef DEBUG_THIS
1256 if (tree)
1257 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
1258 else
1259 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
1260#endif
1261 for (p = tree; p; p = p->alt_char) {
1262 if (p->is_pattern) {
1263 if (p->x[0] == 'N') {
1264 if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
1265#define NEW_MATCHER_CHK_MATCH \
1266 if (p->exten && !MORE(str)) { /* if a shorter pattern matches along the way, might as well report it */ \
1267 if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */ \
1268 update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
1269 if (!p->deleted) { \
1270 if (action == E_FINDLABEL) { \
1271 if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
1272 ast_debug(4, "Found label in preferred extension\n"); \
1273 return; \
1274 } \
1275 } else { \
1276 ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->name); \
1277 return; /* the first match, by definition, will be the best, because of the sorted tree */ \
1278 } \
1279 } \
1280 } \
1281 }
1282
1283#define NEW_MATCHER_RECURSE \
1284 if (p->next_char && (MORE(str) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
1285 || p->next_char->x[0] == '!')) { \
1286 if (MORE(str) || p->next_char->x[0] == '!') { \
1287 new_find_extension(ADVANCE(str), score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
1288 if (score->exten) { \
1289 ast_debug(4 ,"returning an exact match-- %s\n", score->exten->name); \
1290 return; /* the first match is all we need */ \
1291 } \
1292 } else { \
1293 new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
1294 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
1295 ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->name : \
1296 "NULL"); \
1297 return; /* the first match is all we need */ \
1298 } \
1299 } \
1300 } else if ((p->next_char || action == E_CANMATCH) && !MORE(str)) { \
1301 score->canmatch = 1; \
1302 score->canmatch_exten = get_canmatch_exten(p); \
1303 if (action == E_CANMATCH || action == E_MATCHMORE) { \
1304 ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
1305 return; \
1306 } \
1307 }
1308
1311 }
1312 } else if (p->x[0] == 'Z') {
1313 if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
1316 }
1317 } else if (p->x[0] == 'X') {
1318 if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
1321 }
1322 } else if (p->x[0] == '.' && p->x[1] == 0) {
1323 /* how many chars will the . match against? */
1324 int i = 0;
1325 const char *str2 = str;
1326 while (*str2 && *str2 != '/') {
1327 str2++;
1328 i++;
1329 }
1330 if (p->exten && *str2 != '/') {
1331 update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
1332 if (score->exten) {
1333 ast_debug(4, "return because scoreboard has a match with '/'--- %s\n",
1334 score->exten->name);
1335 return; /* the first match is all we need */
1336 }
1337 }
1338 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1339 new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
1340 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1341 ast_debug(4, "return because scoreboard has exact match OR "
1342 "CANMATCH/MATCHMORE & canmatch set--- %s\n",
1343 score->exten ? score->exten->name : "NULL");
1344 return; /* the first match is all we need */
1345 }
1346 }
1347 } else if (p->x[0] == '!' && p->x[1] == 0) {
1348 /* how many chars will the . match against? */
1349 int i = 1;
1350 const char *str2 = str;
1351 while (*str2 && *str2 != '/') {
1352 str2++;
1353 i++;
1354 }
1355 if (p->exten && *str2 != '/') {
1356 update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
1357 if (score->exten) {
1358 ast_debug(4, "return because scoreboard has a '!' match--- %s\n",
1359 score->exten->name);
1360 return; /* the first match is all we need */
1361 }
1362 }
1363 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1364 new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
1365 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1366 ast_debug(4, "return because scoreboard has exact match OR "
1367 "CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n",
1368 score->exten ? score->exten->name : "NULL");
1369 return; /* the first match is all we need */
1370 }
1371 }
1372 } else if (p->x[0] == '/' && p->x[1] == 0) {
1373 /* the pattern in the tree includes the cid match! */
1374 if (p->next_char && callerid && *callerid) {
1375 new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
1376 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1377 ast_debug(4, "return because scoreboard has exact match OR "
1378 "CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n",
1379 score->exten ? score->exten->name : "NULL");
1380 return; /* the first match is all we need */
1381 }
1382 }
1383 } else if (strchr(p->x, *str)) {
1384 ast_debug(4, "Nothing strange about this match\n");
1387 }
1388 } else if (strchr(p->x, *str)) {
1389 ast_debug(4, "Nothing strange about this match\n");
1392 }
1393 }
1394 ast_debug(4, "return at end of func\n");
1395}
1396
1397#undef MORE
1398#undef ADVANCE
1399
1400/* the algorithm for forming the extension pattern tree is also a bit simple; you
1401 * traverse all the extensions in a context, and for each char of the extension,
1402 * you see if it exists in the tree; if it doesn't, you add it at the appropriate
1403 * spot. What more can I say? At the end of each exten, you cap it off by adding the
1404 * address of the extension involved. Duplicate patterns will be complained about.
1405 *
1406 * Ideally, this would be done for each context after it is created and fully
1407 * filled. It could be done as a finishing step after extensions.conf or .ael is
1408 * loaded, or it could be done when the first search is encountered. It should only
1409 * have to be done once, until the next unload or reload.
1410 *
1411 * I guess forming this pattern tree would be analogous to compiling a regex. Except
1412 * that a regex only handles 1 pattern, really. This trie holds any number
1413 * of patterns. Well, really, it **could** be considered a single pattern,
1414 * where the "|" (or) operator is allowed, I guess, in a way, sort of...
1415 */
1416
1417static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
1418{
1419 struct match_char *t;
1420
1421 if (!current) {
1422 return 0;
1423 }
1424
1425 for (t = current; t; t = t->alt_char) {
1426 if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
1427 return t;
1428 }
1429 }
1430
1431 return 0;
1432}
1433
1434/* The first arg is the location of the tree ptr, or the
1435 address of the next_char ptr in the node, so we can mess
1436 with it, if we need to insert at the beginning of the list */
1437
1438static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
1439{
1440 struct match_char *curr, *lcurr;
1441
1442 /* insert node into the tree at "current", so the alt_char list from current is
1443 sorted in increasing value as you go to the leaves */
1444 if (!(*parent_ptr)) {
1445 *parent_ptr = node;
1446 return;
1447 }
1448
1449 if ((*parent_ptr)->specificity > node->specificity) {
1450 /* insert at head */
1451 node->alt_char = (*parent_ptr);
1452 *parent_ptr = node;
1453 return;
1454 }
1455
1456 lcurr = *parent_ptr;
1457 for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
1458 if (curr->specificity > node->specificity) {
1459 node->alt_char = curr;
1460 lcurr->alt_char = node;
1461 break;
1462 }
1463 lcurr = curr;
1464 }
1465
1466 if (!curr) {
1467 lcurr->alt_char = node;
1468 }
1469
1470}
1471
1473 /*! Pattern node specificity */
1475 /*! Pattern node match characters. */
1476 char buf[256];
1477};
1478
1479static 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)
1480{
1481 struct match_char *m;
1482
1483 if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
1484 return NULL;
1485 }
1486
1487 /* strcpy is safe here since we know its size and have allocated
1488 * just enough space for when we allocated m
1489 */
1490 strcpy(m->x, pattern->buf);
1491
1492 /* the specificity scores are the same as used in the old
1493 pattern matcher. */
1495 if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
1496 m->specificity = 0x0832;
1497 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
1498 m->specificity = 0x0931;
1499 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
1500 m->specificity = 0x0a30;
1501 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
1502 m->specificity = 0x18000;
1503 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
1504 m->specificity = 0x28000;
1505 } else {
1506 m->specificity = pattern->specif;
1507 }
1508
1509 if (!con->pattern_tree) {
1511 } else {
1512 if (already) { /* switch to the new regime (traversing vs appending)*/
1513 insert_in_next_chars_alt_char_list(nextcharptr, m);
1514 } else {
1516 }
1517 }
1518
1519 return m;
1520}
1521
1522/*!
1523 * \internal
1524 * \brief Extract the next exten pattern node.
1525 *
1526 * \param node Pattern node to fill.
1527 * \param src Next source character to read.
1528 * \param pattern TRUE if the exten is a pattern.
1529 * \param extenbuf Original exten buffer to use in diagnostic messages.
1530 *
1531 * \retval Ptr to next extenbuf pos to read.
1532 */
1533static const char *get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
1534{
1535#define INC_DST_OVERFLOW_CHECK \
1536 do { \
1537 if (dst - node->buf < sizeof(node->buf) - 1) { \
1538 ++dst; \
1539 } else { \
1540 overflow = 1; \
1541 } \
1542 } while (0)
1543
1544 node->specif = 0;
1545 node->buf[0] = '\0';
1546 while (*src) {
1547 if (*src == '[' && pattern) {
1548 char *dst = node->buf;
1549 const char *src_next;
1550 int length;
1551 int overflow = 0;
1552
1553 /* get past the '[' */
1554 ++src;
1555 for (;;) {
1556 if (*src == '\\') {
1557 /* Escaped character. */
1558 ++src;
1559 if (*src == '[' || *src == '\\' || *src == '-' || *src == ']') {
1560 *dst = *src++;
1562 }
1563 } else if (*src == '-') {
1564 unsigned char first;
1565 unsigned char last;
1566
1567 src_next = src;
1568 first = *(src_next - 1);
1569 last = *++src_next;
1570
1571 if (last == '\\') {
1572 /* Escaped character. */
1573 last = *++src_next;
1574 }
1575
1576 /* Possible char range. */
1577 if (node->buf[0] && last) {
1578 /* Expand the char range. */
1579 while (++first <= last) {
1580 *dst = first;
1582 }
1583 src = src_next + 1;
1584 } else {
1585 /*
1586 * There was no left or right char for the range.
1587 * It is just a '-'.
1588 */
1589 *dst = *src++;
1591 }
1592 } else if (*src == '\0') {
1594 "A matching ']' was not found for '[' in exten pattern '%s'\n",
1595 extenbuf);
1596 break;
1597 } else if (*src == ']') {
1598 ++src;
1599 break;
1600 } else {
1601 *dst = *src++;
1603 }
1604 }
1605 /* null terminate the exploded range */
1606 *dst = '\0';
1607
1608 if (overflow) {
1610 "Expanded character set too large to deal with in exten pattern '%s'. Ignoring character set.\n",
1611 extenbuf);
1612 node->buf[0] = '\0';
1613 continue;
1614 }
1615
1616 /* Sort the characters in character set. */
1617 length = strlen(node->buf);
1618 if (!length) {
1619 ast_log(LOG_WARNING, "Empty character set in exten pattern '%s'. Ignoring.\n",
1620 extenbuf);
1621 node->buf[0] = '\0';
1622 continue;
1623 }
1624 qsort(node->buf, length, 1, compare_char);
1625
1626 /* Remove duplicate characters from character set. */
1627 dst = node->buf;
1628 src_next = node->buf;
1629 while (*src_next++) {
1630 if (*dst != *src_next) {
1631 *++dst = *src_next;
1632 }
1633 }
1634
1635 length = strlen(node->buf);
1636 length <<= 8;
1637 node->specif = length | (unsigned char) node->buf[0];
1638 break;
1639 } else if (*src == '-') {
1640 /* Skip dashes in all extensions. */
1641 ++src;
1642 } else {
1643 if (*src == '\\') {
1644 /*
1645 * XXX The escape character here does not remove any special
1646 * meaning to characters except the '[', '\\', and '-'
1647 * characters since they are special only in this function.
1648 */
1649 node->buf[0] = *++src;
1650 if (!node->buf[0]) {
1651 break;
1652 }
1653 } else {
1654 node->buf[0] = *src;
1655 if (pattern) {
1656 /* make sure n,x,z patterns are canonicalized to N,X,Z */
1657 if (node->buf[0] == 'n') {
1658 node->buf[0] = 'N';
1659 } else if (node->buf[0] == 'x') {
1660 node->buf[0] = 'X';
1661 } else if (node->buf[0] == 'z') {
1662 node->buf[0] = 'Z';
1663 }
1664 }
1665 }
1666 node->buf[1] = '\0';
1667 node->specif = 1;
1668 ++src;
1669 break;
1670 }
1671 }
1672 return src;
1673
1674#undef INC_DST_OVERFLOW_CHECK
1675}
1676
1677#define MAX_EXTENBUF_SIZE 512
1678static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
1679{
1680 struct match_char *m1 = NULL;
1681 struct match_char *m2 = NULL;
1682 struct match_char **m0;
1683 const char *pos;
1684 int already;
1685 int pattern = 0;
1686 int idx_cur;
1687 int idx_next;
1688 char extenbuf[MAX_EXTENBUF_SIZE];
1689 volatile size_t required_space = strlen(e1->exten) + 1;
1690 struct pattern_node pat_node[2];
1691
1692 if (e1->matchcid) {
1693 required_space += (strlen(e1->cidmatch) + 2 /* '/' + NULL */);
1694 if (required_space > MAX_EXTENBUF_SIZE) {
1696 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1697 e1->exten, e1->cidmatch);
1698 return NULL;
1699 }
1700 sprintf(extenbuf, "%s/%s", e1->exten, e1->cidmatch);/* Safe. We just checked. */
1701 } else {
1702 if (required_space > MAX_EXTENBUF_SIZE) {
1704 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
1705 e1->exten, e1->cidmatch);
1706 return NULL;
1707 }
1708 ast_copy_string(extenbuf, e1->exten, required_space);
1709 }
1710
1711#ifdef NEED_DEBUG
1712 ast_debug(1, "Adding exten %s to tree\n", extenbuf);
1713#endif
1714 m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
1715 m0 = &con->pattern_tree;
1716 already = 1;
1717
1718 pos = extenbuf;
1719 if (*pos == '_') {
1720 pattern = 1;
1721 ++pos;
1722 }
1723 idx_cur = 0;
1724 pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
1725 for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
1726 idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
1727 pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
1728
1729 /* See about adding node to tree. */
1730 m2 = NULL;
1731 if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].buf, pattern))
1732 && m2->next_char) {
1733 if (!pat_node[idx_next].buf[0]) {
1734 /*
1735 * This is the end of the pattern, but not the end of the tree.
1736 * Mark this node with the exten... a shorter pattern might win
1737 * if the longer one doesn't match.
1738 */
1739 if (findonly) {
1740 return m2;
1741 }
1742 if (m2->exten) {
1743 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
1744 m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
1745 }
1746 m2->exten = e1;
1747 m2->deleted = 0;
1748 }
1749 m1 = m2->next_char; /* m1 points to the node to compare against */
1750 m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
1751 } else { /* not already OR not m2 OR nor m2->next_char */
1752 if (m2) {
1753 if (findonly) {
1754 return m2;
1755 }
1756 m1 = m2; /* while m0 stays the same */
1757 } else {
1758 if (findonly) {
1759 return m1;
1760 }
1761 m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
1762 if (!m1) { /* m1 is the node just added */
1763 return NULL;
1764 }
1765 m0 = &m1->next_char;
1766 }
1767 if (!pat_node[idx_next].buf[0]) {
1768 if (m2 && m2->exten) {
1769 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
1770 m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
1771 }
1772 m1->deleted = 0;
1773 m1->exten = e1;
1774 }
1775
1776 /* The 'already' variable is a mini-optimization designed to make it so that we
1777 * don't have to call already_in_tree when we know it will return false.
1778 */
1779 already = 0;
1780 }
1781 }
1782 return m1;
1783}
1784
1785static void create_match_char_tree(struct ast_context *con)
1786{
1787 struct ast_hashtab_iter *t1;
1788 struct ast_exten *e1;
1789#ifdef NEED_DEBUG
1790 int biggest_bucket, resizes, numobjs, numbucks;
1791
1792 ast_debug(1, "Creating Extension Trie for context %s(%p)\n", con->name, con);
1793 ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
1794 ast_debug(1, "This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
1795 numobjs, numbucks, biggest_bucket, resizes);
1796#endif
1798 while ((e1 = ast_hashtab_next(t1))) {
1799 if (e1->exten) {
1800 add_exten_to_pattern_tree(con, e1, 0);
1801 } else {
1802 ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
1803 }
1804 }
1806}
1807
1808static 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! */
1809{
1810 /* destroy all the alternates */
1811 if (pattern_tree->alt_char) {
1812 destroy_pattern_tree(pattern_tree->alt_char);
1813 pattern_tree->alt_char = 0;
1814 }
1815 /* destroy all the nexts */
1816 if (pattern_tree->next_char) {
1817 destroy_pattern_tree(pattern_tree->next_char);
1818 pattern_tree->next_char = 0;
1819 }
1820 pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
1821 ast_free(pattern_tree);
1822}
1823
1824/*!
1825 * \internal
1826 * \brief Get the length of the exten string.
1827 *
1828 * \param str Exten to get length.
1829 *
1830 * \retval strlen of exten.
1831 */
1832static int ext_cmp_exten_strlen(const char *str)
1833{
1834 int len;
1835
1836 len = 0;
1837 for (;;) {
1838 /* Ignore '-' chars as eye candy fluff. */
1839 while (*str == '-') {
1840 ++str;
1841 }
1842 if (!*str) {
1843 break;
1844 }
1845 ++str;
1846 ++len;
1847 }
1848 return len;
1849}
1850
1851/*!
1852 * \internal
1853 * \brief Partial comparison of non-pattern extens.
1854 *
1855 * \param left Exten to compare.
1856 * \param right Exten to compare. Also matches if this string ends first.
1857 *
1858 * \retval <0 if left < right
1859 * \retval =0 if left == right
1860 * \retval >0 if left > right
1861 */
1862static int ext_cmp_exten_partial(const char *left, const char *right)
1863{
1864 int cmp;
1865
1866 for (;;) {
1867 /* Ignore '-' chars as eye candy fluff. */
1868 while (*left == '-') {
1869 ++left;
1870 }
1871 while (*right == '-') {
1872 ++right;
1873 }
1874
1875 if (!*right) {
1876 /*
1877 * Right ended first for partial match or both ended at the same
1878 * time for a match.
1879 */
1880 cmp = 0;
1881 break;
1882 }
1883
1884 cmp = *left - *right;
1885 if (cmp) {
1886 break;
1887 }
1888 ++left;
1889 ++right;
1890 }
1891 return cmp;
1892}
1893
1894/*!
1895 * \internal
1896 * \brief Comparison of non-pattern extens.
1897 *
1898 * \param left Exten to compare.
1899 * \param right Exten to compare.
1900 *
1901 * \retval <0 if left < right
1902 * \retval =0 if left == right
1903 * \retval >0 if left > right
1904 */
1905static int ext_cmp_exten(const char *left, const char *right)
1906{
1907 int cmp;
1908
1909 for (;;) {
1910 /* Ignore '-' chars as eye candy fluff. */
1911 while (*left == '-') {
1912 ++left;
1913 }
1914 while (*right == '-') {
1915 ++right;
1916 }
1917
1918 cmp = *left - *right;
1919 if (cmp) {
1920 break;
1921 }
1922 if (!*left) {
1923 /*
1924 * Get here only if both strings ended at the same time. cmp
1925 * would be non-zero if only one string ended.
1926 */
1927 break;
1928 }
1929 ++left;
1930 ++right;
1931 }
1932 return cmp;
1933}
1934
1935/*
1936 * Special characters used in patterns:
1937 * '_' underscore is the leading character of a pattern.
1938 * In other position it is treated as a regular char.
1939 * '-' The '-' is a separator and ignored. Why? So patterns like NXX-XXX-XXXX work.
1940 * . one or more of any character. Only allowed at the end of
1941 * a pattern.
1942 * ! zero or more of anything. Also impacts the result of CANMATCH
1943 * and MATCHMORE. Only allowed at the end of a pattern.
1944 * In the core routine, ! causes a match with a return code of 2.
1945 * In turn, depending on the search mode: (XXX check if it is implemented)
1946 * - E_MATCH returns 1 (does match)
1947 * - E_MATCHMORE returns 0 (no match)
1948 * - E_CANMATCH returns 1 (does match)
1949 *
1950 * / should not appear as it is considered the separator of the CID info.
1951 * XXX at the moment we may stop on this char.
1952 *
1953 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
1954 * [ denotes the start of a set of character. Everything inside
1955 * is considered literally. We can have ranges a-d and individual
1956 * characters. A '[' and '-' can be considered literally if they
1957 * are just before ']'.
1958 * XXX currently there is no way to specify ']' in a range, nor \ is
1959 * considered specially.
1960 *
1961 * When we compare a pattern with a specific extension, all characters in the extension
1962 * itself are considered literally.
1963 * XXX do we want to consider space as a separator as well ?
1964 * XXX do we want to consider the separators in non-patterns as well ?
1965 */
1966
1967/*!
1968 * \brief helper functions to sort extension patterns in the desired way,
1969 * so that more specific patterns appear first.
1970 *
1971 * \details
1972 * The function compares individual characters (or sets of), returning
1973 * an int where bits 0-7 are the ASCII code of the first char in the set,
1974 * bits 8-15 are the number of characters in the set, and bits 16-20 are
1975 * for special cases.
1976 * This way more specific patterns (smaller character sets) appear first.
1977 * Wildcards have a special value, so that we can directly compare them to
1978 * sets by subtracting the two values. In particular:
1979 * 0x001xx one character, character set starting with xx
1980 * 0x0yyxx yy characters, character set starting with xx
1981 * 0x18000 '.' (one or more of anything)
1982 * 0x28000 '!' (zero or more of anything)
1983 * 0x30000 NUL (end of string)
1984 * 0x40000 error in set.
1985 * The pointer to the string is advanced according to needs.
1986 * NOTES:
1987 * 1. the empty set is ignored.
1988 * 2. given that a full set has always 0 as the first element,
1989 * we could encode the special cases as 0xffXX where XX
1990 * is 1, 2, 3, 4 as used above.
1991 */
1992static int ext_cmp_pattern_pos(const char **p, unsigned char *bitwise)
1993{
1994#define BITS_PER 8 /* Number of bits per unit (byte). */
1995 unsigned char c;
1996 unsigned char cmin;
1997 int count;
1998 const char *end;
1999
2000 do {
2001 /* Get character and advance. (Ignore '-' chars as eye candy fluff.) */
2002 do {
2003 c = *(*p)++;
2004 } while (c == '-');
2005
2006 /* always return unless we have a set of chars */
2007 switch (c) {
2008 default:
2009 /* ordinary character */
2010 bitwise[c / BITS_PER] = 1 << ((BITS_PER - 1) - (c % BITS_PER));
2011 return 0x0100 | c;
2012
2013 case 'n':
2014 case 'N':
2015 /* 2..9 */
2016 bitwise[6] = 0x3f;
2017 bitwise[7] = 0xc0;
2018 return 0x0800 | '2';
2019
2020 case 'x':
2021 case 'X':
2022 /* 0..9 */
2023 bitwise[6] = 0xff;
2024 bitwise[7] = 0xc0;
2025 return 0x0A00 | '0';
2026
2027 case 'z':
2028 case 'Z':
2029 /* 1..9 */
2030 bitwise[6] = 0x7f;
2031 bitwise[7] = 0xc0;
2032 return 0x0900 | '1';
2033
2034 case '.':
2035 /* wildcard */
2036 return 0x18000;
2037
2038 case '!':
2039 /* earlymatch */
2040 return 0x28000; /* less specific than '.' */
2041
2042 case '\0':
2043 /* empty string */
2044 *p = NULL;
2045 return 0x30000;
2046
2047 case '[':
2048 /* char set */
2049 break;
2050 }
2051 /* locate end of set */
2052 end = strchr(*p, ']');
2053
2054 if (!end) {
2055 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2056 return 0x40000; /* XXX make this entry go last... */
2057 }
2058
2059 count = 0;
2060 cmin = 0xFF;
2061 for (; *p < end; ++*p) {
2062 unsigned char c1; /* first char in range */
2063 unsigned char c2; /* last char in range */
2064
2065 c1 = (*p)[0];
2066 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
2067 c2 = (*p)[2];
2068 *p += 2; /* skip a total of 3 chars */
2069 } else { /* individual character */
2070 c2 = c1;
2071 }
2072 if (c1 < cmin) {
2073 cmin = c1;
2074 }
2075 for (; c1 <= c2; ++c1) {
2076 unsigned char mask = 1 << ((BITS_PER - 1) - (c1 % BITS_PER));
2077
2078 /*
2079 * Note: If two character sets score the same, the one with the
2080 * lowest ASCII values will compare as coming first. Must fill
2081 * in most significant bits for lower ASCII values to accomplish
2082 * the desired sort order.
2083 */
2084 if (!(bitwise[c1 / BITS_PER] & mask)) {
2085 /* Add the character to the set. */
2086 bitwise[c1 / BITS_PER] |= mask;
2087 count += 0x100;
2088 }
2089 }
2090 }
2091 ++*p;
2092 } while (!count);/* While the char set was empty. */
2093 return count | cmin;
2094}
2095
2096/*!
2097 * \internal
2098 * \brief Comparison of exten patterns.
2099 *
2100 * \param left Pattern to compare.
2101 * \param right Pattern to compare.
2102 *
2103 * \retval <0 if left < right
2104 * \retval =0 if left == right
2105 * \retval >0 if left > right
2106 */
2107static int ext_cmp_pattern(const char *left, const char *right)
2108{
2109 int cmp;
2110 int left_pos;
2111 int right_pos;
2112
2113 for (;;) {
2114 unsigned char left_bitwise[32] = { 0, };
2115 unsigned char right_bitwise[32] = { 0, };
2116
2117 left_pos = ext_cmp_pattern_pos(&left, left_bitwise);
2118 right_pos = ext_cmp_pattern_pos(&right, right_bitwise);
2119 cmp = left_pos - right_pos;
2120 if (!cmp) {
2121 /*
2122 * Are the character sets different, even though they score the same?
2123 *
2124 * Note: Must swap left and right to get the sense of the
2125 * comparison correct. Otherwise, we would need to multiply by
2126 * -1 instead.
2127 */
2128 cmp = memcmp(right_bitwise, left_bitwise, ARRAY_LEN(left_bitwise));
2129 }
2130 if (cmp) {
2131 break;
2132 }
2133 if (!left) {
2134 /*
2135 * Get here only if both patterns ended at the same time. cmp
2136 * would be non-zero if only one pattern ended.
2137 */
2138 break;
2139 }
2140 }
2141 return cmp;
2142}
2143
2144/*!
2145 * \internal
2146 * \brief Comparison of dialplan extens for sorting purposes.
2147 *
2148 * \param left Exten/pattern to compare.
2149 * \param right Exten/pattern to compare.
2150 *
2151 * \retval <0 if left < right
2152 * \retval =0 if left == right
2153 * \retval >0 if left > right
2154 */
2155static int ext_cmp(const char *left, const char *right)
2156{
2157 /* Make sure non-pattern extens come first. */
2158 if (left[0] != '_') {
2159 if (right[0] == '_') {
2160 return -1;
2161 }
2162 /* Compare two non-pattern extens. */
2163 return ext_cmp_exten(left, right);
2164 }
2165 if (right[0] != '_') {
2166 return 1;
2167 }
2168
2169 /*
2170 * OK, we need full pattern sorting routine.
2171 *
2172 * Skip past the underscores
2173 */
2174 return ext_cmp_pattern(left + 1, right + 1);
2175}
2176
2177static int ext_fluff_count(const char *exten)
2178{
2179 int fluff = 0;
2180
2181 if (*exten != '_') {
2182 /* not a pattern, simple check. */
2183 while (*exten) {
2184 if (*exten == '-') {
2185 fluff++;
2186 }
2187 exten++;
2188 }
2189
2190 return fluff;
2191 }
2192
2193 /* do pattern check */
2194 while (*exten) {
2195 if (*exten == '-') {
2196 fluff++;
2197 } else if (*exten == '[') {
2198 /* skip set, dashes here matter. */
2199 exten = strchr(exten, ']');
2200
2201 if (!exten) {
2202 /* we'll end up warning about this later, don't spam logs */
2203 return fluff;
2204 }
2205 }
2206 exten++;
2207 }
2208
2209 return fluff;
2210}
2211
2212int ast_extension_cmp(const char *a, const char *b)
2213{
2214 int cmp;
2215
2216 cmp = ext_cmp(a, b);
2217 if (cmp < 0) {
2218 return -1;
2219 }
2220 if (cmp > 0) {
2221 return 1;
2222 }
2223 return 0;
2224}
2225
2226/*!
2227 * \internal
2228 * \brief used ast_extension_{match|close}
2229 * mode is as follows:
2230 * E_MATCH success only on exact match
2231 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
2232 * E_CANMATCH either of the above.
2233 * \retval 0 on no-match
2234 * \retval 1 on match
2235 * \retval 2 on early match.
2236 */
2237
2238static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2239{
2240 mode &= E_MATCH_MASK; /* only consider the relevant bits */
2241
2242#ifdef NEED_DEBUG_HERE
2243 ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
2244#endif
2245
2246 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
2247 int lp = ext_cmp_exten_strlen(pattern);
2248 int ld = ext_cmp_exten_strlen(data);
2249
2250 if (lp < ld) { /* pattern too short, cannot match */
2251#ifdef NEED_DEBUG_HERE
2252 ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
2253#endif
2254 return 0;
2255 }
2256 /* depending on the mode, accept full or partial match or both */
2257 if (mode == E_MATCH) {
2258#ifdef NEED_DEBUG_HERE
2259 ast_log(LOG_NOTICE,"return (!ext_cmp_exten(%s,%s) when mode== E_MATCH)\n", pattern, data);
2260#endif
2261 return !ext_cmp_exten(pattern, data); /* 1 on match, 0 on fail */
2262 }
2263 if (ld == 0 || !ext_cmp_exten_partial(pattern, data)) { /* partial or full match */
2264#ifdef NEED_DEBUG_HERE
2265 ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
2266#endif
2267 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
2268 } else {
2269#ifdef NEED_DEBUG_HERE
2270 ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
2271#endif
2272 return 0;
2273 }
2274 }
2275 if (mode == E_MATCH && data[0] == '_') {
2276 /*
2277 * XXX It is bad design that we don't know if we should be
2278 * comparing data and pattern as patterns or comparing data if
2279 * it conforms to pattern when the function is called. First,
2280 * assume they are both patterns. If they don't match then try
2281 * to see if data conforms to the given pattern.
2282 *
2283 * note: if this test is left out, then _x. will not match _x. !!!
2284 */
2285#ifdef NEED_DEBUG_HERE
2286 ast_log(LOG_NOTICE, "Comparing as patterns first. pattern:%s data:%s\n", pattern, data);
2287#endif
2288 if (!ext_cmp_pattern(pattern + 1, data + 1)) {
2289#ifdef NEED_DEBUG_HERE
2290 ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
2291#endif
2292 return 1;
2293 }
2294 }
2295
2296 ++pattern; /* skip leading _ */
2297 /*
2298 * XXX below we stop at '/' which is a separator for the CID info. However we should
2299 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
2300 */
2301 for (;;) {
2302 const char *end;
2303
2304 /* Ignore '-' chars as eye candy fluff. */
2305 while (*data == '-') {
2306 ++data;
2307 }
2308 while (*pattern == '-') {
2309 ++pattern;
2310 }
2311 if (!*data || !*pattern || *pattern == '/') {
2312 break;
2313 }
2314
2315 switch (*pattern) {
2316 case '[': /* a range */
2317 ++pattern;
2318 end = strchr(pattern, ']'); /* XXX should deal with escapes ? */
2319 if (!end) {
2320 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2321 return 0; /* unconditional failure */
2322 }
2323 if (pattern == end) {
2324 /* Ignore empty character sets. */
2325 ++pattern;
2326 continue;
2327 }
2328 for (; pattern < end; ++pattern) {
2329 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
2330 if (*data >= pattern[0] && *data <= pattern[2])
2331 break; /* match found */
2332 else {
2333 pattern += 2; /* skip a total of 3 chars */
2334 continue;
2335 }
2336 } else if (*data == pattern[0])
2337 break; /* match found */
2338 }
2339 if (pattern >= end) {
2340#ifdef NEED_DEBUG_HERE
2341 ast_log(LOG_NOTICE,"return (0) when pattern>=end\n");
2342#endif
2343 return 0;
2344 }
2345 pattern = end; /* skip and continue */
2346 break;
2347 case 'n':
2348 case 'N':
2349 if (*data < '2' || *data > '9') {
2350#ifdef NEED_DEBUG_HERE
2351 ast_log(LOG_NOTICE,"return (0) N is not matched\n");
2352#endif
2353 return 0;
2354 }
2355 break;
2356 case 'x':
2357 case 'X':
2358 if (*data < '0' || *data > '9') {
2359#ifdef NEED_DEBUG_HERE
2360 ast_log(LOG_NOTICE,"return (0) X is not matched\n");
2361#endif
2362 return 0;
2363 }
2364 break;
2365 case 'z':
2366 case 'Z':
2367 if (*data < '1' || *data > '9') {
2368#ifdef NEED_DEBUG_HERE
2369 ast_log(LOG_NOTICE,"return (0) Z is not matched\n");
2370#endif
2371 return 0;
2372 }
2373 break;
2374 case '.': /* Must match, even with more digits */
2375#ifdef NEED_DEBUG_HERE
2376 ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
2377#endif
2378 return 1;
2379 case '!': /* Early match */
2380#ifdef NEED_DEBUG_HERE
2381 ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
2382#endif
2383 return 2;
2384 default:
2385 if (*data != *pattern) {
2386#ifdef NEED_DEBUG_HERE
2387 ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
2388#endif
2389 return 0;
2390 }
2391 break;
2392 }
2393 ++data;
2394 ++pattern;
2395 }
2396 if (*data) /* data longer than pattern, no match */ {
2397#ifdef NEED_DEBUG_HERE
2398 ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
2399#endif
2400 return 0;
2401 }
2402
2403 /*
2404 * match so far, but ran off the end of data.
2405 * Depending on what is next, determine match or not.
2406 */
2407 if (*pattern == '\0' || *pattern == '/') { /* exact match */
2408#ifdef NEED_DEBUG_HERE
2409 ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
2410#endif
2411 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
2412 } else if (*pattern == '!') { /* early match */
2413#ifdef NEED_DEBUG_HERE
2414 ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
2415#endif
2416 return 2;
2417 } else { /* partial match */
2418#ifdef NEED_DEBUG_HERE
2419 ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
2420#endif
2421 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
2422 }
2423}
2424
2425/*
2426 * Wrapper around _extension_match_core() to do performance measurement
2427 * using the profiling code.
2428 */
2429static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2430{
2431 int i;
2432 static int prof_id = -2; /* marker for 'unallocated' id */
2433 if (prof_id == -2) {
2434 prof_id = ast_add_profile("ext_match", 0);
2435 }
2436 ast_mark(prof_id, 1);
2437 i = _extension_match_core(ast_strlen_zero(pattern) ? "" : pattern, ast_strlen_zero(data) ? "" : data, mode);
2438 ast_mark(prof_id, 0);
2439 return i;
2440}
2441
2442int ast_extension_match(const char *pattern, const char *extension)
2443{
2444 return extension_match_core(pattern, extension, E_MATCH);
2445}
2446
2447int ast_extension_close(const char *pattern, const char *data, int needmore)
2448{
2449 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
2450 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
2451 return extension_match_core(pattern, data, needmore);
2452}
2453
2455{
2456 struct ast_context *tmp;
2457 struct ast_context item = {
2458 .name = name,
2459 };
2460
2461 if (!name) {
2462 return NULL;
2463 }
2465 if (contexts_table) {
2467 } else {
2468 tmp = NULL;
2469 while ((tmp = ast_walk_contexts(tmp))) {
2470 if (!strcasecmp(name, tmp->name)) {
2471 break;
2472 }
2473 }
2474 }
2476 return tmp;
2477}
2478
2479#define STATUS_NO_CONTEXT 1
2480#define STATUS_NO_EXTENSION 2
2481#define STATUS_NO_PRIORITY 3
2482#define STATUS_NO_LABEL 4
2483#define STATUS_SUCCESS 5
2484
2485static int matchcid(const char *cidpattern, const char *callerid)
2486{
2487 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
2488 failing to get a number should count as a match, otherwise not */
2489
2490 if (ast_strlen_zero(callerid)) {
2491 return ast_strlen_zero(cidpattern) ? 1 : 0;
2492 }
2493
2494 return ast_extension_match(cidpattern, callerid);
2495}
2496
2498 struct ast_context *bypass, struct pbx_find_info *q,
2499 const char *context, const char *exten, int priority,
2500 const char *label, const char *callerid, enum ext_match_t action)
2501{
2502 int x, res;
2503 struct ast_context *tmp = NULL;
2504 struct ast_exten *e = NULL, *eroot = NULL;
2505 struct ast_exten pattern = {NULL, };
2506 struct scoreboard score = {0, };
2507 struct ast_str *tmpdata = NULL;
2508 int idx;
2509
2510 pattern.label = label;
2511 pattern.priority = priority;
2512#ifdef NEED_DEBUG_HERE
2513 ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
2514#endif
2515
2516 /* Initialize status if appropriate */
2517 if (q->stacklen == 0) {
2519 q->swo = NULL;
2520 q->data = NULL;
2521 q->foundcontext = NULL;
2522 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
2523 ast_log(LOG_WARNING, "Maximum PBX stack (%d) exceeded. Too many includes?\n", AST_PBX_MAX_STACK);
2524 return NULL;
2525 }
2526
2527 /* Check first to see if we've already been checked */
2528 for (x = 0; x < q->stacklen; x++) {
2529 if (!strcasecmp(q->incstack[x], context))
2530 return NULL;
2531 }
2532
2533 if (bypass) { /* bypass means we only look there */
2534 tmp = bypass;
2535 } else { /* look in contexts */
2536 tmp = find_context(context);
2537 if (!tmp) {
2538 return NULL;
2539 }
2540 }
2541
2542 if (q->status < STATUS_NO_EXTENSION)
2544
2545 /* Do a search for matching extension */
2546
2547 eroot = NULL;
2548 score.total_specificity = 0;
2549 score.exten = 0;
2550 score.total_length = 0;
2551 if (!tmp->pattern_tree && tmp->root_table) {
2553#ifdef NEED_DEBUG
2554 ast_debug(1, "Tree Created in context %s:\n", context);
2555 log_match_char_tree(tmp->pattern_tree," ");
2556#endif
2557 }
2558#ifdef NEED_DEBUG
2559 ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
2560 log_match_char_tree(tmp->pattern_tree, ":: ");
2561#endif
2562
2563 do {
2565 char *osw = ast_strdupa(overrideswitch), *name;
2566 struct ast_switch *asw;
2567 ast_switch_f *aswf = NULL;
2568 char *datap;
2569 int eval = 0;
2570
2571 name = strsep(&osw, "/");
2572 asw = pbx_findswitch(name);
2573
2574 if (!asw) {
2575 ast_log(LOG_WARNING, "No such switch '%s'\n", name);
2576 break;
2577 }
2578
2579 if (osw && strchr(osw, '$')) {
2580 eval = 1;
2581 }
2582
2583 if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2584 ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!\n");
2585 break;
2586 } else if (eval) {
2587 /* Substitute variables now */
2588 pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2589 datap = ast_str_buffer(tmpdata);
2590 } else {
2591 datap = osw;
2592 }
2593
2594 /* equivalent of extension_match_core() at the switch level */
2595 if (action == E_CANMATCH)
2596 aswf = asw->canmatch;
2597 else if (action == E_MATCHMORE)
2598 aswf = asw->matchmore;
2599 else /* action == E_MATCH */
2600 aswf = asw->exists;
2601 if (!aswf) {
2602 res = 0;
2603 } else {
2604 if (chan) {
2606 }
2607 res = aswf(chan, context, exten, priority, callerid, datap);
2608 if (chan) {
2610 }
2611 }
2612 if (res) { /* Got a match */
2613 q->swo = asw;
2614 q->data = datap;
2615 q->foundcontext = context;
2616 /* XXX keep status = STATUS_NO_CONTEXT ? */
2617 return NULL;
2618 }
2619 }
2620 } while (0);
2621
2623 new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
2624 eroot = score.exten;
2625
2626 if (score.last_char == '!' && action == E_MATCHMORE) {
2627 /* We match an extension ending in '!'.
2628 * The decision in this case is final and is NULL (no match).
2629 */
2630#ifdef NEED_DEBUG_HERE
2631 ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
2632#endif
2633 return NULL;
2634 }
2635
2636 if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
2638#ifdef NEED_DEBUG_HERE
2639 ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
2640#endif
2641 return score.canmatch_exten;
2642 }
2643
2644 if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
2645 if (score.node) {
2646 struct ast_exten *z = trie_find_next_match(score.node);
2647 if (z) {
2648#ifdef NEED_DEBUG_HERE
2649 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
2650#endif
2651 } else {
2652 if (score.canmatch_exten) {
2653#ifdef NEED_DEBUG_HERE
2654 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
2655#endif
2656 return score.canmatch_exten;
2657 } else {
2658#ifdef NEED_DEBUG_HERE
2659 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
2660#endif
2661 }
2662 }
2663 return z;
2664 }
2665#ifdef NEED_DEBUG_HERE
2666 ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
2667#endif
2668 return NULL; /* according to the code, complete matches are null matches in MATCHMORE mode */
2669 }
2670
2671 if (eroot) {
2672 /* found entry, now look for the right priority */
2673 if (q->status < STATUS_NO_PRIORITY)
2675 e = NULL;
2676 if (action == E_FINDLABEL && label ) {
2677 if (q->status < STATUS_NO_LABEL)
2679 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2680 } else {
2681 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2682 }
2683 if (e) { /* found a valid match */
2685 q->foundcontext = context;
2686#ifdef NEED_DEBUG_HERE
2687 ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
2688#endif
2689 return e;
2690 }
2691 }
2692 } else { /* the old/current default exten pattern match algorithm */
2693
2694 /* scan the list trying to match extension and CID */
2695 eroot = NULL;
2696 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
2697 int match = extension_match_core(eroot->exten, exten, action);
2698 /* 0 on fail, 1 on match, 2 on earlymatch */
2699
2700 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
2701 continue; /* keep trying */
2702 if (match == 2 && action == E_MATCHMORE) {
2703 /* We match an extension ending in '!'.
2704 * The decision in this case is final and is NULL (no match).
2705 */
2706 return NULL;
2707 }
2708 /* found entry, now look for the right priority */
2709 if (q->status < STATUS_NO_PRIORITY)
2711 e = NULL;
2712 if (action == E_FINDLABEL && label ) {
2713 if (q->status < STATUS_NO_LABEL)
2715 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2716 } else {
2717 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2718 }
2719 if (e) { /* found a valid match */
2721 q->foundcontext = context;
2722 return e;
2723 }
2724 }
2725 }
2726
2727 /* Check alternative switches */
2728 for (idx = 0; idx < ast_context_switches_count(tmp); idx++) {
2729 const struct ast_sw *sw = ast_context_switches_get(tmp, idx);
2731 ast_switch_f *aswf = NULL;
2732 const char *datap;
2733
2734 if (!asw) {
2735 ast_log(LOG_WARNING, "No such switch '%s'\n", ast_get_switch_name(sw));
2736 continue;
2737 }
2738
2739 /* Substitute variables now */
2740 if (ast_get_switch_eval(sw)) {
2741 if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2742 ast_log(LOG_WARNING, "Can't evaluate switch?!\n");
2743 continue;
2744 }
2746 ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2747 datap = ast_str_buffer(tmpdata);
2748 } else {
2749 datap = ast_get_switch_data(sw);
2750 }
2751
2752 /* equivalent of extension_match_core() at the switch level */
2753 if (action == E_CANMATCH)
2754 aswf = asw->canmatch;
2755 else if (action == E_MATCHMORE)
2756 aswf = asw->matchmore;
2757 else /* action == E_MATCH */
2758 aswf = asw->exists;
2759 if (!aswf)
2760 res = 0;
2761 else {
2762 if (chan)
2764 res = aswf(chan, context, exten, priority, callerid, datap);
2765 if (chan)
2767 }
2768 if (res) { /* Got a match */
2769 q->swo = asw;
2770 q->data = datap;
2771 q->foundcontext = context;
2772 /* XXX keep status = STATUS_NO_CONTEXT ? */
2773 return NULL;
2774 }
2775 }
2776 /* Technically we should be using tmp->name here, but if we used that we
2777 * would have to cast away the constness of the 'name' pointer and I do
2778 * not want to do that. */
2779 q->incstack[q->stacklen++] = tmp->data; /* Setup the stack */
2780 /* Now try any includes we have in this context */
2781 for (idx = 0; idx < ast_context_includes_count(tmp); idx++) {
2782 const struct ast_include *i = ast_context_includes_get(tmp, idx);
2783
2784 if (include_valid(i)) {
2785 if ((e = pbx_find_extension(chan, bypass, q, include_rname(i), exten, priority, label, callerid, action))) {
2786#ifdef NEED_DEBUG_HERE
2787 ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
2788#endif
2789 return e;
2790 }
2791 if (q->swo)
2792 return NULL;
2793 }
2794 }
2795 return NULL;
2796}
2797
2798static void exception_store_free(void *data)
2799{
2800 struct pbx_exception *exception = data;
2802 ast_free(exception);
2803}
2804
2806 .type = "EXCEPTION",
2807 .destroy = exception_store_free,
2808};
2809
2810/*!
2811 * \internal
2812 * \brief Set the PBX to execute the exception extension.
2813 *
2814 * \param chan Channel to raise the exception on.
2815 * \param reason Reason exception is raised.
2816 * \param priority Dialplan priority to set.
2817 *
2818 * \retval 0 on success.
2819 * \retval -1 on error.
2820 */
2821int raise_exception(struct ast_channel *chan, const char *reason, int priority)
2822{
2824 struct pbx_exception *exception = NULL;
2825
2826 if (!ds) {
2828 if (!ds)
2829 return -1;
2830 if (!(exception = ast_calloc_with_stringfields(1, struct pbx_exception, 128))) {
2832 return -1;
2833 }
2834 ds->data = exception;
2835 ast_channel_datastore_add(chan, ds);
2836 } else
2837 exception = ds->data;
2838
2839 ast_string_field_set(exception, reason, reason);
2841 ast_string_field_set(exception, exten, ast_channel_exten(chan));
2842 exception->priority = ast_channel_priority(chan);
2843 set_ext_pri(chan, "e", priority);
2844 return 0;
2845}
2846
2847static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
2848{
2850 struct pbx_exception *exception = NULL;
2851 if (!ds || !ds->data)
2852 return -1;
2853 exception = ds->data;
2854 if (!strcasecmp(data, "REASON"))
2855 ast_copy_string(buf, exception->reason, buflen);
2856 else if (!strcasecmp(data, "CONTEXT"))
2857 ast_copy_string(buf, exception->context, buflen);
2858 else if (!strncasecmp(data, "EXTEN", 5))
2859 ast_copy_string(buf, exception->exten, buflen);
2860 else if (!strcasecmp(data, "PRIORITY"))
2861 snprintf(buf, buflen, "%d", exception->priority);
2862 else
2863 return -1;
2864 return 0;
2865}
2866
2868 .name = "EXCEPTION",
2869 .read = acf_exception_read,
2870};
2871
2872/*!
2873 * \brief The return value depends on the action:
2874 *
2875 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
2876 * and return 0 on failure, -1 on match;
2877 * E_FINDLABEL maps the label to a priority, and returns
2878 * the priority on success, ... XXX
2879 * E_SPAWN, spawn an application,
2880 *
2881 * \retval 0 on success.
2882 * \retval -1 on failure.
2883 *
2884 * \note The channel is auto-serviced in this function, because doing an extension
2885 * match may block for a long time. For example, if the lookup has to use a network
2886 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
2887 * auto-service code will queue up any important signalling frames to be processed
2888 * after this is done.
2889 */
2890static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
2891 const char *context, const char *exten, int priority,
2892 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
2893{
2894 struct ast_exten *e;
2895 struct ast_app *app;
2896 char *substitute = NULL;
2897 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
2898 char passdata[EXT_DATA_SIZE];
2899 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
2900
2902
2903 if (!context) {
2904 context = con->name;
2905 }
2906
2907 if (found)
2908 *found = 0;
2909
2910 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
2911 if (e) {
2912 if (found)
2913 *found = 1;
2914 if (matching_action) {
2916 return -1; /* success, we found it */
2917 } else if (action == E_FINDLABEL) { /* map the label to a priority */
2918 int res = e->priority;
2919
2921
2922 /* the priority we were looking for */
2923 return res;
2924 } else { /* spawn */
2925 if (!e->cached_app)
2926 e->cached_app = pbx_findapp(e->app);
2927 app = e->cached_app;
2928 if (ast_strlen_zero(e->data)) {
2929 *passdata = '\0';
2930 } else {
2931 const char *tmp;
2932 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
2933 /* no variables to substitute, copy on through */
2934 ast_copy_string(passdata, e->data, sizeof(passdata));
2935 } else {
2936 /* save e->data on stack for later processing after lock released */
2937 substitute = ast_strdupa(e->data);
2938 }
2939 }
2941 if (!app) {
2942 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
2943 return -1;
2944 }
2948 return 0;
2949 }
2952 if (ast_channel_exten(c) != exten)
2953 ast_channel_exten_set(c, exten);
2956 if (substitute) {
2957 pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
2958 }
2959 ast_debug(1, "Launching '%s'\n", app_name(app));
2960 if (VERBOSITY_ATLEAST(3)) {
2961 ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
2962 exten, context, priority,
2965 COLORIZE(COLOR_BRMAGENTA, 0, passdata),
2966 "in new stack");
2967 }
2968 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
2969 }
2970 } else if (q.swo) { /* not found here, but in another switch */
2971 if (found)
2972 *found = 1;
2974 if (matching_action) {
2975 return -1;
2976 } else {
2977 if (!q.swo->exec) {
2978 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
2979 return -1;
2980 }
2981 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
2982 }
2983 } else { /* not found anywhere, see what happened */
2985 /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
2986 switch (q.status) {
2987 case STATUS_NO_CONTEXT:
2988 if (!matching_action && !combined_find_spawn)
2989 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
2990 break;
2992 if (!matching_action && !combined_find_spawn)
2993 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
2994 break;
2995 case STATUS_NO_PRIORITY:
2996 if (!matching_action && !combined_find_spawn)
2997 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
2998 break;
2999 case STATUS_NO_LABEL:
3000 if (context && !combined_find_spawn)
3001 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", S_OR(label, ""), exten, S_OR(context, ""));
3002 break;
3003 default:
3004 ast_debug(1, "Shouldn't happen!\n");
3005 }
3006
3007 return (matching_action) ? 0 : -1;
3008 }
3009}
3010
3011/*! \brief Find hint for given extension in context */
3012static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
3013{
3014 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
3015 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
3016}
3017
3018static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
3019{
3020 struct ast_exten *e;
3024 return e;
3025}
3026
3028{
3029 switch (devstate) {
3030 case AST_DEVICE_ONHOLD:
3031 return AST_EXTENSION_ONHOLD;
3032 case AST_DEVICE_BUSY:
3033 return AST_EXTENSION_BUSY;
3034 case AST_DEVICE_UNKNOWN:
3037 case AST_DEVICE_INVALID:
3041 case AST_DEVICE_RINGING:
3042 return AST_EXTENSION_RINGING;
3043 case AST_DEVICE_INUSE:
3044 return AST_EXTENSION_INUSE;
3047 case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
3048 break;
3049 }
3050
3052}
3053
3054/*!
3055 * \internal
3056 * \brief Parse out the presence portion of the hint string
3057 */
3058static char *parse_hint_presence(struct ast_str *hint_args)
3059{
3060 char *copy = ast_strdupa(ast_str_buffer(hint_args));
3061 char *tmp = "";
3062
3063 if ((tmp = strrchr(copy, ','))) {
3064 *tmp = '\0';
3065 tmp++;
3066 } else {
3067 return NULL;
3068 }
3069 ast_str_set(&hint_args, 0, "%s", tmp);
3070 return ast_str_buffer(hint_args);
3071}
3072
3073/*!
3074 * \internal
3075 * \brief Parse out the device portion of the hint string
3076 */
3077static char *parse_hint_device(struct ast_str *hint_args)
3078{
3079 char *copy = ast_strdupa(ast_str_buffer(hint_args));
3080 char *tmp;
3081
3082 if ((tmp = strrchr(copy, ','))) {
3083 *tmp = '\0';
3084 }
3085
3086 ast_str_set(&hint_args, 0, "%s", copy);
3087 return ast_str_buffer(hint_args);
3088}
3089
3090static void device_state_info_dt(void *obj)
3091{
3092 struct ast_device_state_info *info = obj;
3093
3094 ao2_cleanup(info->causing_channel);
3095}
3096
3098{
3100}
3101
3102static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
3103{
3104 char *cur;
3105 char *rest;
3106 struct ast_devstate_aggregate agg;
3107
3108 /* One or more devices separated with a & character */
3109 rest = parse_hint_device(hint_app);
3110
3112 while ((cur = strsep(&rest, "&"))) {
3114
3116 if (device_state_info) {
3117 struct ast_device_state_info *obj;
3118
3119 obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
3120 /* if failed we cannot add this device */
3121 if (obj) {
3122 obj->device_state = state;
3123 strcpy(obj->device_name, cur);
3124 ao2_link(device_state_info, obj);
3125 ao2_ref(obj, -1);
3126 }
3127 }
3128 }
3129
3131}
3132
3133/*! \brief Check state of extension by using hints */
3134static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
3135{
3136 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
3137
3138 if (!e || !hint_app) {
3139 return -1;
3140 }
3141
3142 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
3143 return ast_extension_state3(hint_app, device_state_info);
3144}
3145
3146/*! \brief Return extension_state as string */
3147const char *ast_extension_state2str(int extension_state)
3148{
3149 int i;
3150
3151 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
3152 if (extension_states[i].extension_state == extension_state)
3153 return extension_states[i].text;
3154 }
3155 return "Unknown";
3156}
3157
3158/*!
3159 * \internal
3160 * \brief Check extension state for an extension by using hint
3161 */
3162static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
3163 struct ao2_container *device_state_info)
3164{
3165 struct ast_exten *e;
3166
3167 if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
3168 return -1; /* No hint, return -1 */
3169 }
3170
3171 if (e->exten[0] == '_') {
3172 /* Create this hint on-the-fly, we explicitly lock hints here to ensure the
3173 * same locking order as if this were done through configuration file - that is
3174 * hints is locked first and then (if needed) contexts is locked
3175 */
3176 ao2_lock(hints);
3178 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3179 e->registrar);
3181 if (!(e = ast_hint_extension(c, context, exten))) {
3182 /* Improbable, but not impossible */
3183 return -1;
3184 }
3185 }
3186
3187 return ast_extension_state2(e, device_state_info); /* Check all devices in the hint */
3188}
3189
3190/*! \brief Check extension state for an extension by using hint */
3191int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
3192{
3194}
3195
3196/*! \brief Check extended extension state for an extension by using hint */
3197int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
3198 struct ao2_container **device_state_info)
3199{
3200 struct ao2_container *container = NULL;
3201 int ret;
3202
3203 if (device_state_info) {
3205 }
3206
3208 if (ret < 0 && container) {
3209 ao2_ref(container, -1);
3210 container = NULL;
3211 }
3212
3213 if (device_state_info) {
3215 *device_state_info = container;
3216 }
3217
3218 return ret;
3219}
3220
3221static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
3222{
3223 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
3224 char *presence_provider;
3225 const char *app;
3226
3227 if (!e || !hint_app) {
3228 return -1;
3229 }
3230
3232 if (ast_strlen_zero(app)) {
3233 return -1;
3234 }
3235
3236 ast_str_set(&hint_app, 0, "%s", app);
3237 presence_provider = parse_hint_presence(hint_app);
3238
3239 if (ast_strlen_zero(presence_provider)) {
3240 /* No presence string in the hint */
3241 return 0;
3242 }
3243
3244 return ast_presence_state(presence_provider, subtype, message);
3245}
3246
3247int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
3248{
3249 struct ast_exten *e;
3250
3251 if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
3252 return -1; /* No hint, return -1 */
3253 }
3254
3255 if (e->exten[0] == '_') {
3256 /* Create this hint on-the-fly */
3257 ao2_lock(hints);
3259 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3260 e->registrar);
3262 if (!(e = ast_hint_extension(c, context, exten))) {
3263 /* Improbable, but not impossible */
3264 return -1;
3265 }
3266 }
3267
3268 return extension_presence_state_helper(e, subtype, message);
3269}
3270
3272 const char *context,
3273 const char *exten,
3274 void *data,
3275 enum ast_state_cb_update_reason reason,
3276 struct ast_hint *hint,
3277 struct ao2_container *device_state_info)
3278{
3279 int res = 0;
3280 struct ast_state_cb_info info = { 0, };
3281
3282 info.reason = reason;
3283
3284 /* Copy over current hint data */
3285 if (hint) {
3286 ao2_lock(hint);
3287 info.exten_state = hint->laststate;
3288 info.device_state_info = device_state_info;
3289 info.presence_state = hint->last_presence_state;
3290 if (!(ast_strlen_zero(hint->last_presence_subtype))) {
3291 info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
3292 } else {
3293 info.presence_subtype = "";
3294 }
3295 if (!(ast_strlen_zero(hint->last_presence_message))) {
3296 info.presence_message = ast_strdupa(hint->last_presence_message);
3297 } else {
3298 info.presence_message = "";
3299 }
3300 ao2_unlock(hint);
3301 } else {
3302 info.exten_state = AST_EXTENSION_REMOVED;
3303 }
3304
3305 res = cb(context, exten, &info, data);
3306
3307 return res;
3308}
3309
3310/*!
3311 * \internal
3312 * \brief Identify a channel for every device which is supposedly responsible for the device state.
3313 *
3314 * Especially when the device is ringing, the oldest ringing channel is chosen.
3315 * For all other cases the first encountered channel in the specific state is chosen.
3316 */
3318{
3319 struct ao2_iterator iter;
3321 struct ast_channel *chan;
3322
3323 if (!c || !ao2_container_count(c)) {
3324 return;
3325 }
3326 iter = ao2_iterator_init(c, 0);
3327 for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
3328 enum ast_channel_state search_state = 0; /* prevent false uninit warning */
3329 char match[AST_CHANNEL_NAME];
3330 struct ast_channel_iterator *chan_iter;
3331 struct timeval chantime = {0, }; /* prevent false uninit warning */
3332
3333 switch (info->device_state) {
3334 case AST_DEVICE_RINGING:
3336 /* find ringing channel */
3337 search_state = AST_STATE_RINGING;
3338 break;
3339 case AST_DEVICE_BUSY:
3340 /* find busy channel */
3341 search_state = AST_STATE_BUSY;
3342 break;
3343 case AST_DEVICE_ONHOLD:
3344 case AST_DEVICE_INUSE:
3345 /* find up channel */
3346 search_state = AST_STATE_UP;
3347 break;
3348 case AST_DEVICE_UNKNOWN:
3350 case AST_DEVICE_INVALID:
3352 case AST_DEVICE_TOTAL /* not a state */:
3353 /* no channels are of interest */
3354 continue;
3355 }
3356
3357 /* iterate over all channels of the device */
3358 snprintf(match, sizeof(match), "%s-", info->device_name);
3359 chan_iter = ast_channel_iterator_by_name_new(match, strlen(match));
3360 for (; (chan = ast_channel_iterator_next(chan_iter)); ast_channel_unref(chan)) {
3361 ast_channel_lock(chan);
3362 /* this channel's state doesn't match */
3363 if (search_state != ast_channel_state(chan)) {
3364 ast_channel_unlock(chan);
3365 continue;
3366 }
3367 /* any non-ringing channel will fit */
3368 if (search_state != AST_STATE_RINGING) {
3369 ast_channel_unlock(chan);
3370 info->causing_channel = chan; /* is kept ref'd! */
3371 break;
3372 }
3373 /* but we need the oldest ringing channel of the device to match with undirected pickup */
3374 if (!info->causing_channel) {
3375 chantime = ast_channel_creationtime(chan);
3376 ast_channel_ref(chan); /* must ref it! */
3377 info->causing_channel = chan;
3378 } else if (ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
3379 chantime = ast_channel_creationtime(chan);
3380 ast_channel_unref(info->causing_channel);
3381 ast_channel_ref(chan); /* must ref it! */
3382 info->causing_channel = chan;
3383 }
3384 ast_channel_unlock(chan);
3385 }
3387 }
3388 ao2_iterator_destroy(&iter);
3389}
3390
3391static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app)
3392{
3393 struct ao2_iterator cb_iter;
3394 struct ast_state_cb *state_cb;
3395 int state;
3396 int same_state;
3397 struct ao2_container *device_state_info;
3398 int first_extended_cb_call = 1;
3401
3402 ao2_lock(hint);
3403 if (!hint->exten) {
3404 /* The extension has already been destroyed */
3405 ao2_unlock(hint);
3406 return;
3407 }
3408
3409 /*
3410 * Save off strings in case the hint extension gets destroyed
3411 * while we are notifying the watchers.
3412 */
3415 sizeof(context_name));
3417 sizeof(exten_name));
3418 ast_str_set(hint_app, 0, "%s", ast_get_extension_app(hint->exten));
3419 ao2_unlock(hint);
3420
3421 /*
3422 * Get device state for this hint.
3423 *
3424 * NOTE: We cannot hold any locks while determining the hint
3425 * device state or notifying the watchers without causing a
3426 * deadlock. (conlock, hints, and hint)
3427 */
3428
3429 /* Make a container so state3 can fill it if we wish.
3430 * If that failed we simply do not provide the extended state info.
3431 */
3432 device_state_info = alloc_device_state_info();
3433
3434 state = ast_extension_state3(*hint_app, device_state_info);
3435 same_state = state == hint->laststate;
3436 if (same_state && (~state & AST_EXTENSION_RINGING)) {
3437 ao2_cleanup(device_state_info);
3438 return;
3439 }
3440
3441 /* Device state changed since last check - notify the watchers. */
3442 hint->laststate = state; /* record we saw the change */
3443
3444 /* For general callbacks */
3445 if (!same_state) {
3446 cb_iter = ao2_iterator_init(statecbs, 0);
3447 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3450 exten_name,
3451 state_cb->data,
3453 hint,
3454 NULL);
3455 }
3456 ao2_iterator_destroy(&cb_iter);
3457 }
3458
3459 /* For extension callbacks */
3460 /* extended callbacks are called when the state changed or when AST_STATE_RINGING is
3461 * included. Normal callbacks are only called when the state changed.
3462 */
3463 cb_iter = ao2_iterator_init(hint->callbacks, 0);
3464 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3465 if (state_cb->extended && first_extended_cb_call) {
3466 /* Fill detailed device_state_info now that we know it is used by extd. callback */
3467 first_extended_cb_call = 0;
3468 get_device_state_causing_channels(device_state_info);
3469 }
3470 if (state_cb->extended || !same_state) {
3473 exten_name,
3474 state_cb->data,
3476 hint,
3477 state_cb->extended ? device_state_info : NULL);
3478 }
3479 }
3480 ao2_iterator_destroy(&cb_iter);
3481
3482 ao2_cleanup(device_state_info);
3483}
3484
3485static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app,
3486 struct ast_presence_state_message *presence_state)
3487{
3488 struct ao2_iterator cb_iter;
3489 struct ast_state_cb *state_cb;
3492
3493 ao2_lock(hint);
3494 if (!hint->exten) {
3495 /* The extension has already been destroyed */
3496 ao2_unlock(hint);
3497 return;
3498 }
3499
3500 /*
3501 * Save off strings in case the hint extension gets destroyed
3502 * while we are notifying the watchers.
3503 */
3506 sizeof(context_name));
3508 sizeof(exten_name));
3509 ast_str_set(hint_app, 0, "%s", ast_get_extension_app(hint->exten));
3510 ao2_unlock(hint);
3511
3512 /* Check to see if update is necessary */
3513 if ((hint->last_presence_state == presence_state->state) &&
3514 ((hint->last_presence_subtype && presence_state->subtype &&
3515 !strcmp(hint->last_presence_subtype, presence_state->subtype)) ||
3516 (!hint->last_presence_subtype && !presence_state->subtype)) &&
3517 ((hint->last_presence_message && presence_state->message &&
3518 !strcmp(hint->last_presence_message, presence_state->message)) ||
3519 (!hint->last_presence_message && !presence_state->message))) {
3520 /* this update is the same as the last, do nothing */
3521 return;
3522 }
3523
3524 /* update new values */
3527 hint->last_presence_state = presence_state->state;
3528 hint->last_presence_subtype = presence_state->subtype ? ast_strdup(presence_state->subtype) : NULL;
3529 hint->last_presence_message = presence_state->message ? ast_strdup(presence_state->message) : NULL;
3530
3531 /* For general callbacks */
3532 cb_iter = ao2_iterator_init(statecbs, 0);
3533 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3536 exten_name,
3537 state_cb->data,
3539 hint,
3540 NULL);
3541 }
3542 ao2_iterator_destroy(&cb_iter);
3543
3544 /* For extension callbacks */
3545 cb_iter = ao2_iterator_init(hint->callbacks, 0);
3546 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
3549 exten_name,
3550 state_cb->data,
3552 hint,
3553 NULL);
3554 }
3555 ao2_iterator_destroy(&cb_iter);
3556}
3557
3559{
3560 struct ast_hint *hint;
3561 struct ast_str *hint_app;
3562
3563 if (hint_change_message_type() != stasis_message_type(msg)) {
3564 return 0;
3565 }
3566
3567 if (!(hint_app = ast_str_create(1024))) {
3568 return -1;
3569 }
3570
3571 hint = stasis_message_data(msg);
3572
3573 switch (reason) {
3575 device_state_notify_callbacks(hint, &hint_app);
3576 break;
3578 {
3579 char *presence_subtype = NULL;
3580 char *presence_message = NULL;
3581 int state;
3582
3584 hint->exten, &presence_subtype, &presence_message);
3585 {
3586 struct ast_presence_state_message presence_state = {
3588 .subtype = presence_subtype,
3589 .message = presence_message
3590 };
3591
3592 presence_state_notify_callbacks(hint, &hint_app, &presence_state);
3593 }
3594
3595 ast_free(presence_subtype);
3596 ast_free(presence_message);
3597 }
3598 break;
3599 }
3600
3601 ast_free(hint_app);
3602 return 1;
3603}
3604
3605static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
3606{
3607 struct ast_device_state_message *dev_state;
3608 struct ast_str *hint_app;
3609 struct ast_hintdevice *device;
3610 struct ast_hintdevice *cmpdevice;
3611 struct ao2_iterator *dev_iter;
3612 struct ao2_iterator auto_iter;
3613 struct ast_autohint *autohint;
3614 char *virtual_device;
3615 char *type;
3616 char *device_name;
3617
3619 return;
3620 }
3621
3622 if (hint_remove_message_type() == stasis_message_type(msg)) {
3623 /* The extension has already been destroyed */
3624 struct ast_state_cb *state_cb;
3625 struct ao2_iterator cb_iter;
3626 struct ast_hint *hint = stasis_message_data(msg);
3627
3628 ao2_lock(hint);
3630 ao2_unlock(hint);
3631
3632 cb_iter = ao2_iterator_init(hint->callbacks, 0);
3633 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3635 hint->context_name,
3636 hint->exten_name,
3637 state_cb->data,
3639 hint,
3640 NULL);
3641 }
3642 ao2_iterator_destroy(&cb_iter);
3643 return;
3644 }
3645
3647 return;
3648 }
3649
3650 dev_state = stasis_message_data(msg);
3651 if (dev_state->eid) {
3652 /* ignore non-aggregate states */
3653 return;
3654 }
3655
3657 /* There are no hints monitoring devices. */
3658 return;
3659 }
3660
3661 hint_app = ast_str_create(1024);
3662 if (!hint_app) {
3663 return;
3664 }
3665
3666 cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(dev_state->device));
3667 strcpy(cmpdevice->hintdevice, dev_state->device);
3668
3669 ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
3670
3671 /* Initially we find all hints for the device and notify them */
3672 dev_iter = ao2_t_callback(hintdevices,
3675 cmpdevice,
3676 "find devices in container");
3677 if (dev_iter) {
3678 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
3679 if (device->hint) {
3680 device_state_notify_callbacks(device->hint, &hint_app);
3681 }
3682 }
3683 ao2_iterator_destroy(dev_iter);
3684 }
3685
3686 /* Second stage we look for any autohint contexts and if the device is not already in the hints
3687 * we create it.
3688 */
3689 type = ast_strdupa(dev_state->device);
3690 if (ast_strlen_zero(type)) {
3691 goto end;
3692 }
3693
3694 /* Determine if this is a virtual/custom device or a real device */
3695 virtual_device = strchr(type, ':');
3696 device_name = strchr(type, '/');
3697 if (virtual_device && (!device_name || (virtual_device < device_name))) {
3698 device_name = virtual_device;
3699 }
3700
3701 /* Invalid device state name - not a virtual/custom device and not a real device */
3702 if (ast_strlen_zero(device_name)) {
3703 goto end;
3704 }
3705
3706 *device_name++ = '\0';
3707
3708 auto_iter = ao2_iterator_init(autohints, 0);
3709 for (; (autohint = ao2_iterator_next(&auto_iter)); ao2_t_ref(autohint, -1, "Next autohint")) {
3710 if (ast_get_hint(NULL, 0, NULL, 0, NULL, autohint->context, device_name)) {
3711 continue;
3712 }
3713
3714 /* The device has no hint in the context referenced by this autohint so create one */
3715 ast_add_extension(autohint->context, 0, device_name,
3716 PRIORITY_HINT, NULL, NULL, dev_state->device,
3717 ast_strdup(dev_state->device), ast_free_ptr, autohint->registrar);
3718
3719 /* Since this hint was just created there are no watchers, so we don't need to notify anyone */
3720 }
3721 ao2_iterator_destroy(&auto_iter);
3722
3723end:
3725 ast_free(hint_app);
3726 return;
3727}
3728
3729/*!
3730 * \internal
3731 * \brief Destroy the given state callback object.
3732 *
3733 * \param doomed State callback to destroy.
3734 */
3735static void destroy_state_cb(void *doomed)
3736{
3737 struct ast_state_cb *state_cb = doomed;
3738
3739 if (state_cb->destroy_cb) {
3740 state_cb->destroy_cb(state_cb->id, state_cb->data);
3741 }
3742}
3743
3744/*!
3745 * \internal
3746 * \brief Add watcher for extension states with destructor
3747 */
3748static int extension_state_add_destroy(const char *context, const char *exten,
3750{
3751 struct ast_hint *hint;
3752 struct ast_state_cb *state_cb;
3753 struct ast_exten *e;
3754 int id;
3755
3756 /* If there's no context and extension: add callback to statecbs list */
3757 if (!context && !exten) {
3758 /* Prevent multiple adds from adding the same change_cb at the same time. */
3760
3761 /* Remove any existing change_cb. */
3762 ao2_find(statecbs, change_cb, OBJ_UNLINK | OBJ_NODATA);
3763
3764 /* Now insert the change_cb */
3765 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
3767 return -1;
3768 }
3769 state_cb->id = 0;
3770 state_cb->change_cb = change_cb;
3771 state_cb->destroy_cb = destroy_cb;
3772 state_cb->data = data;
3773 state_cb->extended = extended;
3774 ao2_link(statecbs, state_cb);
3775
3776 ao2_ref(state_cb, -1);
3778 return 0;
3779 }
3780
3781 if (!context || !exten)
3782 return -1;
3783
3784 /* This callback type is for only one hint, so get the hint */
3786 if (!e) {
3787 return -1;
3788 }
3789
3790 /* If this is a pattern, dynamically create a new extension for this
3791 * particular match. Note that this will only happen once for each
3792 * individual extension, because the pattern will no longer match first.
3793 */
3794 if (e->exten[0] == '_') {
3795 ao2_lock(hints);
3797 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3798 e->registrar);
3801 if (!e || e->exten[0] == '_') {
3802 return -1;
3803 }
3804 }
3805
3806 /* Find the hint in the hints container */
3807 ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
3808 hint = ao2_find(hints, e, 0);
3809 if (!hint) {
3811 return -1;
3812 }
3813
3814 /* Now insert the callback in the callback list */
3815 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
3816 ao2_ref(hint, -1);
3818 return -1;
3819 }
3820 do {
3821 id = stateid++; /* Unique ID for this callback */
3822 /* Do not allow id to ever be -1 or 0. */
3823 } while (id == -1 || id == 0);
3824 state_cb->id = id;
3825 state_cb->change_cb = change_cb; /* Pointer to callback routine */
3826 state_cb->destroy_cb = destroy_cb;
3827 state_cb->data = data; /* Data for the callback */
3828 state_cb->extended = extended;
3829 ao2_link(hint->callbacks, state_cb);
3830
3831 ao2_ref(state_cb, -1);
3832 ao2_ref(hint, -1);
3834
3835 return id;
3836}
3837
3838int ast_extension_state_add_destroy(const char *context, const char *exten,
3839 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
3840{
3841 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
3842}
3843
3844int ast_extension_state_add(const char *context, const char *exten,
3845 ast_state_cb_type change_cb, void *data)
3846{
3847 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
3848}
3849
3851 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
3852{
3853 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
3854}
3855
3857 ast_state_cb_type change_cb, void *data)
3858{
3859 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
3860}
3861
3862/*! \brief Find Hint by callback id */
3863static int find_hint_by_cb_id(void *obj, void *arg, int flags)
3864{
3865 struct ast_state_cb *state_cb;
3866 const struct ast_hint *hint = obj;
3867 int *id = arg;
3868
3869 if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
3870 ao2_ref(state_cb, -1);
3871 return CMP_MATCH | CMP_STOP;
3872 }
3873
3874 return 0;
3875}
3876
3878{
3879 struct ast_state_cb *p_cur;
3880 int ret = -1;
3881
3882 if (!id) { /* id == 0 is a callback without extension */
3883 if (!change_cb) {
3884 return ret;
3885 }
3887 if (p_cur) {
3888 ret = 0;
3889 ao2_ref(p_cur, -1);
3890 }
3891 } else { /* callback with extension, find the callback based on ID */
3892 struct ast_hint *hint;
3893
3894 ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
3895 hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
3896 if (hint) {
3897 p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
3898 if (p_cur) {
3899 ret = 0;
3900 ao2_ref(p_cur, -1);
3901 }
3902 ao2_ref(hint, -1);
3903 }
3905 }
3906
3907 return ret;
3908}
3909
3910static int hint_id_cmp(void *obj, void *arg, int flags)
3911{
3912 const struct ast_state_cb *cb = obj;
3913 int *id = arg;
3914
3915 return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
3916}
3917
3918/*!
3919 * \internal
3920 * \brief Destroy the given hint object.
3921 *
3922 * \param obj Hint to destroy.
3923 */
3924static void destroy_hint(void *obj)
3925{
3926 struct ast_hint *hint = obj;
3927 int i;
3928
3929 ao2_cleanup(hint->callbacks);
3930
3931 for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
3932 char *device = AST_VECTOR_GET(&hint->devices, i);
3933 ast_free(device);
3934 }
3935 AST_VECTOR_FREE(&hint->devices);
3938}
3939
3940/*! \brief Publish a hint removed event */
3941static int publish_hint_remove(struct ast_hint *hint)
3942{
3943 struct stasis_message *message;
3944
3945 if (!hint_remove_message_type()) {
3946 return -1;
3947 }
3948
3949 if (!(message = stasis_message_create(hint_remove_message_type(), hint))) {
3950 ao2_ref(hint, -1);
3951 return -1;
3952 }
3953
3955
3956 ao2_ref(message, -1);
3957
3958 return 0;
3959}
3960
3961/*! \brief Remove hint from extension */
3962static int ast_remove_hint(struct ast_exten *e)
3963{
3964 /* Cleanup the Notifys if hint is removed */
3965 struct ast_hint *hint;
3966
3967 if (!e) {
3968 return -1;
3969 }
3970
3971 hint = ao2_find(hints, e, OBJ_UNLINK);
3972 if (!hint) {
3973 return -1;
3974 }
3975
3976 remove_hintdevice(hint);
3977
3978 /*
3979 * The extension is being destroyed so we must save some
3980 * information to notify that the extension is deactivated.
3981 */
3982 ao2_lock(hint);
3985 sizeof(hint->context_name));
3987 sizeof(hint->exten_name));
3988 hint->exten = NULL;
3989 ao2_unlock(hint);
3990
3991 publish_hint_remove(hint);
3992
3993 ao2_ref(hint, -1);
3994
3995 return 0;
3996}
3997
3998/*! \brief Add hint to hint list, check initial extension state */
3999static int ast_add_hint(struct ast_exten *e)
4000{
4001 struct ast_hint *hint_new;
4002 struct ast_hint *hint_found;
4003 char *message = NULL;
4004 char *subtype = NULL;
4005 int presence_state;
4006
4007 if (!e) {
4008 return -1;
4009 }
4010
4011 /*
4012 * We must create the hint we wish to add before determining if
4013 * it is already in the hints container to avoid possible
4014 * deadlock when getting the current extension state.
4015 */
4016 hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
4017 if (!hint_new) {
4018 return -1;
4019 }
4020 AST_VECTOR_INIT(&hint_new->devices, 8);
4021
4022 /* Initialize new hint. */
4024 if (!hint_new->callbacks) {
4025 ao2_ref(hint_new, -1);
4026 return -1;
4027 }
4028 hint_new->exten = e;
4029 if (strstr(e->app, "${") && e->exten[0] == '_') {
4030 /* The hint is dynamic and hasn't been evaluated yet */
4031 hint_new->laststate = AST_DEVICE_INVALID;
4033 } else {
4034 hint_new->laststate = ast_extension_state2(e, NULL);
4035 if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
4036 hint_new->last_presence_state = presence_state;
4037 hint_new->last_presence_subtype = subtype;
4038 hint_new->last_presence_message = message;
4039 }
4040 }
4041
4042 /* Prevent multiple add hints from adding the same hint at the same time. */
4043 ao2_lock(hints);
4044
4045 /* Search if hint exists, do nothing */
4046 hint_found = ao2_find(hints, e, 0);
4047 if (hint_found) {
4048 ao2_ref(hint_found, -1);
4050 ao2_ref(hint_new, -1);
4051 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
4053 return -1;
4054 }
4055
4056 /* Add new hint to the hints container */
4057 ast_debug(2, "HINTS: Adding hint %s: %s\n",
4059 ao2_link(hints, hint_new);
4060 if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
4061 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4064 }
4065
4066 /* if not dynamic */
4067 if (!(strstr(e->app, "${") && e->exten[0] == '_')) {
4068 struct ast_state_cb *state_cb;
4069 struct ao2_iterator cb_iter;
4070
4071 /* For general callbacks */
4072 cb_iter = ao2_iterator_init(statecbs, 0);
4073 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
4077 state_cb->data,
4079 hint_new,
4080 NULL);
4081 }
4082 ao2_iterator_destroy(&cb_iter);
4083 }
4085 ao2_ref(hint_new, -1);
4086
4087 return 0;
4088}
4089
4090/*! \brief Publish a hint changed event */
4091static int publish_hint_change(struct ast_hint *hint, struct ast_exten *ne)
4092{
4093 struct stasis_message *message;
4094
4095 if (!hint_change_message_type()) {
4096 return -1;
4097 }
4098
4099 if (!(message = stasis_message_create(hint_change_message_type(), hint))) {
4100 ao2_ref(hint, -1);
4101 return -1;
4102 }
4103
4106
4107 ao2_ref(message, -1);
4108
4109 return 0;
4110}
4111
4112/*! \brief Change hint for an extension */
4113static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
4114{
4115 struct ast_hint *hint;
4116
4117 if (!oe || !ne) {
4118 return -1;
4119 }
4120
4121 ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
4122
4123 /*
4124 * Unlink the hint from the hints container as the extension
4125 * name (which is the hash value) could change.
4126 */
4127 hint = ao2_find(hints, oe, OBJ_UNLINK);
4128 if (!hint) {
4131 return -1;
4132 }
4133
4134 remove_hintdevice(hint);
4135
4136 /* Update the hint and put it back in the hints container. */
4137 ao2_lock(hint);
4138 hint->exten = ne;
4139
4140 ao2_unlock(hint);
4141
4142 ao2_link(hints, hint);
4143 if (add_hintdevice(hint, ast_get_extension_app(ne))) {
4144 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4147 }
4149
4150 publish_hint_change(hint, ne);
4151
4152 ao2_ref(hint, -1);
4153
4154 return 0;
4155}
4156
4157/*! \brief Get hint for channel */
4158int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
4159{
4161
4162 if (e) {
4163 if (hint)
4164 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
4165 if (name) {
4166 const char *tmp = ast_get_extension_app_data(e);
4167 if (tmp)
4168 ast_copy_string(name, tmp, namesize);
4169 }
4170 return -1;
4171 }
4172 return 0;
4173}
4174
4175/*! \brief Get hint for channel */
4176int 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)
4177{
4179
4180 if (!e) {
4181 return 0;
4182 }
4183
4184 if (hint) {
4185 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
4186 }
4187 if (name) {
4188 const char *tmp = ast_get_extension_app_data(e);
4189 if (tmp) {
4190 ast_str_set(name, namesize, "%s", tmp);
4191 }
4192 }
4193 return -1;
4194}
4195
4196int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
4197{
4198 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
4199}
4200
4201int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
4202{
4203 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
4204}
4205
4206int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
4207{
4208 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
4209}
4210
4211int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
4212{
4213 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
4214}
4215
4216int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
4217{
4218 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
4219}
4220
4221int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
4222{
4223 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
4224}
4225
4226void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
4227{
4228 int autoloopflag;
4229 int found;
4230 int spawn_error;
4231
4232 ast_channel_lock(chan);
4233
4234 /*
4235 * Make sure that the channel is marked as hungup since we are
4236 * going to run the h exten on it.
4237 */
4239
4240 /* Set h exten location */
4241 if (context != ast_channel_context(chan)) {
4243 }
4244 ast_channel_exten_set(chan, "h");
4245 ast_channel_priority_set(chan, 1);
4246
4247 /* Save autoloop flag */
4250 ast_channel_unlock(chan);
4251
4252 for (;;) {
4253 spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
4255 S_COR(ast_channel_caller(chan)->id.number.valid,
4256 ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
4257
4258 ast_channel_lock(chan);
4259 if (spawn_error) {
4260 /* The code after the loop needs the channel locked. */
4261 break;
4262 }
4264 ast_channel_unlock(chan);
4265 }
4266 if (found && spawn_error) {
4267 /* Something bad happened, or a hangup has been requested. */
4268 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
4271 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
4274 }
4275
4276 /* An "h" exten has been run, so indicate that one has been run. */
4278
4279 /* Restore autoloop flag */
4281 ast_channel_unlock(chan);
4282}
4283
4284/*! helper function to set extension and priority */
4285void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
4286{
4291}
4292
4293/*!
4294 * \brief collect digits from the channel into the buffer.
4295 * \param c, buf, buflen, pos
4296 * \param waittime is in milliseconds
4297 * \retval 0 on timeout or done.
4298 * \retval -1 on error.
4299*/
4300static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
4301{
4302 int digit;
4303
4304 buf[pos] = '\0'; /* make sure it is properly terminated */
4306 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4307 /* As long as we're willing to wait, and as long as it's not defined,
4308 keep reading digits until we can't possibly get a right answer anymore. */
4309 digit = ast_waitfordigit(c, waittime);
4312 } else {
4313 if (!digit) /* No entry */
4314 break;
4315 if (digit < 0) /* Error, maybe a hangup */
4316 return -1;
4317 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
4318 buf[pos++] = digit;
4319 buf[pos] = '\0';
4320 }
4321 waittime = ast_channel_pbx(c)->dtimeoutms;
4322 }
4323 }
4324 return 0;
4325}
4326
4328 struct ast_pbx_args *args)
4329{
4330 int found = 0; /* set if we find at least one match */
4331 int res = 0;
4332 int autoloopflag;
4333 int error = 0; /* set an error conditions */
4334 struct ast_pbx *pbx;
4335 ast_callid callid;
4336
4337 /* A little initial setup here */
4338 if (ast_channel_pbx(c)) {
4339 ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
4340 /* XXX and now what ? */
4342 }
4343 if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
4344 return AST_PBX_FAILED;
4345 }
4346
4348 /* If the thread isn't already associated with a callid, we should create that association. */
4349 if (!callid) {
4350 /* Associate new PBX thread with the channel call id if it is available.
4351 * If not, create a new one instead.
4352 */
4353 callid = ast_channel_callid(c);
4354 if (!callid) {
4355 callid = ast_create_callid();
4356 if (callid) {
4358 ast_channel_callid_set(c, callid);
4360 }
4361 }
4363 callid = 0;
4364 }
4365
4366 ast_channel_pbx_set(c, pbx);
4367 /* Set reasonable defaults */
4368 ast_channel_pbx(c)->rtimeoutms = 10000;
4369 ast_channel_pbx(c)->dtimeoutms = 5000;
4370
4372 autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
4375
4377 /* If not successful fall back to 's' - but only if there is no given exten */
4378 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));
4379 /* XXX the original code used the existing priority in the call to
4380 * ast_exists_extension(), and reset it to 1 afterwards.
4381 * I believe the correct thing is to set it to 1 immediately.
4382 */
4383 set_ext_pri(c, "s", 1);
4384 }
4385
4386 for (;;) {
4387 char dst_exten[256]; /* buffer to accumulate digits */
4388 int pos = 0; /* XXX should check bounds */
4389 int digit = 0;
4390 int invalid = 0;
4391 int timeout = 0;
4392
4393 /* No digits pressed yet */
4394 dst_exten[pos] = '\0';
4395
4396 /* loop on priorities in this context/exten */
4399 &found, 1))) {
4400
4401 if (!ast_check_hangup(c)) {
4403 continue;
4404 }
4405
4406 /* Check softhangup flags. */
4409 continue;
4410 }
4413 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4414 set_ext_pri(c, "T", 1);
4415 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4418 continue;
4419 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4420 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4421 raise_exception(c, "ABSOLUTETIMEOUT", 1);
4422 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4425 continue;
4426 }
4427
4428 /* Call timed out with no special extension to jump to. */
4429 error = 1;
4430 break;
4431 }
4432 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
4434 error = 1;
4435 break;
4436 } /* end while - from here on we can use 'break' to go out */
4437 if (found && res) {
4438 /* Something bad happened, or a hangup has been requested. */
4439 if (strchr("0123456789ABCDEF*#", res)) {
4440 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
4441 pos = 0;
4442 dst_exten[pos++] = digit = res;
4443 dst_exten[pos] = '\0';
4444 } else if (res == AST_PBX_INCOMPLETE) {
4445 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));
4446 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));
4447
4448 /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
4450 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4451 invalid = 1;
4452 } else {
4453 ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
4454 digit = 1;
4455 pos = strlen(dst_exten);
4456 }
4457 } else {
4458 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));
4459 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));
4460
4461 if ((res == AST_PBX_ERROR)
4463 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4464 /* if we are already on the 'e' exten, don't jump to it again */
4465 if (!strcmp(ast_channel_exten(c), "e")) {
4466 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));
4467 error = 1;
4468 } else {
4469 raise_exception(c, "ERROR", 1);
4470 continue;
4471 }
4472 }
4473
4476 continue;
4477 }
4480 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4481 set_ext_pri(c, "T", 1);
4482 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4485 continue;
4486 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4487 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4488 raise_exception(c, "ABSOLUTETIMEOUT", 1);
4489 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4492 continue;
4493 }
4494 /* Call timed out with no special extension to jump to. */
4495 }
4496 error = 1;
4497 break;
4498 }
4499 }
4500 if (error)
4501 break;
4502
4503 /*!\note
4504 * We get here on a failure of some kind: non-existing extension or
4505 * hangup. We have options, here. We can either catch the failure
4506 * and continue, or we can drop out entirely. */
4507
4508 if (invalid
4509 || (ast_strlen_zero(dst_exten) &&
4511 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
4512 /*!\note
4513 * If there is no match at priority 1, it is not a valid extension anymore.
4514 * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
4515 * neither exist.
4516 */
4518 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4519 ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
4521 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
4522 set_ext_pri(c, "i", 1);
4523 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4524 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4525 raise_exception(c, "INVALID", 1);
4526 } else {
4527 ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
4529 error = 1; /* we know what to do with it */
4530 break;
4531 }
4533 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
4535 } else { /* keypress received, get more digits for a full extension */
4536 int waittime = 0;
4537 if (digit)
4538 waittime = ast_channel_pbx(c)->dtimeoutms;
4539 else if (!autofallthrough)
4540 waittime = ast_channel_pbx(c)->rtimeoutms;
4541 if (!waittime) {
4542 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
4543 if (!status)
4544 status = "UNKNOWN";
4545 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
4546 if (!strcasecmp(status, "CONGESTION"))
4547 res = indicate_congestion(c, "10");
4548 else if (!strcasecmp(status, "CHANUNAVAIL"))
4549 res = indicate_congestion(c, "10");
4550 else if (!strcasecmp(status, "BUSY"))
4551 res = indicate_busy(c, "10");
4552 error = 1; /* XXX disable message */
4553 break; /* exit from the 'for' loop */
4554 }
4555
4556 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
4557 break;
4558 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
4559 timeout = 1;
4560 if (!timeout
4561 && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
4562 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { /* Prepare the next cycle */
4563 set_ext_pri(c, dst_exten, 1);
4564 } else {
4565 /* No such extension */
4566 if (!timeout && !ast_strlen_zero(dst_exten)) {
4567 /* An invalid extension */
4569 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4570 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
4571 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
4572 set_ext_pri(c, "i", 1);
4573 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4574 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4575 raise_exception(c, "INVALID", 1);
4576 } else {
4578 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
4579 dst_exten, ast_channel_context(c));
4580 found = 1; /* XXX disable message */
4581 break;
4582 }
4583 } else {
4584 /* A simple timeout */
4586 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4587 ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
4588 set_ext_pri(c, "t", 1);
4589 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4590 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4591 raise_exception(c, "RESPONSETIMEOUT", 1);
4592 } else {
4594 "Timeout, but no rule 't' or 'e' in context '%s'\n",
4596 found = 1; /* XXX disable message */
4597 break;
4598 }
4599 }
4600 }
4601 }
4602 }
4603
4604 if (!found && !error) {
4605 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
4606 }
4607
4608 if (!args || !args->no_hangup_chan) {
4612 S_COR(ast_channel_caller(c)->id.number.valid,
4613 ast_channel_caller(c)->id.number.str, NULL))) {
4615 }
4617 }
4618
4621 ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
4625
4626 if (!args || !args->no_hangup_chan) {
4627 ast_hangup(c);
4628 }
4629
4630 return AST_PBX_SUCCESS;
4631}
4632
4633/*!
4634 * \brief Increase call count for channel
4635 * \retval 0 on success
4636 * \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached
4637*/
4638static int increase_call_count(const struct ast_channel *c)
4639{
4640 int failed = 0;
4641 double curloadavg;
4642#if defined(HAVE_SYSINFO)
4643 struct sysinfo sys_info;
4644#endif
4645
4647 if (ast_option_maxcalls) {
4649 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", ast_option_maxcalls, ast_channel_name(c));
4650 failed = -1;
4651 }
4652 }
4653 if (ast_option_maxload) {
4654 getloadavg(&curloadavg, 1);
4655 if (curloadavg >= ast_option_maxload) {
4656 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", ast_option_maxload, ast_channel_name(c), curloadavg);
4657 failed = -1;
4658 }
4659 }
4660#if defined(HAVE_SYSINFO)
4661 if (option_minmemfree) {
4662 /* Make sure that the free system memory is above the configured low watermark */
4663 if (!sysinfo(&sys_info)) {
4664 /* Convert the amount of available RAM from mem_units to MB. The calculation
4665 * was done this way to avoid overflow problems */
4666 uint64_t curfreemem = sys_info.freeram + sys_info.bufferram;
4667 curfreemem *= sys_info.mem_unit;
4668 curfreemem /= 1024 * 1024;
4669 if (curfreemem < option_minmemfree) {
4670 ast_log(LOG_WARNING, "Available system memory (~%" PRIu64 "MB) is below the configured low watermark (%ldMB)\n",
4671 curfreemem, option_minmemfree);
4672 failed = -1;
4673 }
4674 }
4675 }
4676#endif
4677
4678 if (!failed) {
4679 countcalls++;
4680 totalcalls++;
4681 }
4683
4684 return failed;
4685}
4686
4687static void decrease_call_count(void)
4688{
4690 if (countcalls > 0)
4691 countcalls--;
4693}
4694
4695static void destroy_exten(struct ast_exten *e)
4696{
4697 if (e->priority == PRIORITY_HINT)
4698 ast_remove_hint(e);
4699
4700 if (e->peer_table)
4702 if (e->peer_label_table)
4704 if (e->datad)
4705 e->datad(e->data);
4706 ast_free(e);
4707}
4708
4709static void *pbx_thread(void *data)
4710{
4711 /* Oh joyous kernel, we're a new thread, with nothing to do but
4712 answer this channel and get it going.
4713 */
4714 /* NOTE:
4715 The launcher of this function _MUST_ increment 'countcalls'
4716 before invoking the function; it will be decremented when the
4717 PBX has finished running on the channel
4718 */
4719 struct ast_channel *c = data;
4720
4723
4724 pthread_exit(NULL);
4725
4726 return NULL;
4727}
4728
4730{
4731 pthread_t t;
4732
4733 if (!c) {
4734 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
4735 return AST_PBX_FAILED;
4736 }
4737
4738 if (!ast_fully_booted) {
4739 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
4740 return AST_PBX_FAILED;
4741 }
4742
4744 return AST_PBX_CALL_LIMIT;
4745
4746 /* Start a new thread, and get something handling this channel. */
4748 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
4750 return AST_PBX_FAILED;
4751 }
4752
4753 return AST_PBX_SUCCESS;
4754}
4755
4757{
4759
4760 if (!ast_fully_booted) {
4761 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
4762 return AST_PBX_FAILED;
4763 }
4764
4765 if (increase_call_count(c)) {
4766 return AST_PBX_CALL_LIMIT;
4767 }
4768
4769 res = __ast_pbx_run(c, args);
4770
4772
4773 return res;
4774}
4775
4777{
4778 return ast_pbx_run_args(c, NULL);
4779}
4780
4782{
4783 return countcalls;
4784}
4785
4787{
4788 return totalcalls;
4789}
4790
4792{
4793 int oldval = autofallthrough;
4794 autofallthrough = newval;
4795 return oldval;
4796}
4797
4799{
4800 int oldval = extenpatternmatchnew;
4801 extenpatternmatchnew = newval;
4802 return oldval;
4803}
4804
4805void pbx_set_overrideswitch(const char *newval)
4806{
4807 if (overrideswitch) {
4809 }
4810 if (!ast_strlen_zero(newval)) {
4811 overrideswitch = ast_strdup(newval);
4812 } else {
4814 }
4815}
4816
4817/*!
4818 * \brief lookup for a context with a given name,
4819 * \retval found context or NULL if not found.
4820 */
4821static struct ast_context *find_context(const char *context)
4822{
4823 struct ast_context item = {
4824 .name = context,
4825 };
4826
4828}
4829
4830/*!
4831 * \brief lookup for a context with a given name,
4832 * \retval with conlock held if found.
4833 * \retval NULL if not found.
4834 */
4835static struct ast_context *find_context_locked(const char *context)
4836{
4837 struct ast_context *c;
4838 struct ast_context item = {
4839 .name = context,
4840 };
4841
4844 if (!c) {
4846 }
4847
4848 return c;
4849}
4850
4851/*!
4852 * \brief Remove included contexts.
4853 * This function locks contexts list by &conlist, search for the right context
4854 * structure, leave context list locked and call ast_context_remove_include2
4855 * which removes include, unlock contexts list and return ...
4856 */
4857int ast_context_remove_include(const char *context, const char *include, const char *registrar)
4858{
4859 int ret = -1;
4860 struct ast_context *c;
4861
4863 if (c) {
4864 /* found, remove include from this context ... */
4865 ret = ast_context_remove_include2(c, include, registrar);
4867 }
4868 return ret;
4869}
4870
4871/*!
4872 * \brief Locks context, remove included contexts, unlocks context.
4873 * When we call this function, &conlock lock must be locked, because when
4874 * we giving *con argument, some process can remove/change this context
4875 * and after that there can be segfault.
4876 *
4877 * \retval 0 on success.
4878 * \retval -1 on failure.
4879 */
4880int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
4881{
4882 int ret = -1;
4883 int idx;
4884
4885 ast_wrlock_context(con);
4886
4887 /* find our include */
4888 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
4889 struct ast_include *i = AST_VECTOR_GET(&con->includes, idx);
4890
4891 if (!strcmp(ast_get_include_name(i), include) &&
4892 (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) {
4893
4894 /* remove from list */
4895 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
4897
4898 /* free include and return */
4899 include_free(i);
4900 ret = 0;
4901 break;
4902 }
4903 }
4904
4905 ast_unlock_context(con);
4906
4907 return ret;
4908}
4909
4910/*!
4911 * \note This function locks contexts list by &conlist, search for the right context
4912 * structure, leave context list locked and call ast_context_remove_switch2
4913 * which removes switch, unlock contexts list and return ...
4914 */
4915int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
4916{
4917 int ret = -1; /* default error return */
4918 struct ast_context *c;
4919
4921 if (c) {
4922 /* remove switch from this context ... */
4925 }
4926 return ret;
4927}
4928
4929/*!
4930 * \brief This function locks given context, removes switch, unlock context and
4931 * return.
4932 * \note When we call this function, &conlock lock must be locked, because when
4933 * we giving *con argument, some process can remove/change this context
4934 * and after that there can be segfault.
4935 *
4936 */
4937int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
4938{
4939 int idx;
4940 int ret = -1;
4941
4942 ast_wrlock_context(con);
4943
4944 /* walk switches */
4945 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
4946 struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx);
4947
4948 if (!strcmp(ast_get_switch_name(i), sw) &&
4949 !strcmp(ast_get_switch_data(i), data) &&
4950 (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) {
4951
4952 /* found, remove from list */
4953 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
4954 AST_VECTOR_REMOVE_ORDERED(&con->alts, idx);
4955
4956 /* free switch and return */
4957 sw_free(i);
4958 ret = 0;
4959 break;
4960 }
4961 }
4962
4963 ast_unlock_context(con);
4964
4965 return ret;
4966}
4967
4968/*! \note This function will lock conlock. */
4969int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
4970{
4972}
4973
4974int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
4975{
4976 int ret = -1; /* default error return */
4977 struct ast_context *c;
4978
4980 if (c) { /* ... remove extension ... */
4982 matchcallerid, registrar, 0);
4984 }
4985
4986 return ret;
4987}
4988
4989/*!
4990 * \brief This functionc locks given context, search for the right extension and
4991 * fires out all peer in this extensions with given priority. If priority
4992 * is set to 0, all peers are removed. After that, unlock context and
4993 * return.
4994 * \note When do you want to call this function, make sure that &conlock is locked,
4995 * because some process can handle with your *con context before you lock
4996 * it.
4997 *
4998 */
4999int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
5000{
5002}
5003
5004int 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)
5005{
5006 struct ast_exten *exten, *prev_exten = NULL;
5007 struct ast_exten *peer;
5008 struct ast_exten ex, *exten2, *exten3;
5009 char dummy_name[1024];
5010 char dummy_cid[1024];
5011 struct ast_exten *previous_peer = NULL;
5012 struct ast_exten *next_peer = NULL;
5013 int found = 0;
5014
5015 if (!already_locked)
5016 ast_wrlock_context(con);
5017
5018#ifdef NEED_DEBUG
5019 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
5020#endif
5021#ifdef CONTEXT_DEBUG
5022 check_contexts(__FILE__, __LINE__);
5023#endif
5024 /* find this particular extension */
5025 ex.exten = dummy_name;
5026 ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1);
5027 ex.matchcid = matchcallerid;
5028 if (callerid) {
5029 ex.cidmatch = dummy_cid;
5030 ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1);
5031 } else {
5032 ex.cidmatch = NULL;
5033 }
5034 exten = ast_hashtab_lookup(con->root_table, &ex);
5035 if (exten) {
5036 if (priority == 0) {
5038 if (!exten2)
5039 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);
5040 if (con->pattern_tree) {
5041 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5042
5043 if (x->exten) { /* this test for safety purposes */
5044 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5045 x->exten = 0; /* get rid of what will become a bad pointer */
5046 } else {
5047 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
5048 }
5049 }
5050 } else {
5051 ex.priority = priority;
5052 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
5053 if (exten2) {
5054 if (exten2->label) { /* if this exten has a label, remove that, too */
5056 if (!exten3) {
5057 ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) "
5058 "from the peer_label_table of context %s, extension %s!\n",
5059 priority, exten2->label, con->name, exten2->name);
5060 }
5061 }
5062
5064 if (!exten3) {
5065 ast_log(LOG_ERROR, "Did not remove this priority (%d) from the "
5066 "peer_table of context %s, extension %s!\n",
5067 priority, con->name, exten2->name);
5068 }
5069 if (exten2 == exten && exten2->peer) {
5072 }
5073 if (ast_hashtab_size(exten->peer_table) == 0) {
5074 /* well, if the last priority of an exten is to be removed,
5075 then, the extension is removed, too! */
5077 if (!exten3) {
5078 ast_log(LOG_ERROR, "Did not remove this exten (%s) from the "
5079 "context root_table (%s) (priority %d)\n",
5080 exten->name, con->name, priority);
5081 }
5082 if (con->pattern_tree) {
5083 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5084 if (x->exten) { /* this test for safety purposes */
5085 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5086 x->exten = 0; /* get rid of what will become a bad pointer */
5087 }
5088 }
5089 }
5090 } else {
5091 ast_debug(3,"Could not find priority %d of exten %s in context %s!\n",
5092 priority, exten->name, con->name);
5093 }
5094 }
5095 } else {
5096 /* hmmm? this exten is not in this pattern tree? */
5097 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
5098 extension, con->name);
5099 }
5100#ifdef NEED_DEBUG
5101 if (con->pattern_tree) {
5102 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
5103 log_match_char_tree(con->pattern_tree, " ");
5104 }
5105#endif
5106
5107 /* scan the extension list to find first matching extension-registrar */
5108 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
5109 if (!strcmp(exten->exten, ex.exten) &&
5110 (!matchcallerid ||
5113 break;
5114 }
5115 }
5116 if (!exten) {
5117 /* we can't find right extension */
5118 if (!already_locked)
5119 ast_unlock_context(con);
5120 return -1;
5121 }
5122
5123 /* scan the priority list to remove extension with exten->priority == priority */
5124 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
5125 peer && !strcmp(peer->exten, ex.exten) &&
5126 (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, ex.cidmatch))) ;
5127 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
5128
5129 if ((priority == 0 || peer->priority == priority) &&
5130 (!registrar || !strcmp(peer->registrar, registrar) )) {
5131 found = 1;
5132
5133 /* we are first priority extension? */
5134 if (!previous_peer) {
5135 /*
5136 * We are first in the priority chain, so must update the extension chain.
5137 * The next node is either the next priority or the next extension
5138 */
5139 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
5140 if (peer->peer) {
5141 /* move the peer_table and peer_label_table down to the next peer, if
5142 it is there */
5145 peer->peer_table = NULL;
5147 }
5148 if (!prev_exten) { /* change the root... */
5149 con->root = next_node;
5150 } else {
5151 prev_exten->next = next_node; /* unlink */
5152 }
5153 if (peer->peer) { /* update the new head of the pri list */
5154 peer->peer->next = peer->next;
5155 }
5156 } else { /* easy, we are not first priority in extension */
5157 previous_peer->peer = peer->peer;
5158 }
5159
5160
5161 /* now, free whole priority extension */
5163 } else {
5164 previous_peer = peer;
5165 }
5166 }
5167 if (!already_locked)
5168 ast_unlock_context(con);
5169 return found ? 0 : -1;
5170}
5171
5172/*
5173 * Help for CLI commands ...
5174 */
5175
5176/*! \brief handle_show_hints: CLI support for listing registered dial plan hints */
5177static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5178{
5179 struct ast_hint *hint;
5180 int num = 0;
5181 int watchers;
5182 struct ao2_iterator i;
5184
5185 switch (cmd) {
5186 case CLI_INIT:
5187 e->command = "core show hints";
5188 e->usage =
5189 "Usage: core show hints\n"
5190 " List registered hints.\n"
5191 " Hint details are shown in five columns. In order from left to right, they are:\n"
5192 " 1. Hint extension URI.\n"
5193 " 2. List of mapped device or presence state identifiers.\n"
5194 " 3. Current extension state. The aggregate of mapped device states.\n"
5195 " 4. Current presence state for the mapped presence state provider.\n"
5196 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
5197 return NULL;
5198 case CLI_GENERATE:
5199 return NULL;
5200 }
5201
5202 if (ao2_container_count(hints) == 0) {
5203 ast_cli(a->fd, "There are no registered dialplan hints\n");
5204 return CLI_SUCCESS;
5205 }
5206 /* ... we have hints ... */
5207 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
5208
5209 i = ao2_iterator_init(hints, 0);
5210 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5211 ao2_lock(hint);
5212 if (!hint->exten) {
5213 /* The extension has already been destroyed */
5214 ao2_unlock(hint);
5215 continue;
5216 }
5217 watchers = ao2_container_count(hint->callbacks);
5218 snprintf(buf, sizeof(buf), "%s@%s",
5221
5222 ast_cli(a->fd, "%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
5223 buf,
5227 watchers);
5228
5229 ao2_unlock(hint);
5230 num++;
5231 }
5233
5234 ast_cli(a->fd, "----------------\n");
5235 ast_cli(a->fd, "- %d hints registered\n", num);
5236 return CLI_SUCCESS;
5237}
5238
5239/*! \brief autocomplete for CLI command 'core show hint' */
5240static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
5241{
5242 struct ast_hint *hint;
5243 char *ret = NULL;
5244 int which = 0;
5245 int wordlen;
5246 struct ao2_iterator i;
5247
5248 if (pos != 3)
5249 return NULL;
5250
5251 wordlen = strlen(word);
5252
5253 /* walk through all hints */
5254 i = ao2_iterator_init(hints, 0);
5255 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5256 ao2_lock(hint);
5257 if (!hint->exten) {
5258 /* The extension has already been destroyed */
5259 ao2_unlock(hint);
5260 continue;
5261 }
5262 if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
5264 ao2_unlock(hint);
5265 ao2_ref(hint, -1);
5266 break;
5267 }
5268 ao2_unlock(hint);
5269 }
5271
5272 return ret;
5273}
5274
5275/*! \brief handle_show_hint: CLI support for listing registered dial plan hint */
5276static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5277{
5278 struct ast_hint *hint;
5279 int watchers;
5280 int num = 0, extenlen;
5281 struct ao2_iterator i;
5283
5284 switch (cmd) {
5285 case CLI_INIT:
5286 e->command = "core show hint";
5287 e->usage =
5288 "Usage: core show hint <exten>\n"
5289 " List registered hint.\n"
5290 " Hint details are shown in five columns. In order from left to right, they are:\n"
5291 " 1. Hint extension URI.\n"
5292 " 2. List of mapped device or presence state identifiers.\n"
5293 " 3. Current extension state. The aggregate of mapped device states.\n"
5294 " 4. Current presence state for the mapped presence state provider.\n"
5295 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
5296 return NULL;
5297 case CLI_GENERATE:
5298 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
5299 }
5300
5301 if (a->argc < 4)
5302 return CLI_SHOWUSAGE;
5303
5304 if (ao2_container_count(hints) == 0) {
5305 ast_cli(a->fd, "There are no registered dialplan hints\n");
5306 return CLI_SUCCESS;
5307 }
5308
5309 extenlen = strlen(a->argv[3]);
5310 i = ao2_iterator_init(hints, 0);
5311 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5312 ao2_lock(hint);
5313 if (!hint->exten) {
5314 /* The extension has already been destroyed */
5315 ao2_unlock(hint);
5316 continue;
5317 }
5318 if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
5319 watchers = ao2_container_count(hint->callbacks);
5320 sprintf(buf, "%s@%s",
5323 ast_cli(a->fd, "%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
5324 buf,
5328 watchers);
5329 num++;
5330 }
5331 ao2_unlock(hint);
5332 }
5334 if (!num)
5335 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
5336 else
5337 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
5338 return CLI_SUCCESS;
5339}
5340
5341#if 0
5342/* This code can be used to test if the system survives running out of memory.
5343 * It might be an idea to put this in only if ENABLE_AUTODESTRUCT_TESTS is enabled.
5344 *
5345 * If you want to test this, these Linux sysctl flags might be appropriate:
5346 * vm.overcommit_memory = 2
5347 * vm.swappiness = 0
5348 *
5349 * <@Corydon76-home> I envision 'core eat disk space' and 'core eat file descriptors' now
5350 * <@mjordan> egads
5351 * <@mjordan> it's literally the 'big red' auto-destruct button
5352 * <@mjordan> if you were wondering who even builds such a thing.... well, now you know
5353 * ...
5354 * <@Corydon76-home> What about if they lived only if you defined TEST_FRAMEWORK? Shouldn't have those on production machines
5355 * <@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
5356 */
5357static char *handle_eat_memory(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5358{
5359 void **blocks;
5360 int blocks_pos = 0;
5361 const int blocks_max = 50000;
5362 long long int allocated = 0;
5363 int sizes[] = {
5364 100 * 1024 * 1024,
5365 100 * 1024,
5366 2 * 1024,
5367 400,
5368 0
5369 };
5370 int i;
5371
5372 switch (cmd) {
5373 case CLI_INIT:
5374 /* To do: add method to free memory again? 5 minutes? */
5375 e->command = "core eat memory";
5376 e->usage =
5377 "Usage: core eat memory\n"
5378 " Eats all available memory so you can test if the system survives\n";
5379 return NULL;
5380 case CLI_GENERATE:
5381 return NULL;
5382 }
5383
5384 blocks = ast_malloc(sizeof(void*) * blocks_max);
5385 if (!blocks) {
5386 ast_log(LOG_ERROR, "Already out of mem?\n");
5387 return CLI_SUCCESS;
5388 }
5389
5390 for (i = 0; sizes[i]; ++i) {
5391 int alloc_size = sizes[i];
5392 ast_log(LOG_WARNING, "Allocating %d sized blocks (got %d blocks already)\n", alloc_size, blocks_pos);
5393 while (1) {
5394 void *block;
5395 if (blocks_pos >= blocks_max) {
5396 ast_log(LOG_ERROR, "Memory buffer too small? Run me again :)\n");
5397 break;
5398 }
5399
5400 block = ast_malloc(alloc_size);
5401 if (!block) {
5402 break;
5403 }
5404
5405 blocks[blocks_pos++] = block;
5406 allocated += alloc_size;
5407 }
5408 }
5409
5410 /* No freeing of the mem! */
5411 ast_log(LOG_WARNING, "Allocated %lld bytes total!\n", allocated);
5412 return CLI_SUCCESS;
5413}
5414#endif
5415
5416/*
5417 * 'show dialplan' CLI command implementation functions ...
5418 */
5419static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
5420 int state)
5421{
5422 struct ast_context *c = NULL;
5423 char *ret = NULL;
5424 int which = 0;
5425 int wordlen;
5426
5427 /* we are do completion of [exten@]context on second position only */
5428 if (pos != 2)
5429 return NULL;
5430
5432
5433 wordlen = strlen(word);
5434
5435 /* walk through all contexts and return the n-th match */
5436 while ( (c = ast_walk_contexts(c)) ) {
5437 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
5439 break;
5440 }
5441 }
5442
5444
5445 return ret;
5446}
5447
5448/*! \brief Counters for the show dialplan manager command */
5456};
5457
5458/*! \brief helper function to print an extension */
5459static void print_ext(struct ast_exten *e, char * buf, int buflen)
5460{
5461 int prio = ast_get_extension_priority(e);
5462 if (prio == PRIORITY_HINT) {
5463 snprintf(buf, buflen, "hint: %s",
5465 } else {
5466 snprintf(buf, buflen, "%d. %s(%s)",
5467 prio, ast_get_extension_app(e),
5469 }
5470}
5471
5472/*! \brief Writes CLI output of a single extension for show dialplan */
5473static void show_dialplan_helper_extension_output(int fd, char *buf1, char *buf2, struct ast_exten *exten)
5474{
5476 ast_cli(fd, " %-17s %-45s [%s:%d]\n",
5477 buf1, buf2,
5480 return;
5481 }
5482
5483 ast_cli(fd, " %-17s %-45s [%s]\n",
5485}
5486
5487/* XXX not verified */
5488static 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[])
5489{
5490 struct ast_context *c = NULL;
5491 int res = 0, old_total_exten = dpc->total_exten;
5492
5494
5495 /* walk all contexts ... */
5496 while ( (c = ast_walk_contexts(c)) ) {
5497 int idx;
5498 struct ast_exten *e;
5499#ifndef LOW_MEMORY
5500 char buf[1024], buf2[1024];
5501#else
5502 char buf[256], buf2[256];
5503#endif
5504 int context_info_printed = 0;
5505
5506 if (context && strcmp(ast_get_context_name(c), context))
5507 continue; /* skip this one, name doesn't match */
5508
5509 dpc->context_existence = 1;
5510
5512
5513 /* are we looking for exten too? if yes, we print context
5514 * only if we find our extension.
5515 * Otherwise print context even if empty ?
5516 * XXX i am not sure how the rinclude is handled.
5517 * I think it ought to go inside.
5518 */
5519 if (!exten) {
5520 dpc->total_context++;
5521 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
5523 if (c->autohints) {
5524 ast_cli(fd, "Autohints support enabled\n");
5525 }
5526 context_info_printed = 1;
5527 }
5528
5529 /* walk extensions ... */
5530 e = NULL;
5531 while ( (e = ast_walk_context_extensions(c, e)) ) {
5532 struct ast_exten *p;
5533
5535 continue; /* skip, extension match failed */
5536
5537 dpc->extension_existence = 1;
5538
5539 /* may we print context info? */
5540 if (!context_info_printed) {
5541 dpc->total_context++;
5542 if (rinclude) { /* TODO Print more info about rinclude */
5543 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
5545 } else {
5546 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
5548 if (c->autohints) {
5549 ast_cli(fd, "Autohints support enabled\n");
5550 }
5551 }
5552 context_info_printed = 1;
5553 }
5554 dpc->total_prio++;
5555
5556 /* write extension name and first peer */
5557 if (e->matchcid == AST_EXT_MATCHCID_ON)
5558 snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
5559 else
5560 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
5561
5562 print_ext(e, buf2, sizeof(buf2));
5563
5565
5566 dpc->total_exten++;
5567 /* walk next extension peers */
5568 p = e; /* skip the first one, we already got it */
5569 while ( (p = ast_walk_extension_priorities(e, p)) ) {
5570 const char *el = ast_get_extension_label(p);
5571 dpc->total_prio++;
5572 if (el)
5573 snprintf(buf, sizeof(buf), " [%s]", el);
5574 else
5575 buf[0] = '\0';
5576 print_ext(p, buf2, sizeof(buf2));
5577
5579 }
5580 }
5581
5582 /* walk included and write info ... */
5583 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
5584 const struct ast_include *i = ast_context_includes_get(c, idx);
5585
5586 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
5587 if (exten) {
5588 /* Check all includes for the requested extension */
5589 if (includecount >= AST_PBX_MAX_STACK) {
5590 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
5591 } else {
5592 int dupe = 0;
5593 int x;
5594 for (x = 0; x < includecount; x++) {
5595 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
5596 dupe++;
5597 break;
5598 }
5599 }
5600 if (!dupe) {
5601 includes[includecount] = ast_get_include_name(i);
5602 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
5603 } else {
5604 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
5605 }
5606 }
5607 } else {
5608 ast_cli(fd, " Include => %-45s [%s]\n",
5610 }
5611 }
5612
5613 /* walk ignore patterns and write info ... */
5614 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
5615 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
5616 const char *ipname = ast_get_ignorepat_name(ip);
5617 char ignorepat[AST_MAX_EXTENSION];
5618
5619 snprintf(buf, sizeof(buf), "'%s'", ipname);
5620 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
5621 if (!exten || ast_extension_match(ignorepat, exten)) {
5622 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
5624 }
5625 }
5626 if (!rinclude) {
5627 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
5628 const struct ast_sw *sw = ast_context_switches_get(c, idx);
5629
5630 snprintf(buf, sizeof(buf), "'%s/%s'",
5633 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
5635 }
5636 }
5637
5639
5640 /* if we print something in context, make an empty line */
5641 if (context_info_printed)
5642 ast_cli(fd, "\n");
5643 }
5645
5646 return (dpc->total_exten == old_total_exten) ? -1 : res;
5647}
5648
5649static 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[])
5650{
5651 struct ast_context *c = NULL;
5652 int res = 0, old_total_exten = dpc->total_exten;
5653
5654 ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
5655
5656 ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
5657 ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
5658 ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
5659 ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
5660 ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
5661 ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
5662 ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
5664
5665 /* walk all contexts ... */
5666 while ( (c = ast_walk_contexts(c)) ) {
5667 int context_info_printed = 0;
5668
5669 if (context && strcmp(ast_get_context_name(c), context))
5670 continue; /* skip this one, name doesn't match */
5671
5672 dpc->context_existence = 1;
5673
5674 if (!c->pattern_tree) {
5675 /* Ignore check_return warning from Coverity for ast_exists_extension below */
5676 ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
5677 }
5678
5680
5681 dpc->total_context++;
5682 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
5684 context_info_printed = 1;
5685
5686 if (c->pattern_tree)
5687 {
5688 cli_match_char_tree(c->pattern_tree, " ", fd);
5689 } else {
5690 ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
5691 }
5692
5694
5695 /* if we print something in context, make an empty line */
5696 if (context_info_printed)
5697 ast_cli(fd, "\n");
5698 }
5700
5701 return (dpc->total_exten == old_total_exten) ? -1 : res;
5702}
5703
5704static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5705{
5706 char *exten = NULL, *context = NULL;
5707 /* Variables used for different counters */
5708 struct dialplan_counters counters;
5709 const char *incstack[AST_PBX_MAX_STACK];
5710
5711 switch (cmd) {
5712 case CLI_INIT:
5713 e->command = "dialplan show";
5714 e->usage =
5715 "Usage: dialplan show [[exten@]context]\n"
5716 " Show dialplan\n";
5717 return NULL;
5718 case CLI_GENERATE:
5719 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
5720 }
5721
5722 memset(&counters, 0, sizeof(counters));
5723
5724 if (a->argc != 2 && a->argc != 3)
5725 return CLI_SHOWUSAGE;
5726
5727 /* we obtain [exten@]context? if yes, split them ... */
5728 if (a->argc == 3) {
5729 if (strchr(a->argv[2], '@')) { /* split into exten & context */
5730 context = ast_strdupa(a->argv[2]);
5731 exten = strsep(&context, "@");
5732 /* change empty strings to NULL */
5733 if (ast_strlen_zero(exten))
5734 exten = NULL;
5735 } else { /* no '@' char, only context given */
5736 context = ast_strdupa(a->argv[2]);
5737 }
5739 context = NULL;
5740 }
5741 /* else Show complete dial plan, context and exten are NULL */
5742 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
5743
5744 /* check for input failure and throw some error messages */
5745 if (context && !counters.context_existence) {
5746 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
5747 return CLI_FAILURE;
5748 }
5749
5750 if (exten && !counters.extension_existence) {
5751 if (context)
5752 ast_cli(a->fd, "There is no existence of %s@%s extension\n",
5753 exten, context);
5754 else
5755 ast_cli(a->fd,
5756 "There is no existence of '%s' extension in all contexts\n",
5757 exten);
5758 return CLI_FAILURE;
5759 }
5760
5761 ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
5762 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
5763 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
5764 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
5765
5766 /* everything ok */
5767 return CLI_SUCCESS;
5768}
5769
5770/*! \brief Send ack once */
5771static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5772{
5773 char *exten = NULL, *context = NULL;
5774 /* Variables used for different counters */
5775 struct dialplan_counters counters;
5776 const char *incstack[AST_PBX_MAX_STACK];
5777
5778 switch (cmd) {
5779 case CLI_INIT:
5780 e->command = "dialplan debug";
5781 e->usage =
5782 "Usage: dialplan debug [context]\n"
5783 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
5784 return NULL;
5785 case CLI_GENERATE:
5786 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
5787 }
5788
5789 memset(&counters, 0, sizeof(counters));
5790
5791 if (a->argc != 2 && a->argc != 3)
5792 return CLI_SHOWUSAGE;
5793
5794 /* we obtain [exten@]context? if yes, split them ... */
5795 /* note: we ignore the exten totally here .... */
5796 if (a->argc == 3) {
5797 if (strchr(a->argv[2], '@')) { /* split into exten & context */
5798 context = ast_strdupa(a->argv[2]);
5799 exten = strsep(&context, "@");
5800 /* change empty strings to NULL */
5801 if (ast_strlen_zero(exten))
5802 exten = NULL;
5803 } else { /* no '@' char, only context given */
5804 context = ast_strdupa(a->argv[2]);
5805 }
5807 context = NULL;
5808 }
5809 /* else Show complete dial plan, context and exten are NULL */
5810 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
5811
5812 /* check for input failure and throw some error messages */
5813 if (context && !counters.context_existence) {
5814 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
5815 return CLI_FAILURE;
5816 }
5817
5818
5819 ast_cli(a->fd,"-= %d %s. =-\n",
5820 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
5821
5822 /* everything ok */
5823 return CLI_SUCCESS;
5824}
5825
5826/*! \brief Send ack once */
5827static void manager_dpsendack(struct mansession *s, const struct message *m)
5828{
5829 astman_send_listack(s, m, "DialPlan list will follow", "start");
5830}
5831
5832/*! \brief Show dialplan extensions
5833 * XXX this function is similar but not exactly the same as the CLI's
5834 * show dialplan. Must check whether the difference is intentional or not.
5835 */
5836static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
5837 const char *actionidtext, const char *context,
5838 const char *exten, struct dialplan_counters *dpc,
5839 const struct ast_include *rinclude,
5840 int includecount, const char *includes[])
5841{
5842 struct ast_context *c;
5843 int res = 0, old_total_exten = dpc->total_exten;
5844
5845 if (ast_strlen_zero(exten))
5846 exten = NULL;
5848 context = NULL;
5849
5850 ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
5851
5852 /* try to lock contexts */
5853 if (ast_rdlock_contexts()) {
5854 astman_send_error(s, m, "Failed to lock contexts");
5855 ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
5856 return -1;
5857 }
5858
5859 c = NULL; /* walk all contexts ... */
5860 while ( (c = ast_walk_contexts(c)) ) {
5861 int idx;
5862 struct ast_exten *e;
5863
5864 if (context && strcmp(ast_get_context_name(c), context) != 0)
5865 continue; /* not the name we want */
5866
5867 dpc->context_existence = 1;
5868 dpc->total_context++;
5869
5870 ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
5871
5872 if (ast_rdlock_context(c)) { /* failed to lock */
5873 ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
5874 continue;
5875 }
5876
5877 /* XXX note- an empty context is not printed */
5878 e = NULL; /* walk extensions in context */
5879 while ( (e = ast_walk_context_extensions(c, e)) ) {
5880 struct ast_exten *p;
5881
5882 /* looking for extension? is this our extension? */
5884 /* not the one we are looking for, continue */
5885 ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
5886 continue;
5887 }
5888 ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
5889
5890 dpc->extension_existence = 1;
5891
5892 dpc->total_exten++;
5893
5894 p = NULL; /* walk next extension peers */
5895 while ( (p = ast_walk_extension_priorities(e, p)) ) {
5896 int prio = ast_get_extension_priority(p);
5897
5898 dpc->total_prio++;
5899 if (!dpc->total_items++)
5900 manager_dpsendack(s, m);
5901 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5902 astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
5903
5904 /* XXX maybe make this conditional, if p != e ? */
5906 astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
5907
5908 if (prio == PRIORITY_HINT) {
5909 astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
5910 } else {
5911 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));
5912 }
5913 astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
5914 }
5915 }
5916
5917 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
5918 const struct ast_include *i = ast_context_includes_get(c, idx);
5919
5920 if (exten) {
5921 /* Check all includes for the requested extension */
5922 if (includecount >= AST_PBX_MAX_STACK) {
5923 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
5924 } else {
5925 int dupe = 0;
5926 int x;
5927 for (x = 0; x < includecount; x++) {
5928 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
5929 dupe++;
5930 break;
5931 }
5932 }
5933 if (!dupe) {
5934 includes[includecount] = ast_get_include_name(i);
5935 manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
5936 } else {
5937 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
5938 }
5939 }
5940 } else {
5941 if (!dpc->total_items++)
5942 manager_dpsendack(s, m);
5943 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5944 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));
5945 astman_append(s, "\r\n");
5946 ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
5947 }
5948 }
5949
5950 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
5951 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
5952 const char *ipname = ast_get_ignorepat_name(ip);
5953 char ignorepat[AST_MAX_EXTENSION];
5954
5955 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
5956 if (!exten || ast_extension_match(ignorepat, exten)) {
5957 if (!dpc->total_items++)
5958 manager_dpsendack(s, m);
5959 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5960 astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
5961 astman_append(s, "\r\n");
5962 }
5963 }
5964 if (!rinclude) {
5965 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
5966 const struct ast_sw *sw = ast_context_switches_get(c, idx);
5967
5968 if (!dpc->total_items++)
5969 manager_dpsendack(s, m);
5970 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5971 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));
5972 astman_append(s, "\r\n");
5973 ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
5974 }
5975 }
5976
5978 }
5980
5981 if (dpc->total_exten == old_total_exten) {
5982 ast_debug(3, "manager_show_dialplan: Found nothing new\n");
5983 /* Nothing new under the sun */
5984 return -1;
5985 } else {
5986 return res;
5987 }
5988}
5989
5990/*! \brief Manager listing of dial plan */
5991static int manager_show_dialplan(struct mansession *s, const struct message *m)
5992{
5993 const char *exten, *context;
5994 const char *id = astman_get_header(m, "ActionID");
5995 const char *incstack[AST_PBX_MAX_STACK];
5996 char idtext[256];
5997
5998 /* Variables used for different counters */
5999 struct dialplan_counters counters;
6000
6001 if (!ast_strlen_zero(id))
6002 snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
6003 else
6004 idtext[0] = '\0';
6005
6006 memset(&counters, 0, sizeof(counters));
6007
6008 exten = astman_get_header(m, "Extension");
6009 context = astman_get_header(m, "Context");
6010
6011 manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL, 0, incstack);
6012
6013 if (!ast_strlen_zero(context) && !counters.context_existence) {
6014 char errorbuf[BUFSIZ];
6015
6016 snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
6017 astman_send_error(s, m, errorbuf);
6018 return 0;
6019 }
6020 if (!ast_strlen_zero(exten) && !counters.extension_existence) {
6021 char errorbuf[BUFSIZ];
6022
6024 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
6025 else
6026 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
6027 astman_send_error(s, m, errorbuf);
6028 return 0;
6029 }
6030
6031 if (!counters.total_items) {
6032 manager_dpsendack(s, m);
6033 }
6034
6035 astman_send_list_complete_start(s, m, "ShowDialPlanComplete", counters.total_items);
6036 astman_append(s,
6037 "ListExtensions: %d\r\n"
6038 "ListPriorities: %d\r\n"
6039 "ListContexts: %d\r\n",
6040 counters.total_exten, counters.total_prio, counters.total_context);
6042
6043 /* everything ok */
6044 return 0;
6045}
6046
6047#ifdef AST_DEVMODE
6048static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6049{
6050 struct ast_devstate_aggregate agg;
6051 int i, j, exten, combined;
6052
6053 switch (cmd) {
6054 case CLI_INIT:
6055 e->command = "core show device2extenstate";
6056 e->usage =
6057 "Usage: core show device2extenstate\n"
6058 " Lists device state to extension state combinations.\n";
6059 case CLI_GENERATE:
6060 return NULL;
6061 }
6062 for (i = 0; i < AST_DEVICE_TOTAL; i++) {
6063 for (j = 0; j < AST_DEVICE_TOTAL; j++) {
6067 combined = ast_devstate_aggregate_result(&agg);
6068 exten = ast_devstate_to_extenstate(combined);
6069 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));
6070 }
6071 }
6072 ast_cli(a->fd, "\n");
6073 return CLI_SUCCESS;
6074}
6075#endif
6076
6077static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6078{
6079 int oldval = 0;
6080
6081 switch (cmd) {
6082 case CLI_INIT:
6083 e->command = "dialplan set extenpatternmatchnew true";
6084 e->usage =
6085 "Usage: dialplan set extenpatternmatchnew true|false\n"
6086 " Use the NEW extension pattern matching algorithm, true or false.\n";
6087 return NULL;
6088 case CLI_GENERATE:
6089 return NULL;
6090 }
6091
6092 if (a->argc != 4)
6093 return CLI_SHOWUSAGE;
6094
6095 oldval = pbx_set_extenpatternmatchnew(1);
6096
6097 if (oldval)
6098 ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
6099 else
6100 ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
6101
6102 return CLI_SUCCESS;
6103}
6104
6105static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6106{
6107 int oldval = 0;
6108
6109 switch (cmd) {
6110 case CLI_INIT:
6111 e->command = "dialplan set extenpatternmatchnew false";
6112 e->usage =
6113 "Usage: dialplan set extenpatternmatchnew true|false\n"
6114 " Use the NEW extension pattern matching algorithm, true or false.\n";
6115 return NULL;
6116 case CLI_GENERATE:
6117 return NULL;
6118 }
6119
6120 if (a->argc != 4)
6121 return CLI_SHOWUSAGE;
6122
6123 oldval = pbx_set_extenpatternmatchnew(0);
6124
6125 if (!oldval)
6126 ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
6127 else
6128 ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
6129
6130 return CLI_SUCCESS;
6131}
6132
6133/*
6134 * CLI entries for upper commands ...
6135 */
6136static struct ast_cli_entry pbx_cli[] = {
6137#if 0
6138 AST_CLI_DEFINE(handle_eat_memory, "Eats all available memory"),
6139#endif
6140 AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
6141 AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
6142#ifdef AST_DEVMODE
6143 AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
6144#endif
6145 AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
6146 AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
6147 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
6148 AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
6149};
6150
6152{
6153 struct ast_context *context = NULL;
6154 struct ast_exten *eroot = NULL, *e = NULL;
6155
6157 while ((context = ast_walk_contexts(context))) {
6158 while ((eroot = ast_walk_context_extensions(context, eroot))) {
6159 while ((e = ast_walk_extension_priorities(eroot, e))) {
6160 if (e->cached_app == app)
6161 e->cached_app = NULL;
6162 }
6163 }
6164 }
6166
6167 return;
6168}
6169
6170struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
6171{
6172 struct ast_context *tmp, **local_contexts;
6173 struct ast_context search = {
6174 .name = name,
6175 };
6176 size_t name_bytes = strlen(name);
6177 size_t registrar_bytes = strlen(registrar);
6178 int length = sizeof(struct ast_context) + name_bytes + registrar_bytes + 2;
6179
6180 if (!contexts_table) {
6181 /* Protect creation of contexts_table from reentrancy. */
6183 if (!contexts_table) {
6189 0);
6190 }
6192 }
6193
6194 if (!extcontexts) {
6197 tmp = ast_hashtab_lookup(contexts_table, &search);
6198 if (tmp) {
6199 tmp->refcount++;
6201 return tmp;
6202 }
6203 } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
6204 local_contexts = extcontexts;
6205 tmp = ast_hashtab_lookup(exttable, &search);
6206 if (tmp) {
6207 tmp->refcount++;
6208 return tmp;
6209 }
6210 }
6211
6212 if ((tmp = ast_calloc(1, length))) {
6213 ast_rwlock_init(&tmp->lock);
6214 tmp->name = memcpy(&tmp->data[0], name, name_bytes);
6215 tmp->registrar = memcpy(&tmp->data[name_bytes + 1], registrar, registrar_bytes);
6216 tmp->root = NULL;
6217 tmp->root_table = NULL;
6218 AST_VECTOR_INIT(&tmp->includes, 0);
6219 AST_VECTOR_INIT(&tmp->ignorepats, 0);
6220 AST_VECTOR_INIT(&tmp->alts, 0);
6221 tmp->refcount = 1;
6222
6223 /* The context 'name' must be stored at the beginning of 'data.' The
6224 * order of subsequent strings (currently only 'registrar') is not
6225 * relevant. */
6226 ast_assert(tmp->name == &tmp->data[0]);
6227 } else {
6228 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
6229 if (!extcontexts) {
6231 }
6232 return NULL;
6233 }
6234
6235 if (!extcontexts) {
6236 tmp->next = *local_contexts;
6237 *local_contexts = tmp;
6238 ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
6240 } else {
6241 tmp->next = *local_contexts;
6242 if (exttable)
6243 ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
6244
6245 *local_contexts = tmp;
6246 }
6247 ast_debug(1, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
6248 return tmp;
6249}
6250
6252{
6253 con->autohints = enabled;
6254}
6255
6256void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
6257
6259 char *context;
6260 char *exten;
6266
6268 char data[0];
6269};
6270
6272
6274{
6275 int idx;
6276
6277 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);
6278 /* copy in the includes, switches, and ignorepats */
6279 /* walk through includes */
6280 for (idx = 0; idx < ast_context_includes_count(old); idx++) {
6281 const struct ast_include *i = ast_context_includes_get(old, idx);
6282
6283 if (!strcmp(ast_get_include_registrar(i), registrar)) {
6284 continue; /* not mine */
6285 }
6287 }
6288
6289 /* walk through switches */
6290 for (idx = 0; idx < ast_context_switches_count(old); idx++) {
6291 const struct ast_sw *sw = ast_context_switches_get(old, idx);
6292
6293 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
6294 continue; /* not mine */
6295 }
6297 }
6298
6299 /* walk thru ignorepats ... */
6300 for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) {
6301 const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx);
6302
6303 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) {
6304 continue; /* not mine */
6305 }
6307 }
6308}
6309
6310/*! Set up an autohint placeholder in the hints container */
6312{
6313 struct ast_context *con;
6314 struct ast_hashtab_iter *iter;
6315
6316 /* Remove all autohints as the below iteration will recreate them */
6318
6320 while ((con = ast_hashtab_next(iter))) {
6321 size_t name_len = strlen(con->name) + 1;
6322 size_t registrar_len = strlen(con->registrar) + 1;
6323 struct ast_autohint *autohint;
6324
6325 if (!con->autohints) {
6326 continue;
6327 }
6328
6329 autohint = ao2_alloc_options(sizeof(*autohint) + name_len + registrar_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
6330 if (!autohint) {
6331 continue;
6332 }
6333
6334 ast_copy_string(autohint->context, con->name, name_len);
6335 autohint->registrar = autohint->context + name_len;
6336 ast_copy_string(autohint->registrar, con->registrar, registrar_len);
6337
6338 ao2_link(autohints, autohint);
6339 ao2_ref(autohint, -1);
6340
6341 ast_verb(3, "Enabled autohints support on context '%s'\n", con->name);
6342 }
6344}
6345
6346/* the purpose of this routine is to duplicate a context, with all its substructure,
6347 except for any extens that have a matching registrar */
6348static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
6349{
6350 struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
6351 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
6352 struct ast_hashtab_iter *exten_iter;
6353 struct ast_hashtab_iter *prio_iter;
6354 int insert_count = 0;
6355 int first = 1;
6356
6357 /* We'll traverse all the extensions/prios, and see which are not registrar'd with
6358 the current registrar, and copy them to the new context. If the new context does not
6359 exist, we'll create it "on demand". If no items are in this context to copy, then we'll
6360 only create the empty matching context if the old one meets the criteria */
6361
6362 if (context->root_table) {
6363 exten_iter = ast_hashtab_start_traversal(context->root_table);
6364 while ((exten_item=ast_hashtab_next(exten_iter))) {
6365 if (new) {
6366 new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
6367 } else {
6368 new_exten_item = NULL;
6369 }
6370 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
6371 while ((prio_item=ast_hashtab_next(prio_iter))) {
6372 int res1;
6373 char *dupdstr;
6374
6375 if (new_exten_item) {
6376 new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
6377 } else {
6378 new_prio_item = NULL;
6379 }
6380 if (strcmp(prio_item->registrar,registrar) == 0) {
6381 continue;
6382 }
6383 /* make sure the new context exists, so we have somewhere to stick this exten/prio */
6384 if (!new) {
6385 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 */
6386 if (new) {
6387 new->autohints = context->autohints;
6388 }
6389 }
6390
6391 /* copy in the includes, switches, and ignorepats */
6392 if (first) { /* but, only need to do this once */
6394 first = 0;
6395 }
6396
6397 if (!new) {
6398 ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
6399 ast_hashtab_end_traversal(prio_iter);
6400 ast_hashtab_end_traversal(exten_iter);
6401 return; /* no sense continuing. */
6402 }
6403 /* we will not replace existing entries in the new context with stuff from the old context.
6404 but, if this is because of some sort of registrar conflict, we ought to say something... */
6405
6406 dupdstr = ast_strdup(prio_item->data);
6407
6408 res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label,
6409 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar,
6410 prio_item->registrar_file, prio_item->registrar_line);
6411 if (!res1 && new_exten_item && new_prio_item){
6412 ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
6413 context->name, prio_item->name, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
6414 } else {
6415 /* 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,
6416 and no double frees take place, either! */
6417 insert_count++;
6418 }
6419 }
6420 ast_hashtab_end_traversal(prio_iter);
6421 }
6422 ast_hashtab_end_traversal(exten_iter);
6423 } else if (new) {
6424 /* If the context existed but had no extensions, we still want to merge
6425 * the includes, switches and ignore patterns.
6426 */
6428 }
6429
6430 if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
6431 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
6432 /* we could have given it the registrar of the other module who incremented the refcount,
6433 but that's not available, so we give it the registrar we know about */
6434 new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
6435
6436 if (new) {
6437 new->autohints = context->autohints;
6438 }
6439
6440 /* copy in the includes, switches, and ignorepats */
6442 }
6443}
6444
6445
6446/* XXX this does not check that multiple contexts are merged */
6447void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
6448{
6449 double ft;
6450 struct ast_context *tmp;
6451 struct ast_context *oldcontextslist;
6452 struct ast_hashtab *oldtable;
6453 struct store_hints hints_stored = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
6454 struct store_hints hints_removed = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
6455 struct store_hint *saved_hint;
6456 struct ast_hint *hint;
6457 struct ast_exten *exten;
6458 int length;
6459 struct ast_state_cb *thiscb;
6460 struct ast_hashtab_iter *iter;
6461 struct ao2_iterator i;
6462 int ctx_count = 0;
6463 struct timeval begintime;
6464 struct timeval writelocktime;
6465 struct timeval endlocktime;
6466 struct timeval enddeltime;
6467
6468 /*
6469 * It is very important that this function hold the hints
6470 * container lock _and_ the conlock during its operation; not
6471 * only do we need to ensure that the list of contexts and
6472 * extensions does not change, but also that no hint callbacks
6473 * (watchers) are added or removed during the merge/delete
6474 * process
6475 *
6476 * In addition, the locks _must_ be taken in this order, because
6477 * there are already other code paths that use this order
6478 */
6479
6480 begintime = ast_tvnow();
6481 ast_mutex_lock(&context_merge_lock);/* Serialize ast_merge_contexts_and_delete */
6483
6484 if (!contexts_table) {
6485 /* Create any autohint contexts */
6487
6488 /* Well, that's odd. There are no contexts. */
6489 contexts_table = exttable;
6490 contexts = *extcontexts;
6493 return;
6494 }
6495
6497 while ((tmp = ast_hashtab_next(iter))) {
6498 ++ctx_count;
6499 context_merge(extcontexts, exttable, tmp, registrar);
6500 }
6502
6503 ao2_lock(hints);
6504 writelocktime = ast_tvnow();
6505
6506 /* preserve all watchers for hints */
6508 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
6509 if (ao2_container_count(hint->callbacks)) {
6510 size_t exten_len;
6511
6512 ao2_lock(hint);
6513 if (!hint->exten) {
6514 /* The extension has already been destroyed. (Should never happen here) */
6515 ao2_unlock(hint);
6516 continue;
6517 }
6518
6519 exten_len = strlen(hint->exten->exten) + 1;
6520 length = exten_len + strlen(hint->exten->parent->name) + 1
6521 + sizeof(*saved_hint);
6522 if (!(saved_hint = ast_calloc(1, length))) {
6523 ao2_unlock(hint);
6524 continue;
6525 }
6526
6527 /* This removes all the callbacks from the hint into saved_hint. */
6528 while ((thiscb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
6529 AST_LIST_INSERT_TAIL(&saved_hint->callbacks, thiscb, entry);
6530 /*
6531 * We intentionally do not unref thiscb to account for the
6532 * non-ao2 reference in saved_hint->callbacks
6533 */
6534 }
6535
6536 saved_hint->laststate = hint->laststate;
6537 saved_hint->context = saved_hint->data;
6538 strcpy(saved_hint->data, hint->exten->parent->name);
6539 saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
6540 ast_copy_string(saved_hint->exten, hint->exten->exten, exten_len);
6541 if (hint->last_presence_subtype) {
6542 saved_hint->last_presence_subtype = ast_strdup(hint->last_presence_subtype);
6543 }
6544 if (hint->last_presence_message) {
6545 saved_hint->last_presence_message = ast_strdup(hint->last_presence_message);
6546 }
6547 saved_hint->last_presence_state = hint->last_presence_state;
6548 ao2_unlock(hint);
6549 AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
6550 }
6551 }
6553
6554 /* save the old table and list */
6555 oldtable = contexts_table;
6556 oldcontextslist = contexts;
6557
6558 /* move in the new table and list */
6559 contexts_table = exttable;
6560 contexts = *extcontexts;
6561
6562 /*
6563 * Restore the watchers for hints that can be found; notify
6564 * those that cannot be restored.
6565 */
6566 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_stored, list))) {
6567 struct pbx_find_info q = { .stacklen = 0 };
6568
6569 exten = pbx_find_extension(NULL, NULL, &q, saved_hint->context, saved_hint->exten,
6570 PRIORITY_HINT, NULL, "", E_MATCH);
6571 /*
6572 * If this is a pattern, dynamically create a new extension for this
6573 * particular match. Note that this will only happen once for each
6574 * individual extension, because the pattern will no longer match first.
6575 */
6576 if (exten && exten->exten[0] == '_') {
6577 ast_add_extension_nolock(exten->parent->name, 0, saved_hint->exten,
6578 PRIORITY_HINT, NULL, 0, exten->app, ast_strdup(exten->data), ast_free_ptr,
6579 exten->registrar);
6580 /* rwlocks are not recursive locks */
6581 exten = ast_hint_extension_nolock(NULL, saved_hint->context,
6582 saved_hint->exten);
6583 }
6584
6585 /* Find the hint in the hints container */
6586 hint = exten ? ao2_find(hints, exten, 0) : NULL;
6587 if (!hint) {
6588 /*
6589 * Notify watchers of this removed hint later when we aren't
6590 * encumbered by so many locks.
6591 */
6592 AST_LIST_INSERT_HEAD(&hints_removed, saved_hint, list);
6593 } else {
6594 ao2_lock(hint);
6595 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
6596 ao2_link(hint->callbacks, thiscb);
6597 /* Ref that we added when putting into saved_hint->callbacks */
6598 ao2_ref(thiscb, -1);
6599 }
6600 hint->laststate = saved_hint->laststate;
6601 hint->last_presence_state = saved_hint->last_presence_state;
6602 hint->last_presence_subtype = saved_hint->last_presence_subtype;
6603 hint->last_presence_message = saved_hint->last_presence_message;
6604 ao2_unlock(hint);
6605 ao2_ref(hint, -1);
6606 /*
6607 * The free of saved_hint->last_presence_subtype and
6608 * saved_hint->last_presence_message is not necessary here.
6609 */
6610 ast_free(saved_hint);
6611 }
6612 }
6613
6614 /* Create all applicable autohint contexts */
6616
6619
6620 /*
6621 * Notify watchers of all removed hints with the same lock
6622 * environment as device_state_cb().
6623 */
6624 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
6625 /* this hint has been removed, notify the watchers */
6626 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
6628 saved_hint->context,
6629 saved_hint->exten,
6630 thiscb->data,
6632 NULL,
6633 NULL);
6634 /* Ref that we added when putting into saved_hint->callbacks */
6635 ao2_ref(thiscb, -1);
6636 }
6637 ast_free(saved_hint->last_presence_subtype);
6638 ast_free(saved_hint->last_presence_message);
6639 ast_free(saved_hint);
6640 }
6641
6643 endlocktime = ast_tvnow();
6644
6645 /*
6646 * The old list and hashtab no longer are relevant, delete them
6647 * while the rest of asterisk is now freely using the new stuff
6648 * instead.
6649 */
6650
6651 ast_hashtab_destroy(oldtable, NULL);
6652
6653 for (tmp = oldcontextslist; tmp; ) {
6654 struct ast_context *next; /* next starting point */
6655
6656 next = tmp->next;
6658 tmp = next;
6659 }
6660 enddeltime = ast_tvnow();
6661
6662 ft = ast_tvdiff_us(writelocktime, begintime);
6663 ft /= 1000000.0;
6664 ast_verb(5,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
6665
6666 ft = ast_tvdiff_us(endlocktime, writelocktime);
6667 ft /= 1000000.0;
6668 ast_verb(5,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
6669
6670 ft = ast_tvdiff_us(enddeltime, endlocktime);
6671 ft /= 1000000.0;
6672 ast_verb(5,"Time to delete the old dialplan: %8.6f sec\n", ft);
6673
6674 ft = ast_tvdiff_us(enddeltime, begintime);
6675 ft /= 1000000.0;
6676 ast_verb(5,"Total time merge_contexts_delete: %8.6f sec\n", ft);
6677 ast_verb(5, "%s successfully loaded %d contexts (enable debug for details).\n", registrar, ctx_count);
6678}
6679
6680/*
6681 * errno values
6682 * EBUSY - can't lock
6683 * ENOENT - no existence of context
6684 */
6685int ast_context_add_include(const char *context, const char *include, const char *registrar)
6686{
6687 int ret = -1;
6688 struct ast_context *c;
6689
6691 if (c) {
6692 ret = ast_context_add_include2(c, include, registrar);
6694 }
6695 return ret;
6696}
6697
6698/*
6699 * errno values
6700 * ENOMEM - out of memory
6701 * EBUSY - can't lock
6702 * EEXIST - already included
6703 * EINVAL - there is no existence of context for inclusion
6704 */
6705int ast_context_add_include2(struct ast_context *con, const char *value,
6706 const char *registrar)
6707{
6708 struct ast_include *new_include;
6709 int idx;
6710
6711 /* allocate new include structure ... */
6712 new_include = include_alloc(value, registrar);
6713 if (!new_include) {
6714 return -1;
6715 }
6716
6717 ast_wrlock_context(con);
6718
6719 /* ... go to last include and check if context is already included too... */
6720 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
6721 const struct ast_include *i = ast_context_includes_get(con, idx);
6722
6723 if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) {
6724 include_free(new_include);
6725 ast_unlock_context(con);
6726 errno = EEXIST;
6727 return -1;
6728 }
6729 }
6730
6731 /* ... include new context into context list, unlock, return */
6732 if (AST_VECTOR_APPEND(&con->includes, new_include)) {
6733 include_free(new_include);
6734 ast_unlock_context(con);
6735 return -1;
6736 }
6737 ast_debug(1, "Including context '%s' in context '%s'\n",
6738 ast_get_include_name(new_include), ast_get_context_name(con));
6739
6740 ast_unlock_context(con);
6741
6742 return 0;
6743}
6744
6745/*
6746 * errno values
6747 * EBUSY - can't lock
6748 * ENOENT - no existence of context
6749 */
6750int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
6751{
6752 int ret = -1;
6753 struct ast_context *c;
6754
6756 if (c) { /* found, add switch to this context */
6757 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
6759 }
6760 return ret;
6761}
6762
6763/*
6764 * errno values
6765 * ENOMEM - out of memory
6766 * EBUSY - can't lock
6767 * EEXIST - already included
6768 * EINVAL - there is no existence of context for inclusion
6769 */
6770int ast_context_add_switch2(struct ast_context *con, const char *value,
6771 const char *data, int eval, const char *registrar)
6772{
6773 int idx;
6774 struct ast_sw *new_sw;
6775
6776 /* allocate new sw structure ... */
6777 if (!(new_sw = sw_alloc(value, data, eval, registrar))) {
6778 return -1;
6779 }
6780
6781 /* ... try to lock this context ... */
6782 ast_wrlock_context(con);
6783
6784 /* ... go to last sw and check if context is already swd too... */
6785 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
6786 const struct ast_sw *i = ast_context_switches_get(con, idx);
6787
6788 if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) &&
6789 !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) {
6790 sw_free(new_sw);
6791 ast_unlock_context(con);
6792 errno = EEXIST;
6793 return -1;
6794 }
6795 }
6796
6797 /* ... sw new context into context list, unlock, return */
6798 if (AST_VECTOR_APPEND(&con->alts, new_sw)) {
6799 sw_free(new_sw);
6800 ast_unlock_context(con);
6801 return -1;
6802 }
6803
6804 ast_verb(3, "Including switch '%s/%s' in context '%s'\n",
6806
6807 ast_unlock_context(con);
6808
6809 return 0;
6810}
6811
6812/*
6813 * EBUSY - can't lock
6814 * ENOENT - there is not context existence
6815 */
6816int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
6817{
6818 int ret = -1;
6819 struct ast_context *c;
6820
6822 if (c) {
6823 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
6825 }
6826 return ret;
6827}
6828
6829int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
6830{
6831 int idx;
6832
6833 ast_wrlock_context(con);
6834
6835 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6836 struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx);
6837
6838 if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) &&
6841 ignorepat_free(ip);
6842 ast_unlock_context(con);
6843 return 0;
6844 }
6845 }
6846
6847 ast_unlock_context(con);
6848 errno = EINVAL;
6849 return -1;
6850}
6851
6852/*
6853 * EBUSY - can't lock
6854 * ENOENT - there is no existence of context
6855 */
6856int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
6857{
6858 int ret = -1;
6859 struct ast_context *c;
6860
6862 if (c) {
6865 }
6866 return ret;
6867}
6868
6869int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
6870{
6871 struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar);
6872 int idx;
6873
6874 if (!ignorepat) {
6875 return -1;
6876 }
6877
6878 ast_wrlock_context(con);
6879 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6880 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
6881
6882 if (!strcasecmp(ast_get_ignorepat_name(i), value)) {
6883 /* Already there */
6884 ast_unlock_context(con);
6885 ignorepat_free(ignorepat);
6886 errno = EEXIST;
6887 return -1;
6888 }
6889 }
6890 if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) {
6891 ignorepat_free(ignorepat);
6892 ast_unlock_context(con);
6893 return -1;
6894 }
6895 ast_unlock_context(con);
6896
6897 return 0;
6898}
6899
6900int ast_ignore_pattern(const char *context, const char *pattern)
6901{
6902 int ret = 0;
6903 struct ast_context *con;
6904
6907 if (con) {
6908 int idx;
6909
6910 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6911 const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx);
6912
6914 ret = 1;
6915 break;
6916 }
6917 }
6918 }
6920
6921 return ret;
6922}
6923
6924/*
6925 * ast_add_extension_nolock -- use only in situations where the conlock is already held
6926 * ENOENT - no existence of context
6927 *
6928 */
6929static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
6930 int priority, const char *label, const char *callerid,
6931 const char *application, void *data, void (*datad)(void *), const char *registrar)
6932{
6933 int ret = -1;
6934 struct ast_context *c;
6935
6937 if (c) {
6938 ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
6939 application, data, datad, registrar, NULL, 0, 1);
6940 }
6941
6942 return ret;
6943}
6944/*
6945 * EBUSY - can't lock
6946 * ENOENT - no existence of context
6947 *
6948 */
6949int ast_add_extension(const char *context, int replace, const char *extension,
6950 int priority, const char *label, const char *callerid,
6951 const char *application, void *data, void (*datad)(void *), const char *registrar)
6952{
6953 int ret = -1;
6954 struct ast_context *c;
6955
6957 if (c) {
6958 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
6959 application, data, datad, registrar, NULL, 0);
6961 }
6962
6963 return ret;
6964}
6965
6966int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
6967{
6968 if (!chan)
6969 return -1;
6970
6971 ast_channel_lock(chan);
6972
6974 ast_channel_unlock(chan);
6975 return -1;
6976 }
6979 if (!ast_strlen_zero(exten))
6980 ast_channel_exten_set(chan, exten);
6981 if (priority > -1) {
6982 /* see flag description in channel.h for explanation */
6984 --priority;
6985 }
6987 }
6988
6989 ast_channel_unlock(chan);
6990
6991 return 0;
6992}
6993
6994int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
6995{
6996 struct ast_channel *newchan;
6997
6998 ast_channel_lock(chan);
6999 /* Channels in a bridge or running a PBX can be sent directly to the specified destination */
7000 if (ast_channel_is_bridged(chan) || ast_channel_pbx(chan)) {
7002 priority += 1;
7003 }
7006 ast_channel_unlock(chan);
7007 return 0;
7008 }
7009 ast_channel_unlock(chan);
7010
7011 /* Otherwise, we need to gain control of the channel first */
7012 newchan = ast_channel_yank(chan);
7013 if (!newchan) {
7014 ast_log(LOG_WARNING, "Unable to gain control of channel %s\n", ast_channel_name(chan));
7015 return -1;
7016 }
7018 if (ast_pbx_start(newchan)) {
7019 ast_hangup(newchan);
7020 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(newchan));
7021 return -1;
7022 }
7023
7024 return 0;
7025}
7026
7027int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
7028{
7029 struct ast_channel *chan;
7030 int res = -1;
7031
7032 if ((chan = ast_channel_get_by_name(channame))) {
7033 res = ast_async_goto(chan, context, exten, priority);
7034 chan = ast_channel_unref(chan);
7035 }
7036
7037 return res;
7038}
7039
7040/*!
7041 * \internal
7042 * \brief Copy a string skipping whitespace and optionally dashes.
7043 *
7044 * \param dst Destination buffer to copy src string.
7045 * \param src Null terminated string to copy.
7046 * \param dst_size Number of bytes in the dst buffer.
7047 * \param nofluff Nonzero if '-' chars are not copied.
7048 *
7049 * \return Number of bytes written to dst including null terminator.
7050 */
7051static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
7052{
7053 unsigned int count;
7054 unsigned int insquares;
7055 unsigned int is_pattern;
7056
7057 if (!dst_size--) {
7058 /* There really is no dst buffer */
7059 return 0;
7060 }
7061
7062 count = 0;
7063 insquares = 0;
7064 is_pattern = *src == '_';
7065 while (*src && count < dst_size) {
7066 if (*src == '[') {
7067 if (is_pattern) {
7068 insquares = 1;
7069 }
7070 } else if (*src == ']') {
7071 insquares = 0;
7072 } else if (*src == ' ' && !insquares) {
7073 ++src;
7074 continue;
7075 } else if (*src == '-' && !insquares && nofluff) {
7076 ++src;
7077 continue;
7078 }
7079 *dst++ = *src++;
7080 ++count;
7081 }
7082 *dst = '\0';
7083
7084 return count + 1;
7085}
7086
7087/*!
7088 * \brief add the extension in the priority chain.
7089 * \retval 0 on success.
7090 * \retval -1 on failure.
7091*/
7092static int add_priority(struct ast_context *con, struct ast_exten *tmp,
7093 struct ast_exten *el, struct ast_exten *e, int replace)
7094{
7095 struct ast_exten *ep;
7096 struct ast_exten *eh=e;
7097 int repeated_label = 0; /* Track if this label is a repeat, assume no. */
7098
7099 for (ep = NULL; e ; ep = e, e = e->peer) {
7100 if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
7101 if (strcmp(e->name, tmp->name)) {
7103 "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
7104 tmp->name, tmp->priority, con->name, tmp->label, e->name, e->priority);
7105 } else {
7107 "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
7108 tmp->name, tmp->priority, con->name, tmp->label, e->priority);
7109 }
7110 repeated_label = 1;
7111 }
7112 if (e->priority >= tmp->priority) {
7113 break;
7114 }
7115 }
7116
7117 if (repeated_label) { /* Discard the label since it's a repeat. */
7118 tmp->label = NULL;
7119 }
7120
7121 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
7123
7124 if (tmp->label) {
7126 }
7127 ep->peer = tmp;
7128 return 0; /* success */
7129 }
7130 if (e->priority == tmp->priority) {
7131 /* Can't have something exactly the same. Is this a
7132 replacement? If so, replace, otherwise, bonk. */
7133 if (!replace) {
7134 if (strcmp(e->name, tmp->name)) {
7136 "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
7137 tmp->name, tmp->priority, con->name, e->name);
7138 } else {
7140 "Unable to register extension '%s' priority %d in '%s', already in use\n",
7141 tmp->name, tmp->priority, con->name);
7142 }
7143
7144 return -1;
7145 }
7146 /* we are replacing e, so copy the link fields and then update
7147 * whoever pointed to e to point to us
7148 */
7149 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
7150 tmp->peer = e->peer; /* always meaningful */
7151 if (ep) { /* We're in the peer list, just insert ourselves */
7153
7154 if (e->label) {
7156 }
7157
7159 if (tmp->label) {
7161 }
7162
7163 ep->peer = tmp;
7164 } else if (el) { /* We're the first extension. Take over e's functions */
7165 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7166 tmp->peer_table = e->peer_table;
7170 if (e->label) {
7172 }
7173 if (tmp->label) {
7175 }
7176
7179 el->next = tmp;
7180 /* The pattern trie points to this exten; replace the pointer,
7181 and all will be well */
7182 if (x) { /* if the trie isn't formed yet, don't sweat this */
7183 if (x->exten) { /* this test for safety purposes */
7184 x->exten = tmp; /* replace what would become a bad pointer */
7185 } else {
7186 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7187 }
7188 }
7189 } else { /* We're the very first extension. */
7190 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7193 tmp->peer_table = e->peer_table;
7197 if (e->label) {
7199 }
7200 if (tmp->label) {
7202 }
7203
7206 con->root = tmp;
7207 /* The pattern trie points to this exten; replace the pointer,
7208 and all will be well */
7209 if (x) { /* if the trie isn't formed yet; no problem */
7210 if (x->exten) { /* this test for safety purposes */
7211 x->exten = tmp; /* replace what would become a bad pointer */
7212 } else {
7213 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7214 }
7215 }
7216 }
7217 if (tmp->priority == PRIORITY_HINT)
7218 ast_change_hint(e,tmp);
7219 /* Destroy the old one */
7220 if (e->datad)
7221 e->datad(e->data);
7222 ast_free(e);
7223 } else { /* Slip ourselves in just before e */
7224 tmp->peer = e;
7225 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
7226 if (ep) { /* Easy enough, we're just in the peer list */
7227 if (tmp->label) {
7229 }
7231 ep->peer = tmp;
7232 } else { /* we are the first in some peer list, so link in the ext list */
7233 tmp->peer_table = e->peer_table;
7235 e->peer_table = 0;
7236 e->peer_label_table = 0;
7238 if (tmp->label) {
7240 }
7243 if (el)
7244 el->next = tmp; /* in the middle... */
7245 else
7246 con->root = tmp; /* ... or at the head */
7247 e->next = NULL; /* e is no more at the head, so e->next must be reset */
7248 }
7249 /* And immediately return success. */
7250 if (tmp->priority == PRIORITY_HINT) {
7251 ast_add_hint(tmp);
7252 }
7253 }
7254 return 0;
7255}
7256
7257/*! \brief
7258 * Main interface to add extensions to the list for out context.
7259 *
7260 * We sort extensions in order of matching preference, so that we can
7261 * stop the search as soon as we find a suitable match.
7262 * This ordering also takes care of wildcards such as '.' (meaning
7263 * "one or more of any character") and '!' (which is 'earlymatch',
7264 * meaning "zero or more of any character" but also impacts the
7265 * return value from CANMATCH and EARLYMATCH.
7266 *
7267 * The extension match rules defined in the devmeeting 2006.05.05 are
7268 * quite simple: WE SELECT THE LONGEST MATCH.
7269 * In detail, "longest" means the number of matched characters in
7270 * the extension. In case of ties (e.g. _XXX and 333) in the length
7271 * of a pattern, we give priority to entries with the smallest cardinality
7272 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
7273 * while the latter has 7, etc.
7274 * In case of same cardinality, the first element in the range counts.
7275 * If we still have a tie, any final '!' will make this as a possibly
7276 * less specific pattern.
7277 *
7278 * EBUSY - can't lock
7279 * EEXIST - extension with the same priority exist and no replace is set
7280 *
7281 */
7283 int replace, const char *extension, int priority, const char *label, const char *callerid,
7284 const char *application, void *data, void (*datad)(void *),
7285 const char *registrar, const char *registrar_file, int registrar_line)
7286{
7287 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
7288 application, data, datad, registrar, registrar_file, registrar_line, 1);
7289}
7290
7292 int replace, const char *extension, int priority, const char *label, const char *callerid,
7293 const char *application, void *data, void (*datad)(void *),
7294 const char *registrar, const char *registrar_file, int registrar_line)
7295{
7296 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
7297 application, data, datad, registrar, registrar_file, registrar_line, 0);
7298}
7299
7300
7301/*!
7302 * \brief Same as ast_add_extension2() but controls the context locking.
7303 *
7304 * \details
7305 * Does all the work of ast_add_extension2, but adds an arg to
7306 * determine if context locking should be done.
7307 */
7309 int replace, const char *extension, int priority, const char *label, const char *callerid,
7310 const char *application, void *data, void (*datad)(void *),
7311 const char *registrar, const char *registrar_file, int registrar_line, int lock_context)
7312{
7313 /*
7314 * Sort extensions (or patterns) according to the rules indicated above.
7315 * These are implemented by the function ext_cmp()).
7316 * All priorities for the same ext/pattern/cid are kept in a list,
7317 * using the 'peer' field as a link field..
7318 */
7319 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
7320 int res;
7321 int length;
7322 char *p;
7323 char expand_buf[VAR_BUF_SIZE];
7324 struct ast_exten dummy_exten = {0};
7325 char dummy_name[1024];
7326 int exten_fluff;
7327 int callerid_fluff;
7328
7330 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",
7331 con->name);
7332 /* We always need to deallocate 'data' on failure */
7333 if (datad) {
7334 datad(data);
7335 }
7336 return -1;
7337 }
7338
7339 /* If we are adding a hint evaluate in variables and global variables */
7340 if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
7341 int inhibited;
7343
7344 if (c) {
7347 }
7348
7349 /*
7350 * We can allow dangerous functions when adding a hint since
7351 * altering dialplan is itself a privileged activity. Otherwise,
7352 * we could never execute dangerous functions.
7353 */
7355 pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
7356 if (0 < inhibited) {
7358 }
7359
7360 application = expand_buf;
7361 if (c) {
7363 }
7364 }
7365
7366 if (priority == PRIORITY_HINT) {
7367 /* Fluff in a hint is fine. This prevents the removal of dashes from dynamically
7368 * created hints during a reload. */
7369 exten_fluff = 0;
7370 } else {
7371 exten_fluff = ext_fluff_count(extension);
7372 }
7373
7374 callerid_fluff = callerid ? ext_fluff_count(callerid) : 0;
7375
7376 length = sizeof(struct ast_exten);
7377 length += strlen(extension) + 1;
7378 if (exten_fluff) {
7379 length += strlen(extension) + 1 - exten_fluff;
7380 }
7381 length += strlen(application) + 1;
7382 if (label) {
7383 length += strlen(label) + 1;
7384 }
7385 if (callerid) {
7386 length += strlen(callerid) + 1;
7387 if (callerid_fluff) {
7388 length += strlen(callerid) + 1 - callerid_fluff;
7389 }
7390 } else {
7391 length ++; /* just the '\0' */
7392 }
7393 if (registrar_file) {
7394 length += strlen(registrar_file) + 1;
7395 }
7396
7397 /* Be optimistic: Build the extension structure first */
7398 tmp = ast_calloc(1, length);
7399 if (!tmp) {
7400 /* We always need to deallocate 'data' on failure */
7401 if (datad) {
7402 datad(data);
7403 }
7404 return -1;
7405 }
7406
7407 if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
7408 label = 0;
7409
7410 /* use p as dst in assignments, as the fields are const char * */
7411 p = tmp->stuff;
7412 if (label) {
7413 tmp->label = p;
7414 strcpy(p, label);
7415 p += strlen(label) + 1;
7416 }
7417 tmp->name = p;
7418 p += ext_strncpy(p, extension, strlen(extension) + 1, 0);
7419 if (exten_fluff) {
7420 tmp->exten = p;
7421 p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
7422 } else {
7423 /* no fluff, we don't need a copy. */
7424 tmp->exten = tmp->name;
7425 }
7426 tmp->priority = priority;
7427 tmp->cidmatch_display = tmp->cidmatch = p; /* but use p for assignments below */
7428
7429 /* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */
7430 if (callerid) {
7431 p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
7432 if (callerid_fluff) {
7433 tmp->cidmatch = p;
7434 p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
7435 }
7437 } else {
7438 *p++ = '\0';
7440 }
7441
7442 if (registrar_file) {
7443 tmp->registrar_file = p;
7444 strcpy(p, registrar_file);
7445 p += strlen(registrar_file) + 1;
7446 } else {
7447 tmp->registrar_file = NULL;
7448 }
7449
7450 tmp->app = p;
7451 strcpy(p, application);
7452 tmp->parent = con;
7453 tmp->data = data;
7454 tmp->datad = datad;
7455 tmp->registrar = registrar;
7457
7458 if (lock_context) {
7459 ast_wrlock_context(con);
7460 }
7461
7462 if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
7463 an extension, and the trie exists, then we need to incrementally add this pattern to it. */
7464 ext_strncpy(dummy_name, tmp->exten, sizeof(dummy_name), 1);
7465 dummy_exten.exten = dummy_name;
7466 dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
7467 dummy_exten.cidmatch = 0;
7468 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
7469 if (!tmp2) {
7470 /* hmmm, not in the trie; */
7471 add_exten_to_pattern_tree(con, tmp, 0);
7472 ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
7473 }
7474 }
7475 res = 0; /* some compilers will think it is uninitialized otherwise */
7476 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
7477 res = ext_cmp(e->exten, tmp->exten);
7478 if (res == 0) { /* extension match, now look at cidmatch */
7480 res = 0;
7482 res = 1;
7484 res = -1;
7485 else
7486 res = ext_cmp(e->cidmatch, tmp->cidmatch);
7487 }
7488 if (res >= 0)
7489 break;
7490 }
7491 if (e && res == 0) { /* exact match, insert in the priority chain */
7492 res = add_priority(con, tmp, el, e, replace);
7493 if (res < 0) {
7494 if (con->pattern_tree) {
7495 struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
7496
7497 if (x->exten) {
7498 x->deleted = 1;
7499 x->exten = 0;
7500 }
7501
7503 }
7504
7505 if (tmp->datad) {
7506 tmp->datad(tmp->data);
7507 /* if you free this, null it out */
7508 tmp->data = NULL;
7509 }
7510
7511 ast_free(tmp);
7512 }
7513 if (lock_context) {
7514 ast_unlock_context(con);
7515 }
7516 if (res < 0) {
7517 errno = EEXIST;
7518 return -1;
7519 }
7520 } else {
7521 /*
7522 * not an exact match, this is the first entry with this pattern,
7523 * so insert in the main list right before 'e' (if any)
7524 */
7525 tmp->next = e;
7531 0);
7537 0);
7538
7539 if (el) { /* there is another exten already in this context */
7540 el->next = tmp;
7541 } else { /* this is the first exten in this context */
7542 if (!con->root_table) {
7548 0);
7549 }
7550 con->root = tmp;
7551 }
7552 if (label) {
7554 }
7557
7558 if (lock_context) {
7559 ast_unlock_context(con);
7560 }
7561 if (tmp->priority == PRIORITY_HINT) {
7562 ast_add_hint(tmp);
7563 }
7564 }
7565 if (DEBUG_ATLEAST(1)) {
7566 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
7567 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
7568 tmp->name, tmp->priority, tmp->cidmatch_display, con->name, con);
7569 } else {
7570 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s (%p)\n",
7571 tmp->name, tmp->priority, con->name, con);
7572 }
7573 }
7574
7575 return 0;
7576}
7577
7578/*! \brief Structure which contains information about an outgoing dial */
7580 /*! \brief Dialing structure being used */
7582 /*! \brief Condition for synchronous dialing */
7584 /*! \brief Application to execute */
7586 /*! \brief Application data to pass to application */
7587 char *appdata;
7588 /*! \brief Dialplan context */
7590 /*! \brief Dialplan extension */
7592 /*! \brief Dialplan priority */
7594 /*! \brief Result of the dial operation when dialed is set */
7596 /*! \brief Set when dialing is completed */
7597 unsigned int dialed:1;
7598 /*! \brief Set if we've spawned a thread to do our work */
7599 unsigned int in_separate_thread:1;
7600};
7601
7602/*! \brief Destructor for outgoing structure */
7603static void pbx_outgoing_destroy(void *obj)
7604{
7605 struct pbx_outgoing *outgoing = obj;
7606
7607 if (outgoing->dial) {
7609 }
7610
7611 ast_cond_destroy(&outgoing->cond);
7612
7613 ast_free(outgoing->appdata);
7614}
7615
7616/*! \brief Internal function which dials an outgoing leg and sends it to a provided extension or application */
7617static void *pbx_outgoing_exec(void *data)
7618{
7619 RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
7620 enum ast_dial_result res;
7621 struct ast_channel *chan;
7622
7623 res = ast_dial_run(outgoing->dial, NULL, 0);
7624
7625 if (outgoing->in_separate_thread) {
7626 /* Notify anyone interested that dialing is complete */
7628 outgoing->dial_res = res;
7629 outgoing->dialed = 1;
7630 ast_cond_signal(&outgoing->cond);
7632 } else {
7633 /* We still need the dial result, but we don't need to lock */
7634 outgoing->dial_res = res;
7635 }
7636
7637 /* If the outgoing leg was not answered we can immediately return and go no further */
7638 if (res != AST_DIAL_RESULT_ANSWERED) {
7639 return NULL;
7640 }
7641
7642 /* We steal the channel so we get ownership of when it is hung up */
7643 chan = ast_dial_answered_steal(outgoing->dial);
7644
7645 if (!ast_strlen_zero(outgoing->app)) {
7646 struct ast_app *app = pbx_findapp(outgoing->app);
7647
7648 if (app) {
7649 ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
7650 ast_channel_name(chan));
7651 pbx_exec(chan, app, outgoing->appdata);
7652 } else {
7653 ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app);
7654 }
7655
7656 ast_hangup(chan);
7657 } else {
7660 }
7661
7664 }
7665
7666 if (outgoing->priority > 0) {
7668 }
7669
7670 if (ast_pbx_run(chan)) {
7671 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan));
7672 ast_hangup(chan);
7673 }
7674 }
7675
7676 return NULL;
7677}
7678
7679/*! \brief Internal dialing state callback which causes early media to trigger an answer */
7680static void pbx_outgoing_state_callback(struct ast_dial *dial)
7681{
7682 struct ast_channel *channel;
7683
7685 return;
7686 }
7687
7688 if (!(channel = ast_dial_get_channel(dial, 0))) {
7689 return;
7690 }
7691
7692 ast_verb(4, "Treating progress as answer on '%s' due to early media option\n",
7693 ast_channel_name(channel));
7694
7696}
7697
7698/*!
7699 * \brief Attempt to convert disconnect cause to old originate reason.
7700 *
7701 * \todo XXX The old originate reasons need to be trashed and replaced
7702 * with normal disconnect cause codes if the call was not answered.
7703 * The internal consumers of the reason values would also need to be
7704 * updated: app_originate, call files, and AMI OriginateResponse.
7705 */
7706static enum ast_control_frame_type pbx_dial_reason(enum ast_dial_result dial_result, int cause)
7707{
7708 enum ast_control_frame_type pbx_reason;
7709
7710 if (dial_result == AST_DIAL_RESULT_ANSWERED) {
7711 /* Remote end answered. */
7712 pbx_reason = AST_CONTROL_ANSWER;
7713 } else if (dial_result == AST_DIAL_RESULT_HANGUP) {
7714 /* Caller hungup */
7715 pbx_reason = AST_CONTROL_HANGUP;
7716 } else {
7717 switch (cause) {
7719 pbx_reason = AST_CONTROL_BUSY;
7720 break;
7727 pbx_reason = AST_CONTROL_CONGESTION;
7728 break;
7731 /* Remote end was ringing (but isn't anymore) */
7732 pbx_reason = AST_CONTROL_RINGING;
7733 break;
7735 default:
7736 /* Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?) */
7737 pbx_reason = 0;
7738 break;
7739 }
7740 }
7741
7742 return pbx_reason;
7743}
7744
7745static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
7746 const char *addr, int timeout, const char *context, const char *exten, int priority,
7747 const char *app, const char *appdata, int *reason, int synchronous,
7748 const char *cid_num, const char *cid_name, struct ast_variable *vars,
7749 const char *account, struct ast_channel **locked_channel, int early_media,
7750 const struct ast_assigned_ids *assignedids, const char *predial_callee)
7751{
7753 struct ast_channel *dialed;
7754 pthread_t thread;
7755 char tmp_cid_name[128];
7756 char tmp_cid_num[128];
7757
7759 if (!outgoing) {
7760 return -1;
7761 }
7762 ast_cond_init(&outgoing->cond, NULL);
7763
7764 if (!ast_strlen_zero(app)) {
7766 outgoing->appdata = ast_strdup(appdata);
7767 } else {
7771 }
7772
7773 if (!(outgoing->dial = ast_dial_create())) {
7774 return -1;
7775 }
7776
7777 if (ast_dial_append(outgoing->dial, type, addr, assignedids)) {
7778 return -1;
7779 }
7780
7781 ast_dial_set_global_timeout(outgoing->dial, timeout);
7782
7783 if (!ast_strlen_zero(predial_callee)) {
7784 /* note casting to void * here to suppress compiler warning message (passing const to non-const function) */
7785 ast_dial_option_global_enable(outgoing->dial, AST_DIAL_OPTION_PREDIAL, (void *)predial_callee);
7786 }
7787
7788 if (ast_dial_prerun(outgoing->dial, NULL, cap)) {
7789 if (synchronous && reason) {
7791 ast_dial_reason(outgoing->dial, 0));
7792 }
7793 return -1;
7794 }
7795
7797 if (!dialed) {
7798 return -1;
7799 }
7800
7802 if (vars) {
7804 }
7805 if (!ast_strlen_zero(account)) {
7807 ast_channel_accountcode_set(dialed, account);
7808 ast_channel_peeraccount_set(dialed, account);
7810 }
7812
7813 if (!ast_strlen_zero(predial_callee)) {
7814 char *tmp = NULL;
7815 /*
7816 * The predial sub routine may have set callerid so set this into the new channel
7817 * Note... cid_num and cid_name parameters to this function will always be NULL if
7818 * predial_callee is non-NULL so we are not overwriting anything here.
7819 */
7821 if (tmp) {
7822 ast_copy_string(tmp_cid_num, tmp, sizeof(tmp_cid_num));
7823 cid_num = tmp_cid_num;
7824 }
7826 if (tmp) {
7827 ast_copy_string(tmp_cid_name, tmp, sizeof(tmp_cid_name));
7828 cid_name = tmp_cid_name;
7829 }
7830 }
7832
7833 if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
7835
7836 /*
7837 * It seems strange to set the CallerID on an outgoing call leg
7838 * to whom we are calling, but this function's callers are doing
7839 * various Originate methods. This call leg goes to the local
7840 * user. Once the called party answers, the dialplan needs to
7841 * be able to access the CallerID from the CALLERID function as
7842 * if the called party had placed this call.
7843 */
7844 ast_set_callerid(dialed, cid_num, cid_name, cid_num);
7845
7847 if (!ast_strlen_zero(cid_num)) {
7848 connected.id.number.valid = 1;
7849 connected.id.number.str = (char *) cid_num;
7851 }
7852 if (!ast_strlen_zero(cid_name)) {
7853 connected.id.name.valid = 1;
7854 connected.id.name.str = (char *) cid_name;
7856 }
7858 }
7859
7860 if (early_media) {
7862 }
7863
7864 if (locked_channel) {
7865 /*
7866 * Keep a dialed channel ref since the caller wants
7867 * the channel returned. We must get the ref before
7868 * spawning off pbx_outgoing_exec().
7869 */
7870 ast_channel_ref(dialed);
7871 if (!synchronous) {
7872 /*
7873 * Lock it now to hold off pbx_outgoing_exec() in case the
7874 * calling function needs the channel state/snapshot before
7875 * dialing actually happens.
7876 */
7877 ast_channel_lock(dialed);
7878 }
7879 }
7880
7881 /* This extra reference is dereferenced by pbx_outgoing_exec */
7882 ao2_ref(outgoing, +1);
7883
7884 if (synchronous == AST_OUTGOING_WAIT_COMPLETE) {
7885 /*
7886 * Because we are waiting until this is complete anyway, there is no
7887 * sense in creating another thread that we will just need to wait
7888 * for, so instead we commandeer the current thread.
7889 */
7891 } else {
7892 outgoing->in_separate_thread = 1;
7893
7895 ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
7896 ao2_ref(outgoing, -1);
7897 if (locked_channel) {
7898 if (!synchronous) {
7899 ast_channel_unlock(dialed);
7900 }
7901 ast_channel_unref(dialed);
7902 }
7903 return -1;
7904 }
7905
7906 if (synchronous) {
7908 /* Wait for dialing to complete */
7909 while (!outgoing->dialed) {
7911 }
7913 }
7914 }
7915
7916 if (synchronous) {
7917 /* Determine the outcome of the dialing attempt up to it being answered. */
7918 if (reason) {
7919 *reason = pbx_dial_reason(outgoing->dial_res,
7920 ast_dial_reason(outgoing->dial, 0));
7921 }
7922
7923 if (outgoing->dial_res != AST_DIAL_RESULT_ANSWERED) {
7924 /* The dial operation failed. */
7925 if (locked_channel) {
7926 ast_channel_unref(dialed);
7927 }
7928 return -1;
7929 }
7930 if (locked_channel) {
7931 ast_channel_lock(dialed);
7932 }
7933 }
7934
7935 if (locked_channel) {
7936 *locked_channel = dialed;
7937 }
7938 return 0;
7939}
7940
7941int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
7942 int timeout, const char *context, const char *exten, int priority, int *reason,
7943 int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
7944 const char *account, struct ast_channel **locked_channel, int early_media,
7945 const struct ast_assigned_ids *assignedids)
7946{
7947 return ast_pbx_outgoing_exten_predial(type, cap, addr, timeout, context, exten, priority, reason,
7948 synchronous, cid_num, cid_name, vars, account, locked_channel, early_media, assignedids, NULL);
7949}
7950
7951int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr,
7952 int timeout, const char *context, const char *exten, int priority, int *reason,
7953 int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
7954 const char *account, struct ast_channel **locked_channel, int early_media,
7955 const struct ast_assigned_ids *assignedids, const char *predial_callee)
7956{
7957 int res;
7958 int my_reason;
7959
7960 if (!reason) {
7961 reason = &my_reason;
7962 }
7963 *reason = 0;
7964 if (locked_channel) {
7965 *locked_channel = NULL;
7966 }
7967
7968 res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
7969 NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
7970 early_media, assignedids, predial_callee);
7971
7972 if (res < 0 /* Call failed to get connected for some reason. */
7973 && 0 < synchronous
7974 && ast_exists_extension(NULL, context, "failed", 1, NULL)) {
7975 struct ast_channel *failed;
7976
7977 /* We do not have to worry about a locked_channel if dialing failed. */
7978 ast_assert(!locked_channel || !*locked_channel);
7979
7980 /*!
7981 * \todo XXX Not good. The channel name is not unique if more than
7982 * one originate fails at a time.
7983 */
7984 failed = ast_channel_alloc(0, AST_STATE_DOWN, cid_num, cid_name, account,
7985 "failed", context, NULL, NULL, 0, "OutgoingSpoolFailed");
7986 if (failed) {
7987 char failed_reason[12];
7988
7989 ast_set_variables(failed, vars);
7990 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
7991 pbx_builtin_setvar_helper(failed, "REASON", failed_reason);
7992 ast_channel_unlock(failed);
7993
7994 if (ast_pbx_run(failed)) {
7995 ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n",
7996 ast_channel_name(failed));
7997 ast_hangup(failed);
7998 }
7999 }
8000 }
8001
8002 return res;
8003}
8004
8005int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
8006 int timeout, const char *app, const char *appdata, int *reason, int synchronous,
8007 const char *cid_num, const char *cid_name, struct ast_variable *vars,
8008 const char *account, struct ast_channel **locked_channel,
8009 const struct ast_assigned_ids *assignedids)
8010{
8011 return ast_pbx_outgoing_app_predial(type, cap, addr, timeout, app, appdata, reason, synchronous,
8012 cid_num, cid_name, vars, account, locked_channel, assignedids, NULL);
8013}
8014
8015int ast_pbx_outgoing_app_predial(const char *type, struct ast_format_cap *cap, const char *addr,
8016 int timeout, const char *app, const char *appdata, int *reason, int synchronous,
8017 const char *cid_num, const char *cid_name, struct ast_variable *vars,
8018 const char *account, struct ast_channel **locked_channel,
8019 const struct ast_assigned_ids *assignedids, const char *predial_callee)
8020{
8021 if (reason) {
8022 *reason = 0;
8023 }
8024 if (locked_channel) {
8025 *locked_channel = NULL;
8026 }
8027 if (ast_strlen_zero(app)) {
8028 return -1;
8029 }
8030
8031 return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
8032 reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
8033 assignedids, predial_callee);
8034}
8035
8036/* this is the guts of destroying a context --
8037 freeing up the structure, traversing and destroying the
8038 extensions, switches, ignorepats, includes, etc. etc. */
8039
8041{
8042 struct ast_exten *e, *el, *en;
8043 struct ast_context *tmp = con;
8044
8045 /* Free includes */
8048
8049 /* Free ignorepats */
8052
8053 /* Free switches */
8055 AST_VECTOR_FREE(&tmp->alts);
8056
8057 /* destroy the hash tabs */
8058 if (tmp->root_table) {
8060 }
8061 /* and destroy the pattern tree */
8062 if (tmp->pattern_tree)
8064
8065 for (e = tmp->root; e;) {
8066 for (en = e->peer; en;) {
8067 el = en;
8068 en = en->peer;
8070 }
8071 el = e;
8072 e = e->next;
8074 }
8075 tmp->root = NULL;
8076 ast_rwlock_destroy(&tmp->lock);
8077 ast_free(tmp);
8078}
8079
8080
8081void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
8082{
8083 struct ast_context *tmp, *tmpl=NULL;
8084 struct ast_exten *exten_item, *prio_item;
8085
8086 for (tmp = list; tmp; ) {
8087 struct ast_context *next = NULL; /* next starting point */
8088 /* The following code used to skip forward to the next
8089 context with matching registrar, but this didn't
8090 make sense; individual priorities registrar'd to
8091 the matching registrar could occur in any context! */
8092 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
8093 if (con) {
8094 for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
8095 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
8096 if ( !strcasecmp(tmp->name, con->name) ) {
8097 break; /* found it */
8098 }
8099 }
8100 }
8101
8102 if (!tmp) /* not found, we are done */
8103 break;
8104 ast_wrlock_context(tmp);
8105
8106 if (registrar) {
8107 /* then search thru and remove any extens that match registrar. */
8108 struct ast_hashtab_iter *exten_iter;
8109 struct ast_hashtab_iter *prio_iter;
8110 int idx;
8111
8112 /* remove any ignorepats whose registrar matches */
8113 for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) {
8114 struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx);
8115
8116 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
8118 ignorepat_free(ip);
8119 }
8120 }
8121 /* remove any includes whose registrar matches */
8122 for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) {
8123 struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx);
8124
8125 if (!strcmp(ast_get_include_registrar(i), registrar)) {
8127 include_free(i);
8128 }
8129 }
8130 /* remove any switches whose registrar matches */
8131 for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) {
8132 struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx);
8133
8134 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
8135 AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx);
8136 sw_free(sw);
8137 }
8138 }
8139
8140 if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
8141 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
8142 while ((exten_item=ast_hashtab_next(exten_iter))) {
8143 int end_traversal = 1;
8144
8145 /*
8146 * If the extension could not be removed from the root_table due to
8147 * a loaded PBX app, it can exist here but have its peer_table be
8148 * destroyed due to a previous pass through this function.
8149 */
8150 if (!exten_item->peer_table) {
8151 continue;
8152 }
8153
8154 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
8155 while ((prio_item=ast_hashtab_next(prio_iter))) {
8157 char cidmatch[AST_MAX_EXTENSION];
8158 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
8159 continue;
8160 }
8161 ast_verb(5, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
8162 tmp->name, prio_item->name, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
8163 ast_copy_string(extension, prio_item->exten, sizeof(extension));
8164 if (prio_item->cidmatch) {
8165 ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
8166 }
8167 end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
8168 }
8169 /* Explanation:
8170 * ast_context_remove_extension_callerid2 will destroy the extension that it comes across. This
8171 * destruction includes destroying the exten's peer_table, which we are currently traversing. If
8172 * ast_context_remove_extension_callerid2 ever should return '0' then this means we have destroyed
8173 * the hashtable which we are traversing, and thus calling ast_hashtab_end_traversal will result
8174 * in reading invalid memory. Thus, if we detect that we destroyed the hashtable, then we will simply
8175 * free the iterator
8176 */
8177 if (end_traversal) {
8178 ast_hashtab_end_traversal(prio_iter);
8179 } else {
8180 ast_free(prio_iter);
8181 }
8182 }
8183 ast_hashtab_end_traversal(exten_iter);
8184 }
8185
8186 /* delete the context if it's registrar matches, is empty, has refcount of 1, */
8187 /* it's not empty, if it has includes, ignorepats, or switches that are registered from
8188 another registrar. It's not empty if there are any extensions */
8189 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)) {
8190 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
8191 ast_hashtab_remove_this_object(contexttab, tmp);
8192
8193 next = tmp->next;
8194 if (tmpl)
8195 tmpl->next = next;
8196 else
8197 contexts = next;
8198 /* Okay, now we're safe to let it go -- in a sense, we were
8199 ready to let it go as soon as we locked it. */
8200 ast_unlock_context(tmp);
8202 } else {
8203 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
8204 tmp->refcount, tmp->root);
8205 ast_unlock_context(tmp);
8206 next = tmp->next;
8207 tmpl = tmp;
8208 }
8209 } else if (con) {
8210 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
8211 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
8212 ast_hashtab_remove_this_object(contexttab, tmp);
8213
8214 next = tmp->next;
8215 if (tmpl)
8216 tmpl->next = next;
8217 else
8218 contexts = next;
8219 /* Okay, now we're safe to let it go -- in a sense, we were
8220 ready to let it go as soon as we locked it. */
8221 ast_unlock_context(tmp);
8223 }
8224
8225 /* if we have a specific match, we are done, otherwise continue */
8226 tmp = con ? NULL : next;
8227 }
8228}
8229
8230int ast_context_destroy_by_name(const char *context, const char *registrar)
8231{
8232 struct ast_context *con;
8233 int ret = -1;
8234
8237 if (con) {
8239 ret = 0;
8240 }
8242
8243 return ret;
8244}
8245
8246void ast_context_destroy(struct ast_context *con, const char *registrar)
8247{
8251}
8252
8253void wait_for_hangup(struct ast_channel *chan, const void *data)
8254{
8255 int res;
8256 struct ast_frame *f;
8257 double waitsec;
8258 int waittime;
8259
8260 if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
8261 waitsec = -1;
8262 if (waitsec > -1) {
8263 waittime = waitsec * 1000.0;
8264 ast_safe_sleep_without_silence(chan, waittime);
8265 } else do {
8266 res = ast_waitfor(chan, -1);
8267 if (res < 0)
8268 return;
8269 f = ast_read(chan);
8270 if (f)
8271 ast_frfree(f);
8272 } while(f);
8273}
8274
8275/*!
8276 * \ingroup functions
8277 */
8278static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
8279{
8280 struct ast_tm tm;
8281 struct timeval tv;
8282 char *remainder, result[30], timezone[80];
8283
8284 /* Turn off testing? */
8285 if (!pbx_checkcondition(value)) {
8286 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
8287 return 0;
8288 }
8289
8290 /* Parse specified time */
8291 if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
8292 return -1;
8293 }
8294 sscanf(remainder, "%79s", timezone);
8295 tv = ast_mktime(&tm, S_OR(timezone, NULL));
8296
8297 snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
8298 pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
8299 return 0;
8300}
8301
8303 .name = "TESTTIME",
8304 .write = testtime_write,
8305};
8306
8307int pbx_checkcondition(const char *condition)
8308{
8309 int res;
8310 if (ast_strlen_zero(condition)) { /* NULL or empty strings are false */
8311 return 0;
8312 } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
8313 return res;
8314 } else { /* Strings are true */
8315 return 1;
8316 }
8317}
8318
8319static void presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
8320{
8321 struct ast_presence_state_message *presence_state;
8322 struct ast_str *hint_app = NULL;
8323 struct ast_hintdevice *device;
8324 struct ast_hintdevice *cmpdevice;
8325 struct ao2_iterator *dev_iter;
8326
8328 return;
8329 }
8330
8331 presence_state = stasis_message_data(msg);
8332
8333 if (ao2_container_count(hintdevices) == 0) {
8334 /* There are no hints monitoring devices. */
8335 return;
8336 }
8337
8338 hint_app = ast_str_create(1024);
8339 if (!hint_app) {
8340 return;
8341 }
8342
8343 cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(presence_state->provider));
8344 strcpy(cmpdevice->hintdevice, presence_state->provider);
8345
8346 ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
8347 dev_iter = ao2_t_callback(hintdevices,
8350 cmpdevice,
8351 "find devices in container");
8352 if (!dev_iter) {
8354 ast_free(hint_app);
8355 return;
8356 }
8357
8358 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
8359 if (device->hint) {
8360 presence_state_notify_callbacks(device->hint, &hint_app, presence_state);
8361 }
8362 }
8363 ao2_iterator_destroy(dev_iter);
8365
8366 ast_free(hint_app);
8367}
8368
8369static int action_extensionstatelist(struct mansession *s, const struct message *m)
8370{
8371 const char *action_id = astman_get_header(m, "ActionID");
8372 struct ast_hint *hint;
8373 struct ao2_iterator it_hints;
8374 int hint_count = 0;
8375
8376 if (!hints) {
8377 astman_send_error(s, m, "No dialplan hints are available");
8378 return 0;
8379 }
8380
8381 astman_send_listack(s, m, "Extension Statuses will follow", "start");
8382
8383 ao2_lock(hints);
8384 it_hints = ao2_iterator_init(hints, 0);
8385 for (; (hint = ao2_iterator_next(&it_hints)); ao2_ref(hint, -1)) {
8386
8387 ao2_lock(hint);
8388
8389 /* Ignore pattern matching hints; they are stored in the
8390 * hints container but aren't real from the perspective of
8391 * an AMI user
8392 */
8393 if (hint->exten->exten[0] == '_') {
8394 ao2_unlock(hint);
8395 continue;
8396 }
8397
8398 ++hint_count;
8399
8400 astman_append(s, "Event: ExtensionStatus\r\n");
8401 if (!ast_strlen_zero(action_id)) {
8402 astman_append(s, "ActionID: %s\r\n", action_id);
8403 }
8404 astman_append(s,
8405 "Exten: %s\r\n"
8406 "Context: %s\r\n"
8407 "Hint: %s\r\n"
8408 "Status: %d\r\n"
8409 "StatusText: %s\r\n\r\n",
8410 hint->exten->exten,
8411 hint->exten->parent->name,
8412 hint->exten->app,
8413 hint->laststate,
8415 ao2_unlock(hint);
8416 }
8417
8418 ao2_iterator_destroy(&it_hints);
8420
8421 astman_send_list_complete_start(s, m, "ExtensionStateListComplete", hint_count);
8423
8424 return 0;
8425}
8426
8427
8428/*!
8429 * \internal
8430 * \brief Clean up resources on Asterisk shutdown.
8431 *
8432 * \note Cleans up resources allocated in load_pbx
8433 */
8434static void unload_pbx(void)
8435{
8438
8439 ast_manager_unregister("ShowDialPlan");
8440 ast_manager_unregister("ExtensionStateList");
8444}
8445
8446int load_pbx(void)
8447{
8448 int res = 0;
8449
8451
8452 /* Initialize the PBX */
8453 ast_verb(1, "Asterisk PBX Core Initializing\n");
8454
8455 ast_verb(5, "Registering builtin functions:\n");
8459
8460 /* Register manager application */
8463
8464 if (res) {
8465 return -1;
8466 }
8467
8469 return -1;
8470 }
8472 stasis_subscription_accept_message_type(device_state_sub, hint_change_message_type());
8473 stasis_subscription_accept_message_type(device_state_sub, hint_remove_message_type());
8475
8477 return -1;
8478 }
8481
8482 return 0;
8483}
8484
8485/*
8486 * Lock context list functions ...
8487 */
8489{
8490 return ast_mutex_lock(&conlock);
8491}
8492
8494{
8495 return ast_mutex_lock(&conlock);
8496}
8497
8499{
8500 return ast_mutex_unlock(&conlock);
8501}
8502
8503/*
8504 * Lock context ...
8505 */
8507{
8508 return ast_rwlock_wrlock(&con->lock);
8509}
8510
8512{
8513 return ast_rwlock_rdlock(&con->lock);
8514}
8515
8517{
8518 return ast_rwlock_unlock(&con->lock);
8519}
8520
8521/*
8522 * Name functions ...
8523 */
8524const char *ast_get_context_name(struct ast_context *con)
8525{
8526 return con ? con->name : NULL;
8527}
8528
8530{
8531 return exten ? exten->parent : NULL;
8532}
8533
8534const char *ast_get_extension_name(struct ast_exten *exten)
8535{
8536 return exten ? exten->name : NULL;
8537}
8538
8539const char *ast_get_extension_label(struct ast_exten *exten)
8540{
8541 return exten ? exten->label : NULL;
8542}
8543
8545{
8546 return exten ? exten->priority : -1;
8547}
8548
8549/*
8550 * Registrar info functions ...
8551 */
8553{
8554 return c ? c->registrar : NULL;
8555}
8556
8558{
8559 return e ? e->registrar : NULL;
8560}
8561
8563{
8564 return e ? e->registrar_file : NULL;
8565}
8566
8568{
8569 return e ? e->registrar_line : 0;
8570}
8571
8573{
8574 return e ? e->matchcid : 0;
8575}
8576
8578{
8579 return e ? e->cidmatch_display : NULL;
8580}
8581
8582const char *ast_get_extension_app(struct ast_exten *e)
8583{
8584 return e ? e->app : NULL;
8585}
8586
8588{
8589 return e ? e->data : NULL;
8590}
8591
8592int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c,
8593 const char *context, const char *exten, int priority)
8594{
8595 struct ast_exten *e;
8596 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
8598 e = pbx_find_extension(c, NULL, &q, context, exten, priority, NULL, "", E_MATCH);
8599 if (e) {
8600 if (buf) {
8601 const char *tmp = ast_get_extension_app_data(e);
8602 if (tmp) {
8603 ast_copy_string(buf, tmp, bufsize);
8604 }
8605 }
8607 return 0;
8608 }
8610 return -1;
8611}
8612
8613/*
8614 * Walking functions ...
8615 */
8617{
8618 return con ? con->next : contexts;
8619}
8620
8622 struct ast_exten *exten)
8623{
8624 if (!exten)
8625 return con ? con->root : NULL;
8626 else
8627 return exten->next;
8628}
8629
8630const struct ast_sw *ast_walk_context_switches(const struct ast_context *con,
8631 const struct ast_sw *sw)
8632{
8633 if (sw) {
8634 int idx;
8635 int next = 0;
8636
8637 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
8638 const struct ast_sw *s = ast_context_switches_get(con, idx);
8639
8640 if (next) {
8641 return s;
8642 }
8643
8644 if (sw == s) {
8645 next = 1;
8646 }
8647 }
8648
8649 return NULL;
8650 }
8651
8652 if (!ast_context_switches_count(con)) {
8653 return NULL;
8654 }
8655
8656 return ast_context_switches_get(con, 0);
8657}
8658
8660{
8661 return AST_VECTOR_SIZE(&con->alts);
8662}
8663
8664const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx)
8665{
8666 return AST_VECTOR_GET(&con->alts, idx);
8667}
8668
8670 struct ast_exten *priority)
8671{
8672 return priority ? priority->peer : exten;
8673}
8674
8675const struct ast_include *ast_walk_context_includes(const struct ast_context *con,
8676 const struct ast_include *inc)
8677{
8678 if (inc) {
8679 int idx;
8680 int next = 0;
8681
8682 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
8683 const struct ast_include *include = AST_VECTOR_GET(&con->includes, idx);
8684
8685 if (next) {
8686 return include;
8687 }
8688
8689 if (inc == include) {
8690 next = 1;
8691 }
8692 }
8693
8694 return NULL;
8695 }
8696
8697 if (!ast_context_includes_count(con)) {
8698 return NULL;
8699 }
8700
8701 return ast_context_includes_get(con, 0);
8702}
8703
8705{
8706 return AST_VECTOR_SIZE(&con->includes);
8707}
8708
8709const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx)
8710{
8711 return AST_VECTOR_GET(&con->includes, idx);
8712}
8713
8715 const struct ast_ignorepat *ip)
8716{
8717 if (!con) {
8718 return NULL;
8719 }
8720
8721 if (ip) {
8722 int idx;
8723 int next = 0;
8724
8725 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
8726 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
8727
8728 if (next) {
8729 return i;
8730 }
8731
8732 if (ip == i) {
8733 next = 1;
8734 }
8735 }
8736
8737 return NULL;
8738 }
8739
8740 if (!ast_context_ignorepats_count(con)) {
8741 return NULL;
8742 }
8743
8744 return ast_context_ignorepats_get(con, 0);
8745}
8746
8748{
8749 return AST_VECTOR_SIZE(&con->ignorepats);
8750}
8751
8752const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx)
8753{
8754 return AST_VECTOR_GET(&con->ignorepats, idx);
8755}
8756
8758{
8759 int idx;
8760 int res = 0;
8761 int includecount = ast_context_includes_count(con);
8762
8763 if (includecount >= AST_PBX_MAX_STACK) {
8764 ast_log(LOG_WARNING, "Context %s contains too many includes (%d). Maximum is %d.\n",
8765 ast_get_context_name(con), includecount, AST_PBX_MAX_STACK);
8766 }
8767
8768 for (idx = 0; idx < includecount; idx++) {
8769 const struct ast_include *inc = ast_context_includes_get(con, idx);
8770
8771 if (ast_context_find(include_rname(inc))) {
8772 continue;
8773 }
8774
8775 res = -1;
8776 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
8778 break;
8779 }
8780
8781 return res;
8782}
8783
8784
8785static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
8786{
8787 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
8788
8789 if (!chan)
8790 return -2;
8791
8792 if (context == NULL)
8794 if (exten == NULL)
8795 exten = ast_channel_exten(chan);
8796
8797 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
8799 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)))
8800 return goto_func(chan, context, exten, priority);
8801 else {
8802 return AST_PBX_GOTO_FAILED;
8803 }
8804}
8805
8806int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
8807{
8808 return __ast_goto_if_exists(chan, context, exten, priority, 0);
8809}
8810
8811int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
8812{
8813 return __ast_goto_if_exists(chan, context, exten, priority, 1);
8814}
8815
8816int pbx_parse_location(struct ast_channel *chan, char **contextp, char **extenp, char **prip, int *ipri, int *mode, char *rest)
8817{
8818 char *context, *exten, *pri;
8819 /* do the strsep before here, so we don't have to alloc and free */
8820 if (!*extenp) {
8821 /* Only a priority in this one */
8822 *prip = *contextp;
8823 *extenp = NULL;
8824 *contextp = NULL;
8825 } else if (!*prip) {
8826 /* Only an extension and priority in this one */
8827 *prip = *extenp;
8828 *extenp = *contextp;
8829 *contextp = NULL;
8830 }
8831 context = *contextp;
8832 exten = *extenp;
8833 pri = *prip;
8834 if (mode) {
8835 if (*pri == '+') {
8836 *mode = 1;
8837 pri++;
8838 } else if (*pri == '-') {
8839 *mode = -1;
8840 pri++;
8841 }
8842 }
8843 if ((rest && sscanf(pri, "%30d%1s", ipri, rest) != 1) || sscanf(pri, "%30d", ipri) != 1) {
8845 exten ? exten : ast_channel_exten(chan), pri,
8846 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
8847 if (*ipri < 1) {
8848 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
8849 return -1;
8850 } else if (mode) {
8851 *mode = 0;
8852 }
8853 }
8854 return 0;
8855}
8856
8857static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
8858{
8859 char *exten, *pri, *context;
8860 char *stringp;
8861 int ipri;
8862 int mode = 0;
8863 char rest[2] = "";
8864
8865 if (ast_strlen_zero(goto_string)) {
8866 ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
8867 return -1;
8868 }
8869 stringp = ast_strdupa(goto_string);
8870 context = strsep(&stringp, ","); /* guaranteed non-null */
8871 exten = strsep(&stringp, ",");
8872 pri = strsep(&stringp, ",");
8873
8874 if (pbx_parse_location(chan, &context, &exten, &pri, &ipri, &mode, rest)) {
8875 return -1;
8876 }
8877 /* At this point we have a priority and maybe an extension and a context */
8878
8879 if (mode)
8880 ipri = ast_channel_priority(chan) + (ipri * mode);
8881
8882 if (async)
8883 ast_async_goto(chan, context, exten, ipri);
8884 else
8885 ast_explicit_goto(chan, context, exten, ipri);
8886
8887 return 0;
8888
8889}
8890
8891int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
8892{
8893 return pbx_parseable_goto(chan, goto_string, 0);
8894}
8895
8896int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
8897{
8898 return pbx_parseable_goto(chan, goto_string, 1);
8899}
8900
8901static int hint_hash(const void *obj, const int flags)
8902{
8903 const struct ast_hint *hint = obj;
8904 const char *exten_name;
8905 int res;
8906
8909 /*
8910 * If the exten or extension name isn't set, return 0 so that
8911 * the ao2_find() search will start in the first bucket.
8912 */
8913 res = 0;
8914 } else {
8916 }
8917
8918 return res;
8919}
8920
8921static int hint_cmp(void *obj, void *arg, int flags)
8922{
8923 const struct ast_hint *hint = obj;
8924 const struct ast_exten *exten = arg;
8925
8926 return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
8927}
8928
8929static int statecbs_cmp(void *obj, void *arg, int flags)
8930{
8931 const struct ast_state_cb *state_cb = obj;
8933
8934 return (state_cb->change_cb == change_cb) ? CMP_MATCH | CMP_STOP : 0;
8935}
8936
8937/*!
8938 * \internal
8939 * \brief Clean up resources on Asterisk shutdown
8940 */
8941static void pbx_shutdown(void)
8942{
8943 STASIS_MESSAGE_TYPE_CLEANUP(hint_change_message_type);
8944 STASIS_MESSAGE_TYPE_CLEANUP(hint_remove_message_type);
8945
8946 if (hints) {
8947 ao2_container_unregister("hints");
8948 ao2_ref(hints, -1);
8949 hints = NULL;
8950 }
8951 if (hintdevices) {
8952 ao2_container_unregister("hintdevices");
8953 ao2_ref(hintdevices, -1);
8954 hintdevices = NULL;
8955 }
8956 if (autohints) {
8957 ao2_container_unregister("autohints");
8958 ao2_ref(autohints, -1);
8959 autohints = NULL;
8960 }
8961 if (statecbs) {
8962 ao2_container_unregister("statecbs");
8963 ao2_ref(statecbs, -1);
8964 statecbs = NULL;
8965 }
8966 if (contexts_table) {
8968 }
8969}
8970
8971static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8972{
8973 struct ast_hint *hint = v_obj;
8974
8975 if (!hint) {
8976 return;
8977 }
8978 prnt(where, "%s@%s", ast_get_extension_name(hint->exten),
8980}
8981
8982static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8983{
8984 struct ast_hintdevice *hintdevice = v_obj;
8985
8986 if (!hintdevice) {
8987 return;
8988 }
8989 prnt(where, "%s => %s@%s", hintdevice->hintdevice,
8990 ast_get_extension_name(hintdevice->hint->exten),
8992}
8993
8994static void print_autohint_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8995{
8996 struct ast_autohint *autohint = v_obj;
8997
8998 if (!autohint) {
8999 return;
9000 }
9001 prnt(where, "%s", autohint->context);
9002}
9003
9004static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
9005{
9006 struct ast_state_cb *state_cb = v_obj;
9007
9008 if (!state_cb) {
9009 return;
9010 }
9011 prnt(where, "%d", state_cb->id);
9012}
9013
9015{
9018 if (hints) {
9020 }
9023 if (hintdevices) {
9025 }
9026 /* This is protected by the context_and_merge lock */
9029 if (autohints) {
9031 }
9033 if (statecbs) {
9035 }
9036
9038
9039 if (STASIS_MESSAGE_TYPE_INIT(hint_change_message_type) != 0) {
9040 return -1;
9041 }
9042 if (STASIS_MESSAGE_TYPE_INIT(hint_remove_message_type) != 0) {
9043 return -1;
9044 }
9045
9046 return (hints && hintdevices && autohints && statecbs) ? 0 : -1;
9047}
Prototypes for public functions only of internal interest,.
static const char app[]
Definition: app_adsiprog.c:56
char digit
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
enum queue_result id
Definition: app_queue.c:1808
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
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#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:347
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_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#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_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_t_link(container, obj, tag)
Definition: astobj2.h:1534
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1852
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#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
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag)
ao2_callback_data() is a generic function that applies cb_fn() to all objects in a container....
Definition: astobj2.h:1721
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:407
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
Definition: astobj2.h:1696
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
Definition: astobj2.h:1435
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
enum cc_state state
Definition: ccss.c:399
Call Detail Record API.
static int priority
static char * table
Definition: cdr_odbc.c:55
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:2388
static const char type[]
Definition: chan_ooh323.c:109
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:3143
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2354
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2401
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
Definition: channel.c:1348
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2510
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1329
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:8309
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1368
void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
adds a list of channel variables to a channel
Definition: channel.c:8116
struct ast_channel * ast_channel_yank(struct ast_channel *yankee)
Gain control of a channel in the system.
Definition: channel.c:10594
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3130
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1269
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:2997
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
@ AST_FLAG_BRIDGE_HANGUP_RUN
Definition: channel.h:1038
@ AST_FLAG_IN_AUTOLOOP
Definition: channel.h:1017
@ AST_FLAG_ORIGINATED
Definition: channel.h:1059
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...
Definition: autoservice.c:200
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4210
struct timeval ast_channel_creationtime(struct ast_channel *chan)
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:7303
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1397
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:444
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10546
@ 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
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2440
#define AST_CHANNEL_NAME
Definition: channel.h:173
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
#define AST_MAX_CONTEXT
Definition: channel.h:135
void ast_channel_context_set(struct ast_channel *chan, const char *value)
#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:2427
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:2012
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:1546
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
#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:2368
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_RINGING
Definition: channelstate.h:41
@ AST_STATE_DOWN
Definition: channelstate.h:36
@ AST_STATE_BUSY
Definition: channelstate.h:43
@ AST_STATE_UP
Definition: channelstate.h:42
size_t current
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#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
Device state management.
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
Definition: devicestate.c:258
void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
Add a device state to the aggregate device state.
Definition: devicestate.c:639
void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
Initialize aggregate device state.
Definition: devicestate.c:633
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:671
enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
Get the aggregate device state result.
Definition: devicestate.c:666
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
@ AST_DEVICE_TOTAL
Definition: devicestate.h:62
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
Dialing API.
enum ast_dial_result ast_dial_state(struct ast_dial *dial)
Return state of dial.
Definition: dial.c:1008
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:1269
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:1284
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:935
struct ast_channel * ast_dial_answered_steal(struct ast_dial *dial)
Steal the channel that answered.
Definition: dial.c:989
int ast_dial_reason(struct ast_dial *dial, int num)
Get the reason an outgoing channel has failed.
Definition: dial.c:1247
@ 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:1258
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition: dial.c:1091
int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data)
Enables an option globally.
Definition: dial.c:1145
static int enabled
Definition: dnsmgr.c:91
char connected
Definition: eagi_proxy.c:82
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#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
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition: format_mp3.c:68
static const char exten_name[]
static const char context_name[]
static struct ast_threadstorage buf2
static struct ast_threadstorage buf1
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:980
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:2024
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1982
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:2060
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2068
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1903
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7695
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)
Definition: pbx_builtins.c:834
int indicate_congestion(struct ast_channel *chan, const char *data)
Definition: pbx_builtins.c:852
static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
Definition: pbx.c:8278
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:144
const char * ext
Definition: http.c:150
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_BUSY
@ 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 callerid from the thread
Definition: logger.c:2273
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2295
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition: logger.c:2268
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.
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:252
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
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:203
#define EVENT_FLAG_CONFIG
Definition: manager.h:82
#define EVENT_FLAG_CALL
Definition: manager.h:76
Asterisk module definitions.
Music on hold handling.
def info(msg)
#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:8587
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:7680
static int hashtab_compare_extens(const void *ha_a, const void *ah_b)
Definition: pbx.c:713
static struct ao2_container * statecbs
Definition: pbx.c:823
const struct ast_sw * ast_context_switches_get(const struct ast_context *con, int idx)
Definition: pbx.c:8664
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:1084
void unreference_cached_app(struct ast_app *app)
Definition: pbx.c:6151
void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
Definition: pbx.c:8081
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:6949
static int totalcalls
Definition: pbx.c:794
int ast_context_destroy_by_name(const char *context, const char *registrar)
Destroy a context by name.
Definition: pbx.c:8230
static int manager_show_dialplan(struct mansession *s, const struct message *m)
Manager listing of dial plan.
Definition: pbx.c:5991
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
Remove an ignorepat.
Definition: pbx.c:6816
static int countcalls
Definition: pbx.c:793
int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
Uses hint and presence state callback to get the presence state of an extension.
Definition: pbx.c:3247
static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten, struct ao2_container *device_state_info)
Definition: pbx.c:3162
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:4201
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:7706
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:7951
static struct ast_exten * trie_find_next_match(struct match_char *node)
Definition: pbx.c:1180
int ast_extension_state_add_destroy_extended(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
Add watcher for extended extension states with destructor.
Definition: pbx.c:3850
const char * ast_extension_state2str(int extension_state)
Return extension_state as string.
Definition: pbx.c:3147
static int handle_hint_change_message_type(struct stasis_message *msg, enum ast_state_cb_update_reason reason)
Definition: pbx.c:3558
static void hintdevice_destroy(void *obj)
Definition: pbx.c:560
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8544
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8488
static void pbx_destroy(struct ast_pbx *p)
Definition: pbx.c:1005
static int action_extensionstatelist(struct mansession *s, const struct message *m)
Definition: pbx.c:8369
static struct stasis_subscription * presence_state_sub
Subscription for presence state change events.
Definition: pbx.c:790
void ast_context_set_autohints(struct ast_context *con, int enabled)
Enable or disable autohints support on a context.
Definition: pbx.c:6251
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: pbx.c:703
static void print_autohint_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: pbx.c:8994
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:4937
static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app)
Definition: pbx.c:3391
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:8015
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:8567
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:4999
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:7308
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8572
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8675
int ast_async_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8811
static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
Definition: pbx.c:2847
static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: pbx.c:9004
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:8005
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:4756
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:1251
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8506
void wait_for_hangup(struct ast_channel *chan, const void *data)
Definition: pbx.c:8253
static char * parse_hint_presence(struct ast_str *hint_args)
Definition: pbx.c:3058
static const struct cfextension_states extension_states[]
static void presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: pbx.c:8319
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
Definition: pbx.c:741
static int ext_cmp(const char *left, const char *right)
Definition: pbx.c:2155
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:7092
int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
Add an ignorepat.
Definition: pbx.c:6856
static struct ast_threadstorage switch_data
Definition: pbx.c:243
static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
Definition: pbx.c:3102
static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
Definition: pbx.c:1131
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8582
static void destroy_pattern_tree(struct match_char *pattern_tree)
Definition: pbx.c:1808
int ast_context_add_include(const char *context, const char *include, const char *registrar)
Add a context include.
Definition: pbx.c:6685
static int publish_hint_remove(struct ast_hint *hint)
Publish a hint removed event
Definition: pbx.c:3941
static int extenpatternmatchnew
Definition: pbx.c:784
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
Map devstate to an extension state.
Definition: pbx.c:3027
static char * complete_show_dialplan_context(const char *line, const char *word, int pos, int state)
Definition: pbx.c:5419
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:7282
static void decrease_call_count(void)
Definition: pbx.c:4687
int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition: pbx.c:6829
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:7617
static const struct ast_datastore_info exception_store_info
Definition: pbx.c:2805
int ast_extension_state_add_destroy(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
Add watcher for extension states with destructor.
Definition: pbx.c:3838
STASIS_MESSAGE_TYPE_DEFN_LOCAL(hint_change_message_type)
static int ext_fluff_count(const char *exten)
Definition: pbx.c:2177
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition: pbx.c:4776
static struct ast_hashtab * contexts_table
Definition: pbx.c:797
static unsigned int hashtab_hash_extens(const void *obj)
Definition: pbx.c:761
static char * complete_core_show_hint(const char *line, const char *word, int pos, int state)
autocomplete for CLI command 'core show hint'
Definition: pbx.c:5240
#define BITS_PER
static int hint_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:8921
static struct ao2_container * autohints
Container for autohint contexts.
Definition: pbx.c:402
static int ext_cmp_exten_strlen(const char *str)
Definition: pbx.c:1832
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:2497
static unsigned int hashtab_hash_priority(const void *obj)
Definition: pbx.c:771
static int publish_hint_change(struct ast_hint *hint, struct ast_exten *ne)
Publish a hint changed event
Definition: pbx.c:4091
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8577
#define STATUS_NO_LABEL
Definition: pbx.c:2482
static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
Definition: pbx.c:7051
int ast_active_calls(void)
Retrieve the number of active calls.
Definition: pbx.c:4781
#define STATUS_NO_EXTENSION
Definition: pbx.c:2480
static ast_mutex_t maxcalllock
Definition: pbx.c:792
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: pbx.c:755
static int remove_hintdevice(struct ast_hint *hint)
Definition: pbx.c:539
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: pbx.c:2454
static int ext_cmp_exten(const char *left, const char *right)
Definition: pbx.c:1905
static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
Definition: pbx.c:6273
static int execute_state_callback(ast_state_cb_type cb, const char *context, const char *exten, void *data, enum ast_state_cb_update_reason reason, struct ast_hint *hint, struct ao2_container *device_state_info)
Definition: pbx.c:3271
static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
Definition: pbx.c:8785
static int autofallthrough
Definition: pbx.c:783
static void exception_store_free(void *data)
Definition: pbx.c:2798
static int hintdevice_hash_cb(const void *obj, const int flags)
Definition: pbx.c:417
static void context_table_create_autohints(struct ast_hashtab *table)
Definition: pbx.c:6311
static char * handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handle_show_hints: CLI support for listing registered dial plan hints
Definition: pbx.c:5177
static struct match_char * already_in_tree(struct match_char *current, char *pat, int is_pattern)
Definition: pbx.c:1417
static int ast_add_extension_nolock(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)
Definition: pbx.c:6929
static char * handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx.c:6105
static char * parse_hint_device(struct ast_str *hint_args)
Definition: pbx.c:3077
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:4196
static int compare_char(const void *a, const void *b)
Definition: pbx.c:694
static int hint_hash(const void *obj, const int flags)
Definition: pbx.c:8901
static int statecbs_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:8929
int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition: pbx.c:6869
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:6170
static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
Definition: pbx.c:6348
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:5473
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:8816
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:7941
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
Definition: pbx.c:4786
static void manager_dpsendack(struct mansession *s, const struct message *m)
Send ack once.
Definition: pbx.c:5827
static int stateid
Definition: pbx.c:812
static void create_match_char_tree(struct ast_context *con)
Definition: pbx.c:1785
static int autohint_hash_cb(const void *obj, const int flags)
Definition: pbx.c:475
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:4969
static ast_mutex_t conlock
Lock for the ast_context list.
Definition: pbx.c:805
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:1479
int raise_exception(struct ast_channel *chan, const char *reason, int priority)
Definition: pbx.c:2821
const char * ast_get_context_registrar(struct ast_context *c)
Definition: pbx.c:8552
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:6750
#define NEW_MATCHER_RECURSE
void pbx_set_overrideswitch(const char *newval)
Definition: pbx.c:4805
static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: pbx.c:8982
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8516
static void unload_pbx(void)
Definition: pbx.c:8434
static int increase_call_count(const struct ast_channel *c)
Increase call count for channel.
Definition: pbx.c:4638
int ast_extension_close(const char *pattern, const char *data, int needmore)
Definition: pbx.c:2447
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
Definition: pbx.c:6447
const char * ast_get_extension_label(struct ast_exten *exten)
Definition: pbx.c:8539
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4835
int pbx_set_extenpatternmatchnew(int newval)
Definition: pbx.c:4798
static void destroy_hint(void *obj)
Definition: pbx.c:3924
static struct ao2_container * hintdevices
Container for hint devices.
Definition: pbx.c:385
static void pbx_outgoing_destroy(void *obj)
Destructor for outgoing structure.
Definition: pbx.c:7603
static char * handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handle_show_hint: CLI support for listing registered dial plan hint
Definition: pbx.c:5276
static struct ast_threadstorage hintdevice_data
Definition: pbx.c:374
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:4880
static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: pbx.c:8971
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: pbx.c:8616
static char * overrideswitch
Definition: pbx.c:785
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8806
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
Definition: pbx.c:8529
static int ast_remove_hint(struct ast_exten *e)
Remove hint from extension.
Definition: pbx.c:3962
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
Definition: pbx.c:4226
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition: pbx.c:6705
static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
Check state of extension by using hints.
Definition: pbx.c:3134
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:5004
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:4211
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:4221
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:2442
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8246
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:7745
int ast_pbx_init(void)
Definition: pbx.c:9014
static void print_ext(struct ast_exten *e, char *buf, int buflen)
helper function to print an extension
Definition: pbx.c:5459
static char * handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Send ack once.
Definition: pbx.c:5771
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:1992
int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
Remove a switch.
Definition: pbx.c:4915
#define MAX_EXTENBUF_SIZE
Definition: pbx.c:1677
static void destroy_state_cb(void *doomed)
Definition: pbx.c:3735
static int hintdevice_remove_cb(void *obj, void *arg, void *data, int flags)
Definition: pbx.c:526
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4729
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:5649
static int extension_state_add_destroy(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data, int extended)
Definition: pbx.c:3748
static ast_mutex_t context_merge_lock
Lock to hold off restructuring of hints by ast_merge_contexts_and_delete.
Definition: pbx.c:810
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6966
static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
Definition: pbx.c:8857
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8493
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8896
#define STATUS_NO_CONTEXT
Definition: pbx.c:2479
static int matchcid(const char *cidpattern, const char *callerid)
Definition: pbx.c:2485
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:4206
int ast_extension_state_add_extended(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extended extension states.
Definition: pbx.c:3856
static struct match_char * add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
Definition: pbx.c:1678
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:6900
int ast_context_ignorepats_count(const struct ast_context *con)
Definition: pbx.c:8747
#define HASH_EXTENHINT_SIZE
Definition: pbx.c:380
int ast_extension_cmp(const char *a, const char *b)
Determine if one extension should match before another.
Definition: pbx.c:2212
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3877
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8709
static struct ast_custom_function testtime_function
Definition: pbx.c:8302
static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
Definition: pbx.c:443
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition: pbx.c:2238
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
Definition: pbx.c:748
static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app, struct ast_presence_state_message *presence_state)
Definition: pbx.c:3485
static struct ast_context * contexts
Definition: pbx.c:796
#define EXT_DATA_SIZE
Definition: pbx.c:231
const struct ast_sw * ast_walk_context_switches(const struct ast_context *con, const struct ast_sw *sw)
Definition: pbx.c:8630
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3844
static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, struct ast_pbx_args *args)
Definition: pbx.c:4327
static const char * get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
Definition: pbx.c:1533
#define STATUS_NO_PRIORITY
Definition: pbx.c:2481
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:8524
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:8592
int load_pbx(void)
Definition: pbx.c:8446
static struct ao2_container * alloc_device_state_info(void)
Definition: pbx.c:3097
static const char * candidate_exten_advance(const char *str)
Definition: pbx.c:1239
static struct ast_exten * ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
Definition: pbx.c:3018
static int find_hint_by_cb_id(void *obj, void *arg, int flags)
Find Hint by callback id.
Definition: pbx.c:3863
static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
Definition: pbx.c:3221
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: pbx.c:3605
static void device_state_info_dt(void *obj)
Definition: pbx.c:3090
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:4216
static struct ast_threadstorage extensionstate_buf
Definition: pbx.c:244
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:4158
static struct ast_cli_entry pbx_cli[]
Definition: pbx.c:6136
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8307
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:8757
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:5488
static struct stasis_subscription * device_state_sub
Subscription for device state change events.
Definition: pbx.c:788
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:4857
const struct ast_ignorepat * ast_walk_context_ignorepats(const struct ast_context *con, const struct ast_ignorepat *ip)
Definition: pbx.c:8714
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:3012
static void pbx_shutdown(void)
Definition: pbx.c:8941
const struct ast_ignorepat * ast_context_ignorepats_get(const struct ast_context *con, int idx)
Definition: pbx.c:8752
static struct ao2_container * hints
Definition: pbx.c:821
static int ext_cmp_pattern(const char *left, const char *right)
Definition: pbx.c:2107
static char * handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx.c:6077
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: pbx.c:8669
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:7291
static char * handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx.c:5704
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
Change hint for an extension.
Definition: pbx.c:4113
static int autohint_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:496
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:6994
static int hint_id_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:3910
static void destroy_exten(struct ast_exten *e)
Definition: pbx.c:4695
static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
add hintdevice structure and link it into the container.
Definition: pbx.c:572
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:6770
static struct ast_context * find_context(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4821
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:2890
static int ast_add_hint(struct ast_exten *e)
Add hint to hint list, check initial extension state.
Definition: pbx.c:3999
static unsigned int hashtab_hash_labels(const void *obj)
Definition: pbx.c:777
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8498
static struct ast_custom_function exception_function
Definition: pbx.c:2867
#define STATUS_SUCCESS
Definition: pbx.c:2483
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *exten)
Definition: pbx.c:8621
int ast_context_switches_count(const struct ast_context *con)
Definition: pbx.c:8659
#define NEW_MATCHER_CHK_MATCH
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8891
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:4176
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:4974
int pbx_set_autofallthrough(int newval)
Definition: pbx.c:4791
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8704
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:4300
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Check extension state for an extension by using hint.
Definition: pbx.c:3191
static void * pbx_thread(void *data)
Definition: pbx.c:4709
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:5836
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:7027
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
Definition: pbx.c:2429
static struct ast_exten * get_canmatch_exten(struct match_char *node)
Definition: pbx.c:1161
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8534
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
Definition: pbx.c:1438
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:8511
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:8562
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8557
static void get_device_state_causing_channels(struct ao2_container *c)
Definition: pbx.c:3317
static void __ast_internal_context_destroy(struct ast_context *con)
Definition: pbx.c:8040
static int ext_cmp_exten_partial(const char *left, const char *right)
Definition: pbx.c:1862
int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten, struct ao2_container **device_state_info)
Check extended extension state for an extension by using hint.
Definition: pbx.c:3197
#define INC_DST_OVERFLOW_CHECK
void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
Definition: pbx.c:4285
Core PBX routines and definitions.
ast_pbx_result
The result codes when starting the PBX on a channel with ast_pbx_start.
Definition: pbx.h:371
@ AST_PBX_FAILED
Definition: pbx.h:373
@ AST_PBX_CALL_LIMIT
Definition: pbx.h:374
@ AST_PBX_SUCCESS
Definition: pbx.h:372
int ast_thread_inhibit_escalations_swap(int inhibit)
Swap the current thread escalation inhibit setting.
@ AST_OUTGOING_WAIT_COMPLETE
Definition: pbx.h:1145
int(* ast_state_cb_type)(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Typedef for devicestate and hint callbacks.
Definition: pbx.h:112
#define AST_MAX_APP
Definition: pbx.h:40
@ 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:471
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
ast_extension_states
Extension states.
Definition: pbx.h:61
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63
const char * ast_get_ignorepat_registrar(const struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:47
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:157
#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.
ast_state_cb_update_reason
Definition: pbx.h:89
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91
@ AST_HINT_UPDATE_PRESENCE
Definition: pbx.h:93
#define PRIORITY_HINT
Definition: pbx.h:54
#define AST_PBX_GOTO_FAILED
Definition: pbx.h:42
void(* ast_state_cb_destroy_type)(int id, void *data)
Typedef for devicestate and hint callback removal indication callback.
Definition: pbx.h:115
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)
Definition: pbx_ignorepat.c:42
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
static char * registrar
Definition: pbx_ael.c:81
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
static struct ast_context * local_contexts
Definition: pbx_config.c:117
void ignorepat_free(struct ast_ignorepat *ip)
Definition: pbx_ignorepat.c:77
struct ast_ignorepat * ignorepat_alloc(const char *value, const char *registrar)
Definition: pbx_ignorepat.c:52
void include_free(struct ast_include *inc)
Definition: pbx_include.c:106
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:68
Presence state management.
struct stasis_topic * ast_presence_state_topic_all(void)
Get presence state topic.
ast_presence_state
Definition: presencestate.h:26
@ AST_PRESENCE_INVALID
Definition: presencestate.h:39
const char * ast_presence_state2str(enum ast_presence_state state)
Convert presence state to text string for output.
struct stasis_message_type * ast_presence_state_message_type(void)
Get presence state message type.
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ao2_container * container
Definition: res_fax.c:531
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1050
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1104
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1161
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1538
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
size_t 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
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
ast_app: A registered application
Definition: pbx_app.c:45
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:606
Structure for dial plan autohints.
Definition: pbx.c:407
char context[1]
Name of the context.
Definition: pbx.c:411
char * registrar
Name of the registrar.
Definition: pbx.c:409
Main Channel structure associated with a channel.
char exten[AST_MAX_EXTENSION]
const char * data
struct ast_party_dialed dialed
Dialed/Called information.
struct ast_flags flags
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:299
struct ast_sws alts
Definition: pbx.c:310
struct ast_exten * root
Definition: pbx.c:304
struct match_char * pattern_tree
Definition: pbx.c:306
int refcount
Definition: pbx.c:311
struct ast_ignorepats ignorepats
Definition: pbx.c:309
struct ast_includes includes
Definition: pbx.c:308
int autohints
Definition: pbx.c:312
const char * registrar
Definition: pbx.c:301
char data[]
Definition: pbx.c:319
struct ast_context * next
Definition: pbx.c:307
struct ast_hashtab * root_table
Definition: pbx.c:305
ast_rwlock_t lock
Definition: pbx.c:303
const char * name
Definition: pbx.c:300
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
char device_name[1]
Definition: pbx.h:99
enum ast_device_state device_state
Definition: pbx.h:97
The structure that contains device state.
Definition: devicestate.h:238
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246
You shouldn't care about the contents of this struct.
Definition: devicestate.h:228
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:252
const char * cidmatch_display
Definition: pbx.c:257
char * exten
Definition: pbx.c:253
struct ast_hashtab * peer_label_table
Definition: pbx.c:267
struct ast_hashtab * peer_table
Definition: pbx.c:266
char stuff[0]
Definition: pbx.c:272
const char * app
Definition: pbx.c:261
const char * registrar_file
Definition: pbx.c:269
struct ast_app * cached_app
Definition: pbx.c:262
char * name
Definition: pbx.c:254
const char * registrar
Definition: pbx.c:268
const char * cidmatch
Definition: pbx.c:256
int registrar_line
Definition: pbx.c:270
struct ast_context * parent
Definition: pbx.c:260
struct ast_exten * peer
Definition: pbx.c:265
void * data
Definition: pbx.c:263
struct ast_exten * next
Definition: pbx.c:271
int priority
Definition: pbx.c:258
void(* datad)(void *)
Definition: pbx.c:264
const char * label
Definition: pbx.c:259
int matchcid
Definition: pbx.c:255
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::@231 data
an iterator for traversing the buckets
Definition: hashtab.h:106
Structure for dial plan hints.
Definition: pbx.c:346
int laststate
Definition: pbx.c:357
struct ao2_container * callbacks
Definition: pbx.c:354
struct ast_hint::@382 devices
char exten_name[AST_MAX_EXTENSION]
Definition: pbx.c:365
struct ast_exten * exten
Hint extension.
Definition: pbx.c:353
int last_presence_state
Definition: pbx.c:360
char * last_presence_subtype
Definition: pbx.c:361
char context_name[AST_MAX_CONTEXT]
Definition: pbx.c:364
char * last_presence_message
Definition: pbx.c:362
Structure for dial plan hint devices.
Definition: pbx.c:391
char hintdevice[1]
Definition: pbx.c:398
struct ast_hint * hint
Hint this hintdevice belongs to.
Definition: pbx.c:396
ast_ignorepat: Ignore patterns in dial plan
Definition: pbx_ignorepat.c:37
const char pattern[0]
Definition: pbx_ignorepat.c:39
struct ast_ignorepat * next
Definition: extconf.c:2388
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
struct ast_include * next
Definition: extconf.c:2370
Connected Line/Party information.
Definition: channel.h:458
Options for ast_pbx_run()
Definition: pbx.h:408
Definition: pbx.h:215
int rtimeoutms
Definition: pbx.h:217
int dtimeoutms
Definition: pbx.h:216
Stasis message payload representing a presence state update.
enum ast_presence_state state
Structure for rwlock and tracking information.
Definition: lock.h:164
enum ast_state_cb_update_reason reason
Definition: pbx.h:103
struct ao2_container * device_state_info
Definition: pbx.h:105
ast_state_cb: An extension state notify register item
Definition: pbx.c:323
int extended
Definition: pbx.c:329
struct ast_state_cb::@381 entry
ast_state_cb_type change_cb
Definition: pbx.c:331
int id
Definition: pbx.c:325
void * data
Definition: pbx.c:327
ast_state_cb_destroy_type destroy_cb
Definition: pbx.c:333
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:167
ast_switch_f * exists
Definition: pbx.h:166
ast_switch_f * exec
Definition: pbx.h:168
ast_switch_f * matchmore
Definition: pbx.h:169
const char * name
Definition: pbx.h:163
Structure for variables, used for configurations and for channel variables.
int extension_state
Definition: pbx.c:627
const char *const text
Definition: pbx.c:628
Counters for the show dialplan manager command.
Definition: pbx.c:5449
int total_items
Definition: pbx.c:5450
int total_context
Definition: pbx.c:5451
int context_existence
Definition: pbx.c:5454
int total_exten
Definition: pbx.c:5452
int total_prio
Definition: pbx.c:5453
int extension_existence
Definition: pbx.c:5455
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:277
int deleted
Definition: pbx.c:279
int is_pattern
Definition: pbx.c:278
struct match_char * alt_char
Definition: pbx.c:281
int specificity
Definition: pbx.c:280
char x[1]
Definition: pbx.c:284
struct match_char * next_char
Definition: pbx.c:282
struct ast_exten * exten
Definition: pbx.c:283
Definition: test_heap.c:38
Number structure.
Definition: app_followme.c:157
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:1476
int specif
Definition: pbx.c:1474
const ast_string_field context
Definition: pbx.c:645
const ast_string_field exten
Definition: pbx.c:645
int priority
Definition: pbx.c:647
const ast_string_field reason
Definition: pbx.c:645
int stacklen
Definition: extconf.h:237
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:7579
int dial_res
Result of the dial operation when dialed is set.
Definition: pbx.c:7595
ast_cond_t cond
Condition for synchronous dialing.
Definition: pbx.c:7583
char app[AST_MAX_APP]
Application to execute.
Definition: pbx.c:7585
unsigned int in_separate_thread
Set if we've spawned a thread to do our work.
Definition: pbx.c:7599
struct ast_dial * dial
Dialing structure being used.
Definition: pbx.c:7581
unsigned int dialed
Set when dialing is completed.
Definition: pbx.c:7597
char exten[AST_MAX_EXTENSION]
Dialplan extension.
Definition: pbx.c:7591
char context[AST_MAX_CONTEXT]
Dialplan context.
Definition: pbx.c:7589
int priority
Dialplan priority.
Definition: pbx.c:7593
char * appdata
Application data to pass to application.
Definition: pbx.c:7587
int canmatch
Definition: pbx.c:292
int total_length
Definition: pbx.c:290
int total_specificity
Definition: pbx.c:289
char last_char
Definition: pbx.c:291
struct match_char * node
Definition: pbx.c:293
struct ast_exten * exten
Definition: pbx.c:295
struct ast_exten * canmatch_exten
Definition: pbx.c:294
int laststate
Definition: pbx.c:6262
char * exten
Definition: pbx.c:6260
struct store_hint::@383 callbacks
int last_presence_state
Definition: pbx.c:6263
struct store_hint::@384 list
char * last_presence_subtype
Definition: pbx.c:6264
char * context
Definition: pbx.c:6259
char data[0]
Definition: pbx.c:6268
char * last_presence_message
Definition: pbx.c:6265
const char * name
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
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
Definition: test_config.c:1463
const char * args
static struct test_val b
static struct test_val a
static struct test_val c
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
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
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
Definition: time.h:137
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#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:965
#define ast_assert(a)
Definition: utils.h:763
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:612
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:690
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_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
Definition: vector.h:449
#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(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:691
Asterisk XML Documentation API.