Asterisk - The Open Source Telephony Project GIT-master-754dea3
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 }
2947 if (ast_channel_exten(c) != exten)
2948 ast_channel_exten_set(c, exten);
2950 if (substitute) {
2951 pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
2952 }
2953 ast_debug(1, "Launching '%s'\n", app_name(app));
2954 if (VERBOSITY_ATLEAST(3)) {
2955 ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
2956 exten, context, priority,
2959 COLORIZE(COLOR_BRMAGENTA, 0, passdata),
2960 "in new stack");
2961 }
2962 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
2963 }
2964 } else if (q.swo) { /* not found here, but in another switch */
2965 if (found)
2966 *found = 1;
2968 if (matching_action) {
2969 return -1;
2970 } else {
2971 if (!q.swo->exec) {
2972 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
2973 return -1;
2974 }
2975 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
2976 }
2977 } else { /* not found anywhere, see what happened */
2979 /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
2980 switch (q.status) {
2981 case STATUS_NO_CONTEXT:
2982 if (!matching_action && !combined_find_spawn)
2983 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
2984 break;
2986 if (!matching_action && !combined_find_spawn)
2987 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
2988 break;
2989 case STATUS_NO_PRIORITY:
2990 if (!matching_action && !combined_find_spawn)
2991 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
2992 break;
2993 case STATUS_NO_LABEL:
2994 if (context && !combined_find_spawn)
2995 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", S_OR(label, ""), exten, S_OR(context, ""));
2996 break;
2997 default:
2998 ast_debug(1, "Shouldn't happen!\n");
2999 }
3000
3001 return (matching_action) ? 0 : -1;
3002 }
3003}
3004
3005/*! \brief Find hint for given extension in context */
3006static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
3007{
3008 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
3009 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
3010}
3011
3012static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
3013{
3014 struct ast_exten *e;
3018 return e;
3019}
3020
3022{
3023 switch (devstate) {
3024 case AST_DEVICE_ONHOLD:
3025 return AST_EXTENSION_ONHOLD;
3026 case AST_DEVICE_BUSY:
3027 return AST_EXTENSION_BUSY;
3028 case AST_DEVICE_UNKNOWN:
3031 case AST_DEVICE_INVALID:
3035 case AST_DEVICE_RINGING:
3036 return AST_EXTENSION_RINGING;
3037 case AST_DEVICE_INUSE:
3038 return AST_EXTENSION_INUSE;
3041 case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
3042 break;
3043 }
3044
3046}
3047
3048/*!
3049 * \internal
3050 * \brief Parse out the presence portion of the hint string
3051 */
3052static char *parse_hint_presence(struct ast_str *hint_args)
3053{
3054 char *copy = ast_strdupa(ast_str_buffer(hint_args));
3055 char *tmp = "";
3056
3057 if ((tmp = strrchr(copy, ','))) {
3058 *tmp = '\0';
3059 tmp++;
3060 } else {
3061 return NULL;
3062 }
3063 ast_str_set(&hint_args, 0, "%s", tmp);
3064 return ast_str_buffer(hint_args);
3065}
3066
3067/*!
3068 * \internal
3069 * \brief Parse out the device portion of the hint string
3070 */
3071static char *parse_hint_device(struct ast_str *hint_args)
3072{
3073 char *copy = ast_strdupa(ast_str_buffer(hint_args));
3074 char *tmp;
3075
3076 if ((tmp = strrchr(copy, ','))) {
3077 *tmp = '\0';
3078 }
3079
3080 ast_str_set(&hint_args, 0, "%s", copy);
3081 return ast_str_buffer(hint_args);
3082}
3083
3084static void device_state_info_dt(void *obj)
3085{
3086 struct ast_device_state_info *info = obj;
3087
3088 ao2_cleanup(info->causing_channel);
3089}
3090
3092{
3094}
3095
3096static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
3097{
3098 char *cur;
3099 char *rest;
3100 struct ast_devstate_aggregate agg;
3101
3102 /* One or more devices separated with a & character */
3103 rest = parse_hint_device(hint_app);
3104
3106 while ((cur = strsep(&rest, "&"))) {
3108
3110 if (device_state_info) {
3111 struct ast_device_state_info *obj;
3112
3113 obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
3114 /* if failed we cannot add this device */
3115 if (obj) {
3116 obj->device_state = state;
3117 strcpy(obj->device_name, cur);
3118 ao2_link(device_state_info, obj);
3119 ao2_ref(obj, -1);
3120 }
3121 }
3122 }
3123
3125}
3126
3127/*! \brief Check state of extension by using hints */
3128static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
3129{
3130 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
3131
3132 if (!e || !hint_app) {
3133 return -1;
3134 }
3135
3136 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
3137 return ast_extension_state3(hint_app, device_state_info);
3138}
3139
3140/*! \brief Return extension_state as string */
3141const char *ast_extension_state2str(int extension_state)
3142{
3143 int i;
3144
3145 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
3146 if (extension_states[i].extension_state == extension_state)
3147 return extension_states[i].text;
3148 }
3149 return "Unknown";
3150}
3151
3152/*!
3153 * \internal
3154 * \brief Check extension state for an extension by using hint
3155 */
3156static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
3157 struct ao2_container *device_state_info)
3158{
3159 struct ast_exten *e;
3160
3161 if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
3162 return -1; /* No hint, return -1 */
3163 }
3164
3165 if (e->exten[0] == '_') {
3166 /* Create this hint on-the-fly, we explicitly lock hints here to ensure the
3167 * same locking order as if this were done through configuration file - that is
3168 * hints is locked first and then (if needed) contexts is locked
3169 */
3170 ao2_lock(hints);
3172 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3173 e->registrar);
3175 if (!(e = ast_hint_extension(c, context, exten))) {
3176 /* Improbable, but not impossible */
3177 return -1;
3178 }
3179 }
3180
3181 return ast_extension_state2(e, device_state_info); /* Check all devices in the hint */
3182}
3183
3184/*! \brief Check extension state for an extension by using hint */
3185int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
3186{
3188}
3189
3190/*! \brief Check extended extension state for an extension by using hint */
3191int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
3192 struct ao2_container **device_state_info)
3193{
3194 struct ao2_container *container = NULL;
3195 int ret;
3196
3197 if (device_state_info) {
3199 }
3200
3202 if (ret < 0 && container) {
3203 ao2_ref(container, -1);
3204 container = NULL;
3205 }
3206
3207 if (device_state_info) {
3209 *device_state_info = container;
3210 }
3211
3212 return ret;
3213}
3214
3215static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
3216{
3217 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
3218 char *presence_provider;
3219 const char *app;
3220
3221 if (!e || !hint_app) {
3222 return -1;
3223 }
3224
3226 if (ast_strlen_zero(app)) {
3227 return -1;
3228 }
3229
3230 ast_str_set(&hint_app, 0, "%s", app);
3231 presence_provider = parse_hint_presence(hint_app);
3232
3233 if (ast_strlen_zero(presence_provider)) {
3234 /* No presence string in the hint */
3235 return 0;
3236 }
3237
3238 return ast_presence_state(presence_provider, subtype, message);
3239}
3240
3241int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
3242{
3243 struct ast_exten *e;
3244
3245 if (!(e = ast_hint_extension(c, context, exten))) { /* Do we have a hint for this extension ? */
3246 return -1; /* No hint, return -1 */
3247 }
3248
3249 if (e->exten[0] == '_') {
3250 /* Create this hint on-the-fly */
3251 ao2_lock(hints);
3253 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3254 e->registrar);
3256 if (!(e = ast_hint_extension(c, context, exten))) {
3257 /* Improbable, but not impossible */
3258 return -1;
3259 }
3260 }
3261
3262 return extension_presence_state_helper(e, subtype, message);
3263}
3264
3266 const char *context,
3267 const char *exten,
3268 void *data,
3269 enum ast_state_cb_update_reason reason,
3270 struct ast_hint *hint,
3271 struct ao2_container *device_state_info)
3272{
3273 int res = 0;
3274 struct ast_state_cb_info info = { 0, };
3275
3276 info.reason = reason;
3277
3278 /* Copy over current hint data */
3279 if (hint) {
3280 ao2_lock(hint);
3281 info.exten_state = hint->laststate;
3282 info.device_state_info = device_state_info;
3283 info.presence_state = hint->last_presence_state;
3284 if (!(ast_strlen_zero(hint->last_presence_subtype))) {
3285 info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
3286 } else {
3287 info.presence_subtype = "";
3288 }
3289 if (!(ast_strlen_zero(hint->last_presence_message))) {
3290 info.presence_message = ast_strdupa(hint->last_presence_message);
3291 } else {
3292 info.presence_message = "";
3293 }
3294 ao2_unlock(hint);
3295 } else {
3296 info.exten_state = AST_EXTENSION_REMOVED;
3297 }
3298
3299 res = cb(context, exten, &info, data);
3300
3301 return res;
3302}
3303
3304/*!
3305 * \internal
3306 * \brief Identify a channel for every device which is supposedly responsible for the device state.
3307 *
3308 * Especially when the device is ringing, the oldest ringing channel is chosen.
3309 * For all other cases the first encountered channel in the specific state is chosen.
3310 */
3312{
3313 struct ao2_iterator iter;
3315 struct ast_channel *chan;
3316
3317 if (!c || !ao2_container_count(c)) {
3318 return;
3319 }
3320 iter = ao2_iterator_init(c, 0);
3321 for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
3322 enum ast_channel_state search_state = 0; /* prevent false uninit warning */
3323 char match[AST_CHANNEL_NAME];
3324 struct ast_channel_iterator *chan_iter;
3325 struct timeval chantime = {0, }; /* prevent false uninit warning */
3326
3327 switch (info->device_state) {
3328 case AST_DEVICE_RINGING:
3330 /* find ringing channel */
3331 search_state = AST_STATE_RINGING;
3332 break;
3333 case AST_DEVICE_BUSY:
3334 /* find busy channel */
3335 search_state = AST_STATE_BUSY;
3336 break;
3337 case AST_DEVICE_ONHOLD:
3338 case AST_DEVICE_INUSE:
3339 /* find up channel */
3340 search_state = AST_STATE_UP;
3341 break;
3342 case AST_DEVICE_UNKNOWN:
3344 case AST_DEVICE_INVALID:
3346 case AST_DEVICE_TOTAL /* not a state */:
3347 /* no channels are of interest */
3348 continue;
3349 }
3350
3351 /* iterate over all channels of the device */
3352 snprintf(match, sizeof(match), "%s-", info->device_name);
3353 chan_iter = ast_channel_iterator_by_name_new(match, strlen(match));
3354 for (; (chan = ast_channel_iterator_next(chan_iter)); ast_channel_unref(chan)) {
3355 ast_channel_lock(chan);
3356 /* this channel's state doesn't match */
3357 if (search_state != ast_channel_state(chan)) {
3358 ast_channel_unlock(chan);
3359 continue;
3360 }
3361 /* any non-ringing channel will fit */
3362 if (search_state != AST_STATE_RINGING) {
3363 ast_channel_unlock(chan);
3364 info->causing_channel = chan; /* is kept ref'd! */
3365 break;
3366 }
3367 /* but we need the oldest ringing channel of the device to match with undirected pickup */
3368 if (!info->causing_channel) {
3369 chantime = ast_channel_creationtime(chan);
3370 ast_channel_ref(chan); /* must ref it! */
3371 info->causing_channel = chan;
3372 } else if (ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
3373 chantime = ast_channel_creationtime(chan);
3374 ast_channel_unref(info->causing_channel);
3375 ast_channel_ref(chan); /* must ref it! */
3376 info->causing_channel = chan;
3377 }
3378 ast_channel_unlock(chan);
3379 }
3381 }
3382 ao2_iterator_destroy(&iter);
3383}
3384
3385static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app)
3386{
3387 struct ao2_iterator cb_iter;
3388 struct ast_state_cb *state_cb;
3389 int state;
3390 int same_state;
3391 struct ao2_container *device_state_info;
3392 int first_extended_cb_call = 1;
3395
3396 ao2_lock(hint);
3397 if (!hint->exten) {
3398 /* The extension has already been destroyed */
3399 ao2_unlock(hint);
3400 return;
3401 }
3402
3403 /*
3404 * Save off strings in case the hint extension gets destroyed
3405 * while we are notifying the watchers.
3406 */
3409 sizeof(context_name));
3411 sizeof(exten_name));
3412 ast_str_set(hint_app, 0, "%s", ast_get_extension_app(hint->exten));
3413 ao2_unlock(hint);
3414
3415 /*
3416 * Get device state for this hint.
3417 *
3418 * NOTE: We cannot hold any locks while determining the hint
3419 * device state or notifying the watchers without causing a
3420 * deadlock. (conlock, hints, and hint)
3421 */
3422
3423 /* Make a container so state3 can fill it if we wish.
3424 * If that failed we simply do not provide the extended state info.
3425 */
3426 device_state_info = alloc_device_state_info();
3427
3428 state = ast_extension_state3(*hint_app, device_state_info);
3429 same_state = state == hint->laststate;
3430 if (same_state && (~state & AST_EXTENSION_RINGING)) {
3431 ao2_cleanup(device_state_info);
3432 return;
3433 }
3434
3435 /* Device state changed since last check - notify the watchers. */
3436 hint->laststate = state; /* record we saw the change */
3437
3438 /* For general callbacks */
3439 if (!same_state) {
3440 cb_iter = ao2_iterator_init(statecbs, 0);
3441 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3444 exten_name,
3445 state_cb->data,
3447 hint,
3448 NULL);
3449 }
3450 ao2_iterator_destroy(&cb_iter);
3451 }
3452
3453 /* For extension callbacks */
3454 /* extended callbacks are called when the state changed or when AST_STATE_RINGING is
3455 * included. Normal callbacks are only called when the state changed.
3456 */
3457 cb_iter = ao2_iterator_init(hint->callbacks, 0);
3458 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3459 if (state_cb->extended && first_extended_cb_call) {
3460 /* Fill detailed device_state_info now that we know it is used by extd. callback */
3461 first_extended_cb_call = 0;
3462 get_device_state_causing_channels(device_state_info);
3463 }
3464 if (state_cb->extended || !same_state) {
3467 exten_name,
3468 state_cb->data,
3470 hint,
3471 state_cb->extended ? device_state_info : NULL);
3472 }
3473 }
3474 ao2_iterator_destroy(&cb_iter);
3475
3476 ao2_cleanup(device_state_info);
3477}
3478
3479static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app,
3480 struct ast_presence_state_message *presence_state)
3481{
3482 struct ao2_iterator cb_iter;
3483 struct ast_state_cb *state_cb;
3486
3487 ao2_lock(hint);
3488 if (!hint->exten) {
3489 /* The extension has already been destroyed */
3490 ao2_unlock(hint);
3491 return;
3492 }
3493
3494 /*
3495 * Save off strings in case the hint extension gets destroyed
3496 * while we are notifying the watchers.
3497 */
3500 sizeof(context_name));
3502 sizeof(exten_name));
3503 ast_str_set(hint_app, 0, "%s", ast_get_extension_app(hint->exten));
3504 ao2_unlock(hint);
3505
3506 /* Check to see if update is necessary */
3507 if ((hint->last_presence_state == presence_state->state) &&
3508 ((hint->last_presence_subtype && presence_state->subtype &&
3509 !strcmp(hint->last_presence_subtype, presence_state->subtype)) ||
3510 (!hint->last_presence_subtype && !presence_state->subtype)) &&
3511 ((hint->last_presence_message && presence_state->message &&
3512 !strcmp(hint->last_presence_message, presence_state->message)) ||
3513 (!hint->last_presence_message && !presence_state->message))) {
3514 /* this update is the same as the last, do nothing */
3515 return;
3516 }
3517
3518 /* update new values */
3521 hint->last_presence_state = presence_state->state;
3522 hint->last_presence_subtype = presence_state->subtype ? ast_strdup(presence_state->subtype) : NULL;
3523 hint->last_presence_message = presence_state->message ? ast_strdup(presence_state->message) : NULL;
3524
3525 /* For general callbacks */
3526 cb_iter = ao2_iterator_init(statecbs, 0);
3527 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3530 exten_name,
3531 state_cb->data,
3533 hint,
3534 NULL);
3535 }
3536 ao2_iterator_destroy(&cb_iter);
3537
3538 /* For extension callbacks */
3539 cb_iter = ao2_iterator_init(hint->callbacks, 0);
3540 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
3543 exten_name,
3544 state_cb->data,
3546 hint,
3547 NULL);
3548 }
3549 ao2_iterator_destroy(&cb_iter);
3550}
3551
3553{
3554 struct ast_hint *hint;
3555 struct ast_str *hint_app;
3556
3557 if (hint_change_message_type() != stasis_message_type(msg)) {
3558 return 0;
3559 }
3560
3561 if (!(hint_app = ast_str_create(1024))) {
3562 return -1;
3563 }
3564
3565 hint = stasis_message_data(msg);
3566
3567 switch (reason) {
3569 device_state_notify_callbacks(hint, &hint_app);
3570 break;
3572 {
3573 char *presence_subtype = NULL;
3574 char *presence_message = NULL;
3575 int state;
3576
3578 hint->exten, &presence_subtype, &presence_message);
3579 {
3580 struct ast_presence_state_message presence_state = {
3582 .subtype = presence_subtype,
3583 .message = presence_message
3584 };
3585
3586 presence_state_notify_callbacks(hint, &hint_app, &presence_state);
3587 }
3588
3589 ast_free(presence_subtype);
3590 ast_free(presence_message);
3591 }
3592 break;
3593 }
3594
3595 ast_free(hint_app);
3596 return 1;
3597}
3598
3599static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
3600{
3601 struct ast_device_state_message *dev_state;
3602 struct ast_str *hint_app;
3603 struct ast_hintdevice *device;
3604 struct ast_hintdevice *cmpdevice;
3605 struct ao2_iterator *dev_iter;
3606 struct ao2_iterator auto_iter;
3607 struct ast_autohint *autohint;
3608 char *virtual_device;
3609 char *type;
3610 char *device_name;
3611
3613 return;
3614 }
3615
3616 if (hint_remove_message_type() == stasis_message_type(msg)) {
3617 /* The extension has already been destroyed */
3618 struct ast_state_cb *state_cb;
3619 struct ao2_iterator cb_iter;
3620 struct ast_hint *hint = stasis_message_data(msg);
3621
3622 ao2_lock(hint);
3624 ao2_unlock(hint);
3625
3626 cb_iter = ao2_iterator_init(hint->callbacks, 0);
3627 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
3629 hint->context_name,
3630 hint->exten_name,
3631 state_cb->data,
3633 hint,
3634 NULL);
3635 }
3636 ao2_iterator_destroy(&cb_iter);
3637 return;
3638 }
3639
3641 return;
3642 }
3643
3644 dev_state = stasis_message_data(msg);
3645 if (dev_state->eid) {
3646 /* ignore non-aggregate states */
3647 return;
3648 }
3649
3651 /* There are no hints monitoring devices. */
3652 return;
3653 }
3654
3655 hint_app = ast_str_create(1024);
3656 if (!hint_app) {
3657 return;
3658 }
3659
3660 cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(dev_state->device));
3661 strcpy(cmpdevice->hintdevice, dev_state->device);
3662
3663 ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
3664
3665 /* Initially we find all hints for the device and notify them */
3666 dev_iter = ao2_t_callback(hintdevices,
3669 cmpdevice,
3670 "find devices in container");
3671 if (dev_iter) {
3672 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
3673 if (device->hint) {
3674 device_state_notify_callbacks(device->hint, &hint_app);
3675 }
3676 }
3677 ao2_iterator_destroy(dev_iter);
3678 }
3679
3680 /* Second stage we look for any autohint contexts and if the device is not already in the hints
3681 * we create it.
3682 */
3683 type = ast_strdupa(dev_state->device);
3684 if (ast_strlen_zero(type)) {
3685 goto end;
3686 }
3687
3688 /* Determine if this is a virtual/custom device or a real device */
3689 virtual_device = strchr(type, ':');
3690 device_name = strchr(type, '/');
3691 if (virtual_device && (!device_name || (virtual_device < device_name))) {
3692 device_name = virtual_device;
3693 }
3694
3695 /* Invalid device state name - not a virtual/custom device and not a real device */
3696 if (ast_strlen_zero(device_name)) {
3697 goto end;
3698 }
3699
3700 *device_name++ = '\0';
3701
3702 auto_iter = ao2_iterator_init(autohints, 0);
3703 for (; (autohint = ao2_iterator_next(&auto_iter)); ao2_t_ref(autohint, -1, "Next autohint")) {
3704 if (ast_get_hint(NULL, 0, NULL, 0, NULL, autohint->context, device_name)) {
3705 continue;
3706 }
3707
3708 /* The device has no hint in the context referenced by this autohint so create one */
3709 ast_add_extension(autohint->context, 0, device_name,
3710 PRIORITY_HINT, NULL, NULL, dev_state->device,
3711 ast_strdup(dev_state->device), ast_free_ptr, autohint->registrar);
3712
3713 /* Since this hint was just created there are no watchers, so we don't need to notify anyone */
3714 }
3715 ao2_iterator_destroy(&auto_iter);
3716
3717end:
3719 ast_free(hint_app);
3720 return;
3721}
3722
3723/*!
3724 * \internal
3725 * \brief Destroy the given state callback object.
3726 *
3727 * \param doomed State callback to destroy.
3728 */
3729static void destroy_state_cb(void *doomed)
3730{
3731 struct ast_state_cb *state_cb = doomed;
3732
3733 if (state_cb->destroy_cb) {
3734 state_cb->destroy_cb(state_cb->id, state_cb->data);
3735 }
3736}
3737
3738/*!
3739 * \internal
3740 * \brief Add watcher for extension states with destructor
3741 */
3742static int extension_state_add_destroy(const char *context, const char *exten,
3744{
3745 struct ast_hint *hint;
3746 struct ast_state_cb *state_cb;
3747 struct ast_exten *e;
3748 int id;
3749
3750 /* If there's no context and extension: add callback to statecbs list */
3751 if (!context && !exten) {
3752 /* Prevent multiple adds from adding the same change_cb at the same time. */
3754
3755 /* Remove any existing change_cb. */
3756 ao2_find(statecbs, change_cb, OBJ_UNLINK | OBJ_NODATA);
3757
3758 /* Now insert the change_cb */
3759 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
3761 return -1;
3762 }
3763 state_cb->id = 0;
3764 state_cb->change_cb = change_cb;
3765 state_cb->destroy_cb = destroy_cb;
3766 state_cb->data = data;
3767 state_cb->extended = extended;
3768 ao2_link(statecbs, state_cb);
3769
3770 ao2_ref(state_cb, -1);
3772 return 0;
3773 }
3774
3775 if (!context || !exten)
3776 return -1;
3777
3778 /* This callback type is for only one hint, so get the hint */
3780 if (!e) {
3781 return -1;
3782 }
3783
3784 /* If this is a pattern, dynamically create a new extension for this
3785 * particular match. Note that this will only happen once for each
3786 * individual extension, because the pattern will no longer match first.
3787 */
3788 if (e->exten[0] == '_') {
3789 ao2_lock(hints);
3791 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
3792 e->registrar);
3795 if (!e || e->exten[0] == '_') {
3796 return -1;
3797 }
3798 }
3799
3800 /* Find the hint in the hints container */
3801 ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
3802 hint = ao2_find(hints, e, 0);
3803 if (!hint) {
3805 return -1;
3806 }
3807
3808 /* Now insert the callback in the callback list */
3809 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
3810 ao2_ref(hint, -1);
3812 return -1;
3813 }
3814 do {
3815 id = stateid++; /* Unique ID for this callback */
3816 /* Do not allow id to ever be -1 or 0. */
3817 } while (id == -1 || id == 0);
3818 state_cb->id = id;
3819 state_cb->change_cb = change_cb; /* Pointer to callback routine */
3820 state_cb->destroy_cb = destroy_cb;
3821 state_cb->data = data; /* Data for the callback */
3822 state_cb->extended = extended;
3823 ao2_link(hint->callbacks, state_cb);
3824
3825 ao2_ref(state_cb, -1);
3826 ao2_ref(hint, -1);
3828
3829 return id;
3830}
3831
3832int ast_extension_state_add_destroy(const char *context, const char *exten,
3833 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
3834{
3835 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
3836}
3837
3838int ast_extension_state_add(const char *context, const char *exten,
3839 ast_state_cb_type change_cb, void *data)
3840{
3841 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
3842}
3843
3845 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
3846{
3847 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
3848}
3849
3851 ast_state_cb_type change_cb, void *data)
3852{
3853 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
3854}
3855
3856/*! \brief Find Hint by callback id */
3857static int find_hint_by_cb_id(void *obj, void *arg, int flags)
3858{
3859 struct ast_state_cb *state_cb;
3860 const struct ast_hint *hint = obj;
3861 int *id = arg;
3862
3863 if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
3864 ao2_ref(state_cb, -1);
3865 return CMP_MATCH | CMP_STOP;
3866 }
3867
3868 return 0;
3869}
3870
3872{
3873 struct ast_state_cb *p_cur;
3874 int ret = -1;
3875
3876 if (!id) { /* id == 0 is a callback without extension */
3877 if (!change_cb) {
3878 return ret;
3879 }
3881 if (p_cur) {
3882 ret = 0;
3883 ao2_ref(p_cur, -1);
3884 }
3885 } else { /* callback with extension, find the callback based on ID */
3886 struct ast_hint *hint;
3887
3888 ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
3889 hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
3890 if (hint) {
3891 p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
3892 if (p_cur) {
3893 ret = 0;
3894 ao2_ref(p_cur, -1);
3895 }
3896 ao2_ref(hint, -1);
3897 }
3899 }
3900
3901 return ret;
3902}
3903
3904static int hint_id_cmp(void *obj, void *arg, int flags)
3905{
3906 const struct ast_state_cb *cb = obj;
3907 int *id = arg;
3908
3909 return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
3910}
3911
3912/*!
3913 * \internal
3914 * \brief Destroy the given hint object.
3915 *
3916 * \param obj Hint to destroy.
3917 */
3918static void destroy_hint(void *obj)
3919{
3920 struct ast_hint *hint = obj;
3921 int i;
3922
3923 ao2_cleanup(hint->callbacks);
3924
3925 for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
3926 char *device = AST_VECTOR_GET(&hint->devices, i);
3927 ast_free(device);
3928 }
3929 AST_VECTOR_FREE(&hint->devices);
3932}
3933
3934/*! \brief Publish a hint removed event */
3935static int publish_hint_remove(struct ast_hint *hint)
3936{
3937 struct stasis_message *message;
3938
3939 if (!hint_remove_message_type()) {
3940 return -1;
3941 }
3942
3943 if (!(message = stasis_message_create(hint_remove_message_type(), hint))) {
3944 ao2_ref(hint, -1);
3945 return -1;
3946 }
3947
3949
3950 ao2_ref(message, -1);
3951
3952 return 0;
3953}
3954
3955/*! \brief Remove hint from extension */
3956static int ast_remove_hint(struct ast_exten *e)
3957{
3958 /* Cleanup the Notifys if hint is removed */
3959 struct ast_hint *hint;
3960
3961 if (!e) {
3962 return -1;
3963 }
3964
3965 hint = ao2_find(hints, e, OBJ_UNLINK);
3966 if (!hint) {
3967 return -1;
3968 }
3969
3970 remove_hintdevice(hint);
3971
3972 /*
3973 * The extension is being destroyed so we must save some
3974 * information to notify that the extension is deactivated.
3975 */
3976 ao2_lock(hint);
3979 sizeof(hint->context_name));
3981 sizeof(hint->exten_name));
3982 hint->exten = NULL;
3983 ao2_unlock(hint);
3984
3985 publish_hint_remove(hint);
3986
3987 ao2_ref(hint, -1);
3988
3989 return 0;
3990}
3991
3992/*! \brief Add hint to hint list, check initial extension state */
3993static int ast_add_hint(struct ast_exten *e)
3994{
3995 struct ast_hint *hint_new;
3996 struct ast_hint *hint_found;
3997 char *message = NULL;
3998 char *subtype = NULL;
3999 int presence_state;
4000
4001 if (!e) {
4002 return -1;
4003 }
4004
4005 /*
4006 * We must create the hint we wish to add before determining if
4007 * it is already in the hints container to avoid possible
4008 * deadlock when getting the current extension state.
4009 */
4010 hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
4011 if (!hint_new) {
4012 return -1;
4013 }
4014 AST_VECTOR_INIT(&hint_new->devices, 8);
4015
4016 /* Initialize new hint. */
4018 if (!hint_new->callbacks) {
4019 ao2_ref(hint_new, -1);
4020 return -1;
4021 }
4022 hint_new->exten = e;
4023 if (strstr(e->app, "${") && e->exten[0] == '_') {
4024 /* The hint is dynamic and hasn't been evaluated yet */
4025 hint_new->laststate = AST_DEVICE_INVALID;
4027 } else {
4028 hint_new->laststate = ast_extension_state2(e, NULL);
4029 if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
4030 hint_new->last_presence_state = presence_state;
4031 hint_new->last_presence_subtype = subtype;
4032 hint_new->last_presence_message = message;
4033 }
4034 }
4035
4036 /* Prevent multiple add hints from adding the same hint at the same time. */
4037 ao2_lock(hints);
4038
4039 /* Search if hint exists, do nothing */
4040 hint_found = ao2_find(hints, e, 0);
4041 if (hint_found) {
4042 ao2_ref(hint_found, -1);
4044 ao2_ref(hint_new, -1);
4045 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
4047 return -1;
4048 }
4049
4050 /* Add new hint to the hints container */
4051 ast_debug(2, "HINTS: Adding hint %s: %s\n",
4053 ao2_link(hints, hint_new);
4054 if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
4055 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4058 }
4059
4060 /* if not dynamic */
4061 if (!(strstr(e->app, "${") && e->exten[0] == '_')) {
4062 struct ast_state_cb *state_cb;
4063 struct ao2_iterator cb_iter;
4064
4065 /* For general callbacks */
4066 cb_iter = ao2_iterator_init(statecbs, 0);
4067 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
4071 state_cb->data,
4073 hint_new,
4074 NULL);
4075 }
4076 ao2_iterator_destroy(&cb_iter);
4077 }
4079 ao2_ref(hint_new, -1);
4080
4081 return 0;
4082}
4083
4084/*! \brief Publish a hint changed event */
4085static int publish_hint_change(struct ast_hint *hint, struct ast_exten *ne)
4086{
4087 struct stasis_message *message;
4088
4089 if (!hint_change_message_type()) {
4090 return -1;
4091 }
4092
4093 if (!(message = stasis_message_create(hint_change_message_type(), hint))) {
4094 ao2_ref(hint, -1);
4095 return -1;
4096 }
4097
4100
4101 ao2_ref(message, -1);
4102
4103 return 0;
4104}
4105
4106/*! \brief Change hint for an extension */
4107static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
4108{
4109 struct ast_hint *hint;
4110
4111 if (!oe || !ne) {
4112 return -1;
4113 }
4114
4115 ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
4116
4117 /*
4118 * Unlink the hint from the hints container as the extension
4119 * name (which is the hash value) could change.
4120 */
4121 hint = ao2_find(hints, oe, OBJ_UNLINK);
4122 if (!hint) {
4125 return -1;
4126 }
4127
4128 remove_hintdevice(hint);
4129
4130 /* Update the hint and put it back in the hints container. */
4131 ao2_lock(hint);
4132 hint->exten = ne;
4133
4134 ao2_unlock(hint);
4135
4136 ao2_link(hints, hint);
4137 if (add_hintdevice(hint, ast_get_extension_app(ne))) {
4138 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
4141 }
4143
4144 publish_hint_change(hint, ne);
4145
4146 ao2_ref(hint, -1);
4147
4148 return 0;
4149}
4150
4151/*! \brief Get hint for channel */
4152int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
4153{
4155
4156 if (e) {
4157 if (hint)
4158 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
4159 if (name) {
4160 const char *tmp = ast_get_extension_app_data(e);
4161 if (tmp)
4162 ast_copy_string(name, tmp, namesize);
4163 }
4164 return -1;
4165 }
4166 return 0;
4167}
4168
4169/*! \brief Get hint for channel */
4170int 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)
4171{
4173
4174 if (!e) {
4175 return 0;
4176 }
4177
4178 if (hint) {
4179 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
4180 }
4181 if (name) {
4182 const char *tmp = ast_get_extension_app_data(e);
4183 if (tmp) {
4184 ast_str_set(name, namesize, "%s", tmp);
4185 }
4186 }
4187 return -1;
4188}
4189
4190int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
4191{
4192 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
4193}
4194
4195int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
4196{
4197 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
4198}
4199
4200int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
4201{
4202 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
4203}
4204
4205int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
4206{
4207 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
4208}
4209
4210int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
4211{
4212 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
4213}
4214
4215int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
4216{
4217 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
4218}
4219
4220void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
4221{
4222 int autoloopflag;
4223 int found;
4224 int spawn_error;
4225
4226 ast_channel_lock(chan);
4227
4228 /*
4229 * Make sure that the channel is marked as hungup since we are
4230 * going to run the h exten on it.
4231 */
4233
4234 /* Set h exten location */
4235 if (context != ast_channel_context(chan)) {
4237 }
4238 ast_channel_exten_set(chan, "h");
4239 ast_channel_priority_set(chan, 1);
4240
4241 /* Save autoloop flag */
4244 ast_channel_unlock(chan);
4245
4246 for (;;) {
4247 spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
4249 S_COR(ast_channel_caller(chan)->id.number.valid,
4250 ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
4251
4252 ast_channel_lock(chan);
4253 if (spawn_error) {
4254 /* The code after the loop needs the channel locked. */
4255 break;
4256 }
4258 ast_channel_unlock(chan);
4259 }
4260 if (found && spawn_error) {
4261 /* Something bad happened, or a hangup has been requested. */
4262 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
4265 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
4268 }
4269
4270 /* An "h" exten has been run, so indicate that one has been run. */
4272
4273 /* Restore autoloop flag */
4275 ast_channel_unlock(chan);
4276}
4277
4278/*! helper function to set extension and priority */
4279void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
4280{
4285}
4286
4287/*!
4288 * \brief collect digits from the channel into the buffer.
4289 * \param c, buf, buflen, pos
4290 * \param waittime is in milliseconds
4291 * \retval 0 on timeout or done.
4292 * \retval -1 on error.
4293*/
4294static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
4295{
4296 int digit;
4297
4298 buf[pos] = '\0'; /* make sure it is properly terminated */
4300 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4301 /* As long as we're willing to wait, and as long as it's not defined,
4302 keep reading digits until we can't possibly get a right answer anymore. */
4303 digit = ast_waitfordigit(c, waittime);
4306 } else {
4307 if (!digit) /* No entry */
4308 break;
4309 if (digit < 0) /* Error, maybe a hangup */
4310 return -1;
4311 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
4312 buf[pos++] = digit;
4313 buf[pos] = '\0';
4314 }
4315 waittime = ast_channel_pbx(c)->dtimeoutms;
4316 }
4317 }
4318 return 0;
4319}
4320
4322 struct ast_pbx_args *args)
4323{
4324 int found = 0; /* set if we find at least one match */
4325 int res = 0;
4326 int autoloopflag;
4327 int error = 0; /* set an error conditions */
4328 struct ast_pbx *pbx;
4329 ast_callid callid;
4330
4331 /* A little initial setup here */
4332 if (ast_channel_pbx(c)) {
4333 ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
4334 /* XXX and now what ? */
4336 }
4337 if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
4338 return AST_PBX_FAILED;
4339 }
4340
4342 /* If the thread isn't already associated with a callid, we should create that association. */
4343 if (!callid) {
4344 /* Associate new PBX thread with the channel call id if it is available.
4345 * If not, create a new one instead.
4346 */
4347 callid = ast_channel_callid(c);
4348 if (!callid) {
4349 callid = ast_create_callid();
4350 if (callid) {
4352 ast_channel_callid_set(c, callid);
4354 }
4355 }
4357 callid = 0;
4358 }
4359
4360 ast_channel_pbx_set(c, pbx);
4361 /* Set reasonable defaults */
4362 ast_channel_pbx(c)->rtimeoutms = 10000;
4363 ast_channel_pbx(c)->dtimeoutms = 5000;
4364
4366 autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
4369
4371 /* If not successful fall back to 's' - but only if there is no given exten */
4372 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));
4373 /* XXX the original code used the existing priority in the call to
4374 * ast_exists_extension(), and reset it to 1 afterwards.
4375 * I believe the correct thing is to set it to 1 immediately.
4376 */
4377 set_ext_pri(c, "s", 1);
4378 }
4379
4380 for (;;) {
4381 char dst_exten[256]; /* buffer to accumulate digits */
4382 int pos = 0; /* XXX should check bounds */
4383 int digit = 0;
4384 int invalid = 0;
4385 int timeout = 0;
4386
4387 /* No digits pressed yet */
4388 dst_exten[pos] = '\0';
4389
4390 /* loop on priorities in this context/exten */
4393 &found, 1))) {
4394
4395 if (!ast_check_hangup(c)) {
4397 continue;
4398 }
4399
4400 /* Check softhangup flags. */
4403 continue;
4404 }
4407 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4408 set_ext_pri(c, "T", 1);
4409 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4412 continue;
4413 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4414 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4415 raise_exception(c, "ABSOLUTETIMEOUT", 1);
4416 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4419 continue;
4420 }
4421
4422 /* Call timed out with no special extension to jump to. */
4423 error = 1;
4424 break;
4425 }
4426 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
4428 error = 1;
4429 break;
4430 } /* end while - from here on we can use 'break' to go out */
4431 if (found && res) {
4432 /* Something bad happened, or a hangup has been requested. */
4433 if (strchr("0123456789ABCDEF*#", res)) {
4434 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
4435 pos = 0;
4436 dst_exten[pos++] = digit = res;
4437 dst_exten[pos] = '\0';
4438 } else if (res == AST_PBX_INCOMPLETE) {
4439 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));
4440 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));
4441
4442 /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
4444 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4445 invalid = 1;
4446 } else {
4447 ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
4448 digit = 1;
4449 pos = strlen(dst_exten);
4450 }
4451 } else {
4452 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));
4453 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));
4454
4455 if ((res == AST_PBX_ERROR)
4457 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4458 /* if we are already on the 'e' exten, don't jump to it again */
4459 if (!strcmp(ast_channel_exten(c), "e")) {
4460 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));
4461 error = 1;
4462 } else {
4463 raise_exception(c, "ERROR", 1);
4464 continue;
4465 }
4466 }
4467
4470 continue;
4471 }
4474 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4475 set_ext_pri(c, "T", 1);
4476 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4479 continue;
4480 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4481 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4482 raise_exception(c, "ABSOLUTETIMEOUT", 1);
4483 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
4486 continue;
4487 }
4488 /* Call timed out with no special extension to jump to. */
4489 }
4490 error = 1;
4491 break;
4492 }
4493 }
4494 if (error)
4495 break;
4496
4497 /*!\note
4498 * We get here on a failure of some kind: non-existing extension or
4499 * hangup. We have options, here. We can either catch the failure
4500 * and continue, or we can drop out entirely. */
4501
4502 if (invalid
4503 || (ast_strlen_zero(dst_exten) &&
4505 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
4506 /*!\note
4507 * If there is no match at priority 1, it is not a valid extension anymore.
4508 * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
4509 * neither exist.
4510 */
4512 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4513 ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
4515 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
4516 set_ext_pri(c, "i", 1);
4517 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4518 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4519 raise_exception(c, "INVALID", 1);
4520 } else {
4521 ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
4523 error = 1; /* we know what to do with it */
4524 break;
4525 }
4527 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
4529 } else { /* keypress received, get more digits for a full extension */
4530 int waittime = 0;
4531 if (digit)
4532 waittime = ast_channel_pbx(c)->dtimeoutms;
4533 else if (!autofallthrough)
4534 waittime = ast_channel_pbx(c)->rtimeoutms;
4535 if (!waittime) {
4536 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
4537 if (!status)
4538 status = "UNKNOWN";
4539 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
4540 if (!strcasecmp(status, "CONGESTION"))
4541 res = indicate_congestion(c, "10");
4542 else if (!strcasecmp(status, "CHANUNAVAIL"))
4543 res = indicate_congestion(c, "10");
4544 else if (!strcasecmp(status, "BUSY"))
4545 res = indicate_busy(c, "10");
4546 error = 1; /* XXX disable message */
4547 break; /* exit from the 'for' loop */
4548 }
4549
4550 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
4551 break;
4552 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
4553 timeout = 1;
4554 if (!timeout
4555 && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
4556 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) { /* Prepare the next cycle */
4557 set_ext_pri(c, dst_exten, 1);
4558 } else {
4559 /* No such extension */
4560 if (!timeout && !ast_strlen_zero(dst_exten)) {
4561 /* An invalid extension */
4563 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4564 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
4565 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
4566 set_ext_pri(c, "i", 1);
4567 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4568 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4569 raise_exception(c, "INVALID", 1);
4570 } else {
4572 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
4573 dst_exten, ast_channel_context(c));
4574 found = 1; /* XXX disable message */
4575 break;
4576 }
4577 } else {
4578 /* A simple timeout */
4580 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4581 ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
4582 set_ext_pri(c, "t", 1);
4583 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
4584 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
4585 raise_exception(c, "RESPONSETIMEOUT", 1);
4586 } else {
4588 "Timeout, but no rule 't' or 'e' in context '%s'\n",
4590 found = 1; /* XXX disable message */
4591 break;
4592 }
4593 }
4594 }
4595 }
4596 }
4597
4598 if (!found && !error) {
4599 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
4600 }
4601
4602 if (!args || !args->no_hangup_chan) {
4606 S_COR(ast_channel_caller(c)->id.number.valid,
4607 ast_channel_caller(c)->id.number.str, NULL))) {
4609 }
4611 }
4612
4615 ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
4619
4620 if (!args || !args->no_hangup_chan) {
4621 ast_hangup(c);
4622 }
4623
4624 return AST_PBX_SUCCESS;
4625}
4626
4627/*!
4628 * \brief Increase call count for channel
4629 * \retval 0 on success
4630 * \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached
4631*/
4632static int increase_call_count(const struct ast_channel *c)
4633{
4634 int failed = 0;
4635 double curloadavg;
4636#if defined(HAVE_SYSINFO)
4637 struct sysinfo sys_info;
4638#endif
4639
4641 if (ast_option_maxcalls) {
4643 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", ast_option_maxcalls, ast_channel_name(c));
4644 failed = -1;
4645 }
4646 }
4647 if (ast_option_maxload) {
4648 getloadavg(&curloadavg, 1);
4649 if (curloadavg >= ast_option_maxload) {
4650 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", ast_option_maxload, ast_channel_name(c), curloadavg);
4651 failed = -1;
4652 }
4653 }
4654#if defined(HAVE_SYSINFO)
4655 if (option_minmemfree) {
4656 /* Make sure that the free system memory is above the configured low watermark */
4657 if (!sysinfo(&sys_info)) {
4658 /* Convert the amount of available RAM from mem_units to MB. The calculation
4659 * was done this way to avoid overflow problems */
4660 uint64_t curfreemem = sys_info.freeram + sys_info.bufferram;
4661 curfreemem *= sys_info.mem_unit;
4662 curfreemem /= 1024 * 1024;
4663 if (curfreemem < option_minmemfree) {
4664 ast_log(LOG_WARNING, "Available system memory (~%" PRIu64 "MB) is below the configured low watermark (%ldMB)\n",
4665 curfreemem, option_minmemfree);
4666 failed = -1;
4667 }
4668 }
4669 }
4670#endif
4671
4672 if (!failed) {
4673 countcalls++;
4674 totalcalls++;
4675 }
4677
4678 return failed;
4679}
4680
4681static void decrease_call_count(void)
4682{
4684 if (countcalls > 0)
4685 countcalls--;
4687}
4688
4689static void destroy_exten(struct ast_exten *e)
4690{
4691 if (e->priority == PRIORITY_HINT)
4692 ast_remove_hint(e);
4693
4694 if (e->peer_table)
4696 if (e->peer_label_table)
4698 if (e->datad)
4699 e->datad(e->data);
4700 ast_free(e);
4701}
4702
4703static void *pbx_thread(void *data)
4704{
4705 /* Oh joyous kernel, we're a new thread, with nothing to do but
4706 answer this channel and get it going.
4707 */
4708 /* NOTE:
4709 The launcher of this function _MUST_ increment 'countcalls'
4710 before invoking the function; it will be decremented when the
4711 PBX has finished running on the channel
4712 */
4713 struct ast_channel *c = data;
4714
4717
4718 pthread_exit(NULL);
4719
4720 return NULL;
4721}
4722
4724{
4725 pthread_t t;
4726
4727 if (!c) {
4728 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
4729 return AST_PBX_FAILED;
4730 }
4731
4733 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
4734 return AST_PBX_FAILED;
4735 }
4736
4738 return AST_PBX_CALL_LIMIT;
4739
4740 /* Start a new thread, and get something handling this channel. */
4742 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
4744 return AST_PBX_FAILED;
4745 }
4746
4747 return AST_PBX_SUCCESS;
4748}
4749
4751{
4753
4755 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
4756 return AST_PBX_FAILED;
4757 }
4758
4759 if (increase_call_count(c)) {
4760 return AST_PBX_CALL_LIMIT;
4761 }
4762
4763 res = __ast_pbx_run(c, args);
4764
4766
4767 return res;
4768}
4769
4771{
4772 return ast_pbx_run_args(c, NULL);
4773}
4774
4776{
4777 return countcalls;
4778}
4779
4781{
4782 return totalcalls;
4783}
4784
4786{
4787 int oldval = autofallthrough;
4788 autofallthrough = newval;
4789 return oldval;
4790}
4791
4793{
4794 int oldval = extenpatternmatchnew;
4795 extenpatternmatchnew = newval;
4796 return oldval;
4797}
4798
4799void pbx_set_overrideswitch(const char *newval)
4800{
4801 if (overrideswitch) {
4803 }
4804 if (!ast_strlen_zero(newval)) {
4805 overrideswitch = ast_strdup(newval);
4806 } else {
4808 }
4809}
4810
4811/*!
4812 * \brief lookup for a context with a given name,
4813 * \retval found context or NULL if not found.
4814 */
4815static struct ast_context *find_context(const char *context)
4816{
4817 struct ast_context item = {
4818 .name = context,
4819 };
4820
4822}
4823
4824/*!
4825 * \brief lookup for a context with a given name,
4826 * \retval with conlock held if found.
4827 * \retval NULL if not found.
4828 */
4829static struct ast_context *find_context_locked(const char *context)
4830{
4831 struct ast_context *c;
4832 struct ast_context item = {
4833 .name = context,
4834 };
4835
4838 if (!c) {
4840 }
4841
4842 return c;
4843}
4844
4845/*!
4846 * \brief Remove included contexts.
4847 * This function locks contexts list by &conlist, search for the right context
4848 * structure, leave context list locked and call ast_context_remove_include2
4849 * which removes include, unlock contexts list and return ...
4850 */
4851int ast_context_remove_include(const char *context, const char *include, const char *registrar)
4852{
4853 int ret = -1;
4854 struct ast_context *c;
4855
4857 if (c) {
4858 /* found, remove include from this context ... */
4859 ret = ast_context_remove_include2(c, include, registrar);
4861 }
4862 return ret;
4863}
4864
4865/*!
4866 * \brief Locks context, remove included contexts, unlocks context.
4867 * When we call this function, &conlock lock must be locked, because when
4868 * we giving *con argument, some process can remove/change this context
4869 * and after that there can be segfault.
4870 *
4871 * \retval 0 on success.
4872 * \retval -1 on failure.
4873 */
4874int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
4875{
4876 int ret = -1;
4877 int idx;
4878
4879 ast_wrlock_context(con);
4880
4881 /* find our include */
4882 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
4883 struct ast_include *i = AST_VECTOR_GET(&con->includes, idx);
4884
4885 if (!strcmp(ast_get_include_name(i), include) &&
4886 (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) {
4887
4888 /* remove from list */
4889 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
4891
4892 /* free include and return */
4893 include_free(i);
4894 ret = 0;
4895 break;
4896 }
4897 }
4898
4899 ast_unlock_context(con);
4900
4901 return ret;
4902}
4903
4904/*!
4905 * \note This function locks contexts list by &conlist, search for the right context
4906 * structure, leave context list locked and call ast_context_remove_switch2
4907 * which removes switch, unlock contexts list and return ...
4908 */
4909int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
4910{
4911 int ret = -1; /* default error return */
4912 struct ast_context *c;
4913
4915 if (c) {
4916 /* remove switch from this context ... */
4919 }
4920 return ret;
4921}
4922
4923/*!
4924 * \brief This function locks given context, removes switch, unlock context and
4925 * return.
4926 * \note When we call this function, &conlock lock must be locked, because when
4927 * we giving *con argument, some process can remove/change this context
4928 * and after that there can be segfault.
4929 *
4930 */
4931int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
4932{
4933 int idx;
4934 int ret = -1;
4935
4936 ast_wrlock_context(con);
4937
4938 /* walk switches */
4939 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
4940 struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx);
4941
4942 if (!strcmp(ast_get_switch_name(i), sw) &&
4943 !strcmp(ast_get_switch_data(i), data) &&
4944 (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) {
4945
4946 /* found, remove from list */
4947 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
4948 AST_VECTOR_REMOVE_ORDERED(&con->alts, idx);
4949
4950 /* free switch and return */
4951 sw_free(i);
4952 ret = 0;
4953 break;
4954 }
4955 }
4956
4957 ast_unlock_context(con);
4958
4959 return ret;
4960}
4961
4962/*! \note This function will lock conlock. */
4963int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
4964{
4966}
4967
4968int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
4969{
4970 int ret = -1; /* default error return */
4971 struct ast_context *c;
4972
4974 if (c) { /* ... remove extension ... */
4976 matchcallerid, registrar, 0);
4978 }
4979
4980 return ret;
4981}
4982
4983/*!
4984 * \brief This functionc locks given context, search for the right extension and
4985 * fires out all peer in this extensions with given priority. If priority
4986 * is set to 0, all peers are removed. After that, unlock context and
4987 * return.
4988 * \note When do you want to call this function, make sure that &conlock is locked,
4989 * because some process can handle with your *con context before you lock
4990 * it.
4991 *
4992 */
4993int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
4994{
4996}
4997
4998int 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)
4999{
5000 struct ast_exten *exten, *prev_exten = NULL;
5001 struct ast_exten *peer;
5002 struct ast_exten ex, *exten2, *exten3;
5003 char dummy_name[1024];
5004 char dummy_cid[1024];
5005 struct ast_exten *previous_peer = NULL;
5006 struct ast_exten *next_peer = NULL;
5007 int found = 0;
5008
5009 if (!already_locked)
5010 ast_wrlock_context(con);
5011
5012#ifdef NEED_DEBUG
5013 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
5014#endif
5015#ifdef CONTEXT_DEBUG
5016 check_contexts(__FILE__, __LINE__);
5017#endif
5018 /* find this particular extension */
5019 ex.exten = dummy_name;
5020 ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1);
5021 ex.matchcid = matchcallerid;
5022 if (callerid) {
5023 ex.cidmatch = dummy_cid;
5024 ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1);
5025 } else {
5026 ex.cidmatch = NULL;
5027 }
5028 exten = ast_hashtab_lookup(con->root_table, &ex);
5029 if (exten) {
5030 if (priority == 0) {
5032 if (!exten2)
5033 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);
5034 if (con->pattern_tree) {
5035 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5036
5037 if (x->exten) { /* this test for safety purposes */
5038 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5039 x->exten = 0; /* get rid of what will become a bad pointer */
5040 } else {
5041 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
5042 }
5043 }
5044 } else {
5045 ex.priority = priority;
5046 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
5047 if (exten2) {
5048 if (exten2->label) { /* if this exten has a label, remove that, too */
5050 if (!exten3) {
5051 ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) "
5052 "from the peer_label_table of context %s, extension %s!\n",
5053 priority, exten2->label, con->name, exten2->name);
5054 }
5055 }
5056
5058 if (!exten3) {
5059 ast_log(LOG_ERROR, "Did not remove this priority (%d) from the "
5060 "peer_table of context %s, extension %s!\n",
5061 priority, con->name, exten2->name);
5062 }
5063 if (exten2 == exten && exten2->peer) {
5066 }
5067 if (ast_hashtab_size(exten->peer_table) == 0) {
5068 /* well, if the last priority of an exten is to be removed,
5069 then, the extension is removed, too! */
5071 if (!exten3) {
5072 ast_log(LOG_ERROR, "Did not remove this exten (%s) from the "
5073 "context root_table (%s) (priority %d)\n",
5074 exten->name, con->name, priority);
5075 }
5076 if (con->pattern_tree) {
5077 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
5078 if (x->exten) { /* this test for safety purposes */
5079 x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
5080 x->exten = 0; /* get rid of what will become a bad pointer */
5081 }
5082 }
5083 }
5084 } else {
5085 ast_debug(3,"Could not find priority %d of exten %s in context %s!\n",
5086 priority, exten->name, con->name);
5087 }
5088 }
5089 } else {
5090 /* hmmm? this exten is not in this pattern tree? */
5091 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
5092 extension, con->name);
5093 }
5094#ifdef NEED_DEBUG
5095 if (con->pattern_tree) {
5096 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
5097 log_match_char_tree(con->pattern_tree, " ");
5098 }
5099#endif
5100
5101 /* scan the extension list to find first matching extension-registrar */
5102 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
5103 if (!strcmp(exten->exten, ex.exten) &&
5104 (!matchcallerid ||
5107 break;
5108 }
5109 }
5110 if (!exten) {
5111 /* we can't find right extension */
5112 if (!already_locked)
5113 ast_unlock_context(con);
5114 return -1;
5115 }
5116
5117 /* scan the priority list to remove extension with exten->priority == priority */
5118 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
5119 peer && !strcmp(peer->exten, ex.exten) &&
5120 (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, ex.cidmatch))) ;
5121 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
5122
5123 if ((priority == 0 || peer->priority == priority) &&
5124 (!registrar || !strcmp(peer->registrar, registrar) )) {
5125 found = 1;
5126
5127 /* we are first priority extension? */
5128 if (!previous_peer) {
5129 /*
5130 * We are first in the priority chain, so must update the extension chain.
5131 * The next node is either the next priority or the next extension
5132 */
5133 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
5134 if (peer->peer) {
5135 /* move the peer_table and peer_label_table down to the next peer, if
5136 it is there */
5139 peer->peer_table = NULL;
5141 }
5142 if (!prev_exten) { /* change the root... */
5143 con->root = next_node;
5144 } else {
5145 prev_exten->next = next_node; /* unlink */
5146 }
5147 if (peer->peer) { /* update the new head of the pri list */
5148 peer->peer->next = peer->next;
5149 }
5150 } else { /* easy, we are not first priority in extension */
5151 previous_peer->peer = peer->peer;
5152 }
5153
5154
5155 /* now, free whole priority extension */
5157 } else {
5158 previous_peer = peer;
5159 }
5160 }
5161 if (!already_locked)
5162 ast_unlock_context(con);
5163 return found ? 0 : -1;
5164}
5165
5166/*
5167 * Help for CLI commands ...
5168 */
5169
5170/*! \brief handle_show_hints: CLI support for listing registered dial plan hints */
5171static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5172{
5173 struct ast_hint *hint;
5174 int num = 0;
5175 int watchers;
5176 struct ao2_iterator i;
5178
5179 switch (cmd) {
5180 case CLI_INIT:
5181 e->command = "core show hints";
5182 e->usage =
5183 "Usage: core show hints\n"
5184 " List registered hints.\n"
5185 " Hint details are shown in five columns. In order from left to right, they are:\n"
5186 " 1. Hint extension URI.\n"
5187 " 2. List of mapped device or presence state identifiers.\n"
5188 " 3. Current extension state. The aggregate of mapped device states.\n"
5189 " 4. Current presence state for the mapped presence state provider.\n"
5190 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
5191 return NULL;
5192 case CLI_GENERATE:
5193 return NULL;
5194 }
5195
5196 if (ao2_container_count(hints) == 0) {
5197 ast_cli(a->fd, "There are no registered dialplan hints\n");
5198 return CLI_SUCCESS;
5199 }
5200 /* ... we have hints ... */
5201 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
5202
5203 i = ao2_iterator_init(hints, 0);
5204 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5205 ao2_lock(hint);
5206 if (!hint->exten) {
5207 /* The extension has already been destroyed */
5208 ao2_unlock(hint);
5209 continue;
5210 }
5211 watchers = ao2_container_count(hint->callbacks);
5212 snprintf(buf, sizeof(buf), "%s@%s",
5215
5216 ast_cli(a->fd, "%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
5217 buf,
5221 watchers);
5222
5223 ao2_unlock(hint);
5224 num++;
5225 }
5227
5228 ast_cli(a->fd, "----------------\n");
5229 ast_cli(a->fd, "- %d hints registered\n", num);
5230 return CLI_SUCCESS;
5231}
5232
5233/*! \brief autocomplete for CLI command 'core show hint' */
5234static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
5235{
5236 struct ast_hint *hint;
5237 char *ret = NULL;
5238 int which = 0;
5239 int wordlen;
5240 struct ao2_iterator i;
5241
5242 if (pos != 3)
5243 return NULL;
5244
5245 wordlen = strlen(word);
5246
5247 /* walk through all hints */
5248 i = ao2_iterator_init(hints, 0);
5249 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5250 ao2_lock(hint);
5251 if (!hint->exten) {
5252 /* The extension has already been destroyed */
5253 ao2_unlock(hint);
5254 continue;
5255 }
5256 if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
5258 ao2_unlock(hint);
5259 ao2_ref(hint, -1);
5260 break;
5261 }
5262 ao2_unlock(hint);
5263 }
5265
5266 return ret;
5267}
5268
5269/*! \brief handle_show_hint: CLI support for listing registered dial plan hint */
5270static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5271{
5272 struct ast_hint *hint;
5273 int watchers;
5274 int num = 0, extenlen;
5275 struct ao2_iterator i;
5277
5278 switch (cmd) {
5279 case CLI_INIT:
5280 e->command = "core show hint";
5281 e->usage =
5282 "Usage: core show hint <exten>\n"
5283 " List registered hint.\n"
5284 " Hint details are shown in five columns. In order from left to right, they are:\n"
5285 " 1. Hint extension URI.\n"
5286 " 2. List of mapped device or presence state identifiers.\n"
5287 " 3. Current extension state. The aggregate of mapped device states.\n"
5288 " 4. Current presence state for the mapped presence state provider.\n"
5289 " 5. Watchers - number of subscriptions and other entities watching this hint.\n";
5290 return NULL;
5291 case CLI_GENERATE:
5292 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
5293 }
5294
5295 if (a->argc < 4)
5296 return CLI_SHOWUSAGE;
5297
5298 if (ao2_container_count(hints) == 0) {
5299 ast_cli(a->fd, "There are no registered dialplan hints\n");
5300 return CLI_SUCCESS;
5301 }
5302
5303 extenlen = strlen(a->argv[3]);
5304 i = ao2_iterator_init(hints, 0);
5305 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
5306 ao2_lock(hint);
5307 if (!hint->exten) {
5308 /* The extension has already been destroyed */
5309 ao2_unlock(hint);
5310 continue;
5311 }
5312 if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
5313 watchers = ao2_container_count(hint->callbacks);
5314 sprintf(buf, "%s@%s",
5317 ast_cli(a->fd, "%-30.30s: %-60.60s State:%-15.15s Presence:%-15.15s Watchers %2d\n",
5318 buf,
5322 watchers);
5323 num++;
5324 }
5325 ao2_unlock(hint);
5326 }
5328 if (!num)
5329 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
5330 else
5331 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
5332 return CLI_SUCCESS;
5333}
5334
5335#if 0
5336/* This code can be used to test if the system survives running out of memory.
5337 * It might be an idea to put this in only if ENABLE_AUTODESTRUCT_TESTS is enabled.
5338 *
5339 * If you want to test this, these Linux sysctl flags might be appropriate:
5340 * vm.overcommit_memory = 2
5341 * vm.swappiness = 0
5342 *
5343 * <@Corydon76-home> I envision 'core eat disk space' and 'core eat file descriptors' now
5344 * <@mjordan> egads
5345 * <@mjordan> it's literally the 'big red' auto-destruct button
5346 * <@mjordan> if you were wondering who even builds such a thing.... well, now you know
5347 * ...
5348 * <@Corydon76-home> What about if they lived only if you defined TEST_FRAMEWORK? Shouldn't have those on production machines
5349 * <@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
5350 */
5351static char *handle_eat_memory(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5352{
5353 void **blocks;
5354 int blocks_pos = 0;
5355 const int blocks_max = 50000;
5356 long long int allocated = 0;
5357 int sizes[] = {
5358 100 * 1024 * 1024,
5359 100 * 1024,
5360 2 * 1024,
5361 400,
5362 0
5363 };
5364 int i;
5365
5366 switch (cmd) {
5367 case CLI_INIT:
5368 /* To do: add method to free memory again? 5 minutes? */
5369 e->command = "core eat memory";
5370 e->usage =
5371 "Usage: core eat memory\n"
5372 " Eats all available memory so you can test if the system survives\n";
5373 return NULL;
5374 case CLI_GENERATE:
5375 return NULL;
5376 }
5377
5378 blocks = ast_malloc(sizeof(void*) * blocks_max);
5379 if (!blocks) {
5380 ast_log(LOG_ERROR, "Already out of mem?\n");
5381 return CLI_SUCCESS;
5382 }
5383
5384 for (i = 0; sizes[i]; ++i) {
5385 int alloc_size = sizes[i];
5386 ast_log(LOG_WARNING, "Allocating %d sized blocks (got %d blocks already)\n", alloc_size, blocks_pos);
5387 while (1) {
5388 void *block;
5389 if (blocks_pos >= blocks_max) {
5390 ast_log(LOG_ERROR, "Memory buffer too small? Run me again :)\n");
5391 break;
5392 }
5393
5394 block = ast_malloc(alloc_size);
5395 if (!block) {
5396 break;
5397 }
5398
5399 blocks[blocks_pos++] = block;
5400 allocated += alloc_size;
5401 }
5402 }
5403
5404 /* No freeing of the mem! */
5405 ast_log(LOG_WARNING, "Allocated %lld bytes total!\n", allocated);
5406 return CLI_SUCCESS;
5407}
5408#endif
5409
5410/*
5411 * 'show dialplan' CLI command implementation functions ...
5412 */
5413static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
5414 int state)
5415{
5416 struct ast_context *c = NULL;
5417 char *ret = NULL;
5418 int which = 0;
5419 int wordlen;
5420
5421 /* we are do completion of [exten@]context on second position only */
5422 if (pos != 2)
5423 return NULL;
5424
5426
5427 wordlen = strlen(word);
5428
5429 /* walk through all contexts and return the n-th match */
5430 while ( (c = ast_walk_contexts(c)) ) {
5431 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
5433 break;
5434 }
5435 }
5436
5438
5439 return ret;
5440}
5441
5442/*! \brief Counters for the show dialplan manager command */
5450};
5451
5452/*! \brief helper function to print an extension */
5453static void print_ext(struct ast_exten *e, char * buf, int buflen)
5454{
5455 int prio = ast_get_extension_priority(e);
5456 if (prio == PRIORITY_HINT) {
5457 snprintf(buf, buflen, "hint: %s",
5459 } else {
5460 snprintf(buf, buflen, "%d. %s(%s)",
5461 prio, ast_get_extension_app(e),
5463 }
5464}
5465
5466/*! \brief Writes CLI output of a single extension for show dialplan */
5467static void show_dialplan_helper_extension_output(int fd, char *buf1, char *buf2, struct ast_exten *exten)
5468{
5470 ast_cli(fd, " %-17s %-45s [%s:%d]\n",
5471 buf1, buf2,
5474 return;
5475 }
5476
5477 ast_cli(fd, " %-17s %-45s [%s]\n",
5479}
5480
5481/* XXX not verified */
5482static 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[])
5483{
5484 struct ast_context *c = NULL;
5485 int res = 0, old_total_exten = dpc->total_exten;
5486
5488
5489 /* walk all contexts ... */
5490 while ( (c = ast_walk_contexts(c)) ) {
5491 int idx;
5492 struct ast_exten *e;
5493#ifndef LOW_MEMORY
5494 char buf[1024], buf2[1024];
5495#else
5496 char buf[256], buf2[256];
5497#endif
5498 int context_info_printed = 0;
5499
5500 if (context && strcmp(ast_get_context_name(c), context))
5501 continue; /* skip this one, name doesn't match */
5502
5503 dpc->context_existence = 1;
5504
5506
5507 /* are we looking for exten too? if yes, we print context
5508 * only if we find our extension.
5509 * Otherwise print context even if empty ?
5510 * XXX i am not sure how the rinclude is handled.
5511 * I think it ought to go inside.
5512 */
5513 if (!exten) {
5514 dpc->total_context++;
5515 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
5517 if (c->autohints) {
5518 ast_cli(fd, "Autohints support enabled\n");
5519 }
5520 context_info_printed = 1;
5521 }
5522
5523 /* walk extensions ... */
5524 e = NULL;
5525 while ( (e = ast_walk_context_extensions(c, e)) ) {
5526 struct ast_exten *p;
5527
5529 continue; /* skip, extension match failed */
5530
5531 dpc->extension_existence = 1;
5532
5533 /* may we print context info? */
5534 if (!context_info_printed) {
5535 dpc->total_context++;
5536 if (rinclude) { /* TODO Print more info about rinclude */
5537 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
5539 } else {
5540 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
5542 if (c->autohints) {
5543 ast_cli(fd, "Autohints support enabled\n");
5544 }
5545 }
5546 context_info_printed = 1;
5547 }
5548 dpc->total_prio++;
5549
5550 /* write extension name and first peer */
5551 if (e->matchcid == AST_EXT_MATCHCID_ON)
5552 snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
5553 else
5554 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
5555
5556 print_ext(e, buf2, sizeof(buf2));
5557
5559
5560 dpc->total_exten++;
5561 /* walk next extension peers */
5562 p = e; /* skip the first one, we already got it */
5563 while ( (p = ast_walk_extension_priorities(e, p)) ) {
5564 const char *el = ast_get_extension_label(p);
5565 dpc->total_prio++;
5566 if (el)
5567 snprintf(buf, sizeof(buf), " [%s]", el);
5568 else
5569 buf[0] = '\0';
5570 print_ext(p, buf2, sizeof(buf2));
5571
5573 }
5574 }
5575
5576 /* walk included and write info ... */
5577 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
5578 const struct ast_include *i = ast_context_includes_get(c, idx);
5579
5580 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
5581 if (exten) {
5582 /* Check all includes for the requested extension */
5583 if (includecount >= AST_PBX_MAX_STACK) {
5584 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
5585 } else {
5586 int dupe = 0;
5587 int x;
5588 for (x = 0; x < includecount; x++) {
5589 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
5590 dupe++;
5591 break;
5592 }
5593 }
5594 if (!dupe) {
5595 includes[includecount] = ast_get_include_name(i);
5596 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
5597 } else {
5598 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
5599 }
5600 }
5601 } else {
5602 ast_cli(fd, " Include => %-45s [%s]\n",
5604 }
5605 }
5606
5607 /* walk ignore patterns and write info ... */
5608 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
5609 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
5610 const char *ipname = ast_get_ignorepat_name(ip);
5611 char ignorepat[AST_MAX_EXTENSION];
5612
5613 snprintf(buf, sizeof(buf), "'%s'", ipname);
5614 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
5615 if (!exten || ast_extension_match(ignorepat, exten)) {
5616 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
5618 }
5619 }
5620 if (!rinclude) {
5621 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
5622 const struct ast_sw *sw = ast_context_switches_get(c, idx);
5623
5624 snprintf(buf, sizeof(buf), "'%s/%s'",
5627 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
5629 }
5630 }
5631
5633
5634 /* if we print something in context, make an empty line */
5635 if (context_info_printed)
5636 ast_cli(fd, "\n");
5637 }
5639
5640 return (dpc->total_exten == old_total_exten) ? -1 : res;
5641}
5642
5643static 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[])
5644{
5645 struct ast_context *c = NULL;
5646 int res = 0, old_total_exten = dpc->total_exten;
5647
5648 ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
5649
5650 ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
5651 ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
5652 ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
5653 ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
5654 ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
5655 ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
5656 ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
5658
5659 /* walk all contexts ... */
5660 while ( (c = ast_walk_contexts(c)) ) {
5661 int context_info_printed = 0;
5662
5663 if (context && strcmp(ast_get_context_name(c), context))
5664 continue; /* skip this one, name doesn't match */
5665
5666 dpc->context_existence = 1;
5667
5668 if (!c->pattern_tree) {
5669 /* Ignore check_return warning from Coverity for ast_exists_extension below */
5670 ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
5671 }
5672
5674
5675 dpc->total_context++;
5676 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
5678 context_info_printed = 1;
5679
5680 if (c->pattern_tree)
5681 {
5682 cli_match_char_tree(c->pattern_tree, " ", fd);
5683 } else {
5684 ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
5685 }
5686
5688
5689 /* if we print something in context, make an empty line */
5690 if (context_info_printed)
5691 ast_cli(fd, "\n");
5692 }
5694
5695 return (dpc->total_exten == old_total_exten) ? -1 : res;
5696}
5697
5698static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5699{
5700 char *exten = NULL, *context = NULL;
5701 /* Variables used for different counters */
5702 struct dialplan_counters counters;
5703 const char *incstack[AST_PBX_MAX_STACK];
5704
5705 switch (cmd) {
5706 case CLI_INIT:
5707 e->command = "dialplan show";
5708 e->usage =
5709 "Usage: dialplan show [[exten@]context]\n"
5710 " Show dialplan\n";
5711 return NULL;
5712 case CLI_GENERATE:
5713 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
5714 }
5715
5716 memset(&counters, 0, sizeof(counters));
5717
5718 if (a->argc != 2 && a->argc != 3)
5719 return CLI_SHOWUSAGE;
5720
5721 /* we obtain [exten@]context? if yes, split them ... */
5722 if (a->argc == 3) {
5723 if (strchr(a->argv[2], '@')) { /* split into exten & context */
5724 context = ast_strdupa(a->argv[2]);
5725 exten = strsep(&context, "@");
5726 /* change empty strings to NULL */
5727 if (ast_strlen_zero(exten))
5728 exten = NULL;
5729 } else { /* no '@' char, only context given */
5730 context = ast_strdupa(a->argv[2]);
5731 }
5733 context = NULL;
5734 }
5735 /* else Show complete dial plan, context and exten are NULL */
5736 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
5737
5738 /* check for input failure and throw some error messages */
5739 if (context && !counters.context_existence) {
5740 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
5741 return CLI_FAILURE;
5742 }
5743
5744 if (exten && !counters.extension_existence) {
5745 if (context)
5746 ast_cli(a->fd, "There is no existence of %s@%s extension\n",
5747 exten, context);
5748 else
5749 ast_cli(a->fd,
5750 "There is no existence of '%s' extension in all contexts\n",
5751 exten);
5752 return CLI_FAILURE;
5753 }
5754
5755 ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
5756 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
5757 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
5758 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
5759
5760 /* everything ok */
5761 return CLI_SUCCESS;
5762}
5763
5764/*! \brief Send ack once */
5765static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5766{
5767 char *exten = NULL, *context = NULL;
5768 /* Variables used for different counters */
5769 struct dialplan_counters counters;
5770 const char *incstack[AST_PBX_MAX_STACK];
5771
5772 switch (cmd) {
5773 case CLI_INIT:
5774 e->command = "dialplan debug";
5775 e->usage =
5776 "Usage: dialplan debug [context]\n"
5777 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
5778 return NULL;
5779 case CLI_GENERATE:
5780 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
5781 }
5782
5783 memset(&counters, 0, sizeof(counters));
5784
5785 if (a->argc != 2 && a->argc != 3)
5786 return CLI_SHOWUSAGE;
5787
5788 /* we obtain [exten@]context? if yes, split them ... */
5789 /* note: we ignore the exten totally here .... */
5790 if (a->argc == 3) {
5791 if (strchr(a->argv[2], '@')) { /* split into exten & context */
5792 context = ast_strdupa(a->argv[2]);
5793 exten = strsep(&context, "@");
5794 /* change empty strings to NULL */
5795 if (ast_strlen_zero(exten))
5796 exten = NULL;
5797 } else { /* no '@' char, only context given */
5798 context = ast_strdupa(a->argv[2]);
5799 }
5801 context = NULL;
5802 }
5803 /* else Show complete dial plan, context and exten are NULL */
5804 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
5805
5806 /* check for input failure and throw some error messages */
5807 if (context && !counters.context_existence) {
5808 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
5809 return CLI_FAILURE;
5810 }
5811
5812
5813 ast_cli(a->fd,"-= %d %s. =-\n",
5814 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
5815
5816 /* everything ok */
5817 return CLI_SUCCESS;
5818}
5819
5820/*! \brief Send ack once */
5821static void manager_dpsendack(struct mansession *s, const struct message *m)
5822{
5823 astman_send_listack(s, m, "DialPlan list will follow", "start");
5824}
5825
5826/*! \brief Show dialplan extensions
5827 * XXX this function is similar but not exactly the same as the CLI's
5828 * show dialplan. Must check whether the difference is intentional or not.
5829 */
5830static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
5831 const char *actionidtext, const char *context,
5832 const char *exten, struct dialplan_counters *dpc,
5833 const struct ast_include *rinclude,
5834 int includecount, const char *includes[])
5835{
5836 struct ast_context *c;
5837 int res = 0, old_total_exten = dpc->total_exten;
5838
5839 if (ast_strlen_zero(exten))
5840 exten = NULL;
5842 context = NULL;
5843
5844 ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
5845
5846 /* try to lock contexts */
5847 if (ast_rdlock_contexts()) {
5848 astman_send_error(s, m, "Failed to lock contexts");
5849 ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
5850 return -1;
5851 }
5852
5853 c = NULL; /* walk all contexts ... */
5854 while ( (c = ast_walk_contexts(c)) ) {
5855 int idx;
5856 struct ast_exten *e;
5857
5858 if (context && strcmp(ast_get_context_name(c), context) != 0)
5859 continue; /* not the name we want */
5860
5861 dpc->context_existence = 1;
5862 dpc->total_context++;
5863
5864 ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
5865
5866 if (ast_rdlock_context(c)) { /* failed to lock */
5867 ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
5868 continue;
5869 }
5870
5871 /* XXX note- an empty context is not printed */
5872 e = NULL; /* walk extensions in context */
5873 while ( (e = ast_walk_context_extensions(c, e)) ) {
5874 struct ast_exten *p;
5875
5876 /* looking for extension? is this our extension? */
5878 /* not the one we are looking for, continue */
5879 ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
5880 continue;
5881 }
5882 ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
5883
5884 dpc->extension_existence = 1;
5885
5886 dpc->total_exten++;
5887
5888 p = NULL; /* walk next extension peers */
5889 while ( (p = ast_walk_extension_priorities(e, p)) ) {
5890 int prio = ast_get_extension_priority(p);
5891
5892 dpc->total_prio++;
5893 if (!dpc->total_items++)
5894 manager_dpsendack(s, m);
5895 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5896 astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
5897
5898 /* XXX maybe make this conditional, if p != e ? */
5900 astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
5901
5902 if (prio == PRIORITY_HINT) {
5903 astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
5904 } else {
5905 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));
5906 }
5907 astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
5908 }
5909 }
5910
5911 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
5912 const struct ast_include *i = ast_context_includes_get(c, idx);
5913
5914 if (exten) {
5915 /* Check all includes for the requested extension */
5916 if (includecount >= AST_PBX_MAX_STACK) {
5917 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
5918 } else {
5919 int dupe = 0;
5920 int x;
5921 for (x = 0; x < includecount; x++) {
5922 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
5923 dupe++;
5924 break;
5925 }
5926 }
5927 if (!dupe) {
5928 includes[includecount] = ast_get_include_name(i);
5929 manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
5930 } else {
5931 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
5932 }
5933 }
5934 } else {
5935 if (!dpc->total_items++)
5936 manager_dpsendack(s, m);
5937 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5938 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));
5939 astman_append(s, "\r\n");
5940 ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
5941 }
5942 }
5943
5944 for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
5945 const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
5946 const char *ipname = ast_get_ignorepat_name(ip);
5947 char ignorepat[AST_MAX_EXTENSION];
5948
5949 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
5950 if (!exten || ast_extension_match(ignorepat, exten)) {
5951 if (!dpc->total_items++)
5952 manager_dpsendack(s, m);
5953 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5954 astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
5955 astman_append(s, "\r\n");
5956 }
5957 }
5958 if (!rinclude) {
5959 for (idx = 0; idx < ast_context_switches_count(c); idx++) {
5960 const struct ast_sw *sw = ast_context_switches_get(c, idx);
5961
5962 if (!dpc->total_items++)
5963 manager_dpsendack(s, m);
5964 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
5965 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));
5966 astman_append(s, "\r\n");
5967 ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
5968 }
5969 }
5970
5972 }
5974
5975 if (dpc->total_exten == old_total_exten) {
5976 ast_debug(3, "manager_show_dialplan: Found nothing new\n");
5977 /* Nothing new under the sun */
5978 return -1;
5979 } else {
5980 return res;
5981 }
5982}
5983
5984/*! \brief Manager listing of dial plan */
5985static int manager_show_dialplan(struct mansession *s, const struct message *m)
5986{
5987 const char *exten, *context;
5988 const char *id = astman_get_header(m, "ActionID");
5989 const char *incstack[AST_PBX_MAX_STACK];
5990 char idtext[256];
5991
5992 /* Variables used for different counters */
5993 struct dialplan_counters counters;
5994
5995 if (!ast_strlen_zero(id))
5996 snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
5997 else
5998 idtext[0] = '\0';
5999
6000 memset(&counters, 0, sizeof(counters));
6001
6002 exten = astman_get_header(m, "Extension");
6003 context = astman_get_header(m, "Context");
6004
6005 manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL, 0, incstack);
6006
6007 if (!ast_strlen_zero(context) && !counters.context_existence) {
6008 char errorbuf[BUFSIZ];
6009
6010 snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
6011 astman_send_error(s, m, errorbuf);
6012 return 0;
6013 }
6014 if (!ast_strlen_zero(exten) && !counters.extension_existence) {
6015 char errorbuf[BUFSIZ];
6016
6018 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
6019 else
6020 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
6021 astman_send_error(s, m, errorbuf);
6022 return 0;
6023 }
6024
6025 if (!counters.total_items) {
6026 manager_dpsendack(s, m);
6027 }
6028
6029 astman_send_list_complete_start(s, m, "ShowDialPlanComplete", counters.total_items);
6030 astman_append(s,
6031 "ListExtensions: %d\r\n"
6032 "ListPriorities: %d\r\n"
6033 "ListContexts: %d\r\n",
6034 counters.total_exten, counters.total_prio, counters.total_context);
6036
6037 /* everything ok */
6038 return 0;
6039}
6040
6041#ifdef AST_DEVMODE
6042static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6043{
6044 struct ast_devstate_aggregate agg;
6045 int i, j, exten, combined;
6046
6047 switch (cmd) {
6048 case CLI_INIT:
6049 e->command = "core show device2extenstate";
6050 e->usage =
6051 "Usage: core show device2extenstate\n"
6052 " Lists device state to extension state combinations.\n";
6053 case CLI_GENERATE:
6054 return NULL;
6055 }
6056 for (i = 0; i < AST_DEVICE_TOTAL; i++) {
6057 for (j = 0; j < AST_DEVICE_TOTAL; j++) {
6061 combined = ast_devstate_aggregate_result(&agg);
6062 exten = ast_devstate_to_extenstate(combined);
6063 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));
6064 }
6065 }
6066 ast_cli(a->fd, "\n");
6067 return CLI_SUCCESS;
6068}
6069#endif
6070
6071static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6072{
6073 int oldval = 0;
6074
6075 switch (cmd) {
6076 case CLI_INIT:
6077 e->command = "dialplan set extenpatternmatchnew true";
6078 e->usage =
6079 "Usage: dialplan set extenpatternmatchnew true|false\n"
6080 " Use the NEW extension pattern matching algorithm, true or false.\n";
6081 return NULL;
6082 case CLI_GENERATE:
6083 return NULL;
6084 }
6085
6086 if (a->argc != 4)
6087 return CLI_SHOWUSAGE;
6088
6089 oldval = pbx_set_extenpatternmatchnew(1);
6090
6091 if (oldval)
6092 ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
6093 else
6094 ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
6095
6096 return CLI_SUCCESS;
6097}
6098
6099static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
6100{
6101 int oldval = 0;
6102
6103 switch (cmd) {
6104 case CLI_INIT:
6105 e->command = "dialplan set extenpatternmatchnew false";
6106 e->usage =
6107 "Usage: dialplan set extenpatternmatchnew true|false\n"
6108 " Use the NEW extension pattern matching algorithm, true or false.\n";
6109 return NULL;
6110 case CLI_GENERATE:
6111 return NULL;
6112 }
6113
6114 if (a->argc != 4)
6115 return CLI_SHOWUSAGE;
6116
6117 oldval = pbx_set_extenpatternmatchnew(0);
6118
6119 if (!oldval)
6120 ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
6121 else
6122 ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
6123
6124 return CLI_SUCCESS;
6125}
6126
6127/*
6128 * CLI entries for upper commands ...
6129 */
6130static struct ast_cli_entry pbx_cli[] = {
6131#if 0
6132 AST_CLI_DEFINE(handle_eat_memory, "Eats all available memory"),
6133#endif
6134 AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
6135 AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
6136#ifdef AST_DEVMODE
6137 AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
6138#endif
6139 AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
6140 AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
6141 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
6142 AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
6143};
6144
6146{
6147 struct ast_context *context = NULL;
6148 struct ast_exten *eroot = NULL, *e = NULL;
6149
6151 while ((context = ast_walk_contexts(context))) {
6152 while ((eroot = ast_walk_context_extensions(context, eroot))) {
6153 while ((e = ast_walk_extension_priorities(eroot, e))) {
6154 if (e->cached_app == app)
6155 e->cached_app = NULL;
6156 }
6157 }
6158 }
6160
6161 return;
6162}
6163
6164struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
6165{
6166 struct ast_context *tmp, **local_contexts;
6167 struct ast_context search = {
6168 .name = name,
6169 };
6170 size_t name_bytes = strlen(name);
6171 size_t registrar_bytes = strlen(registrar);
6172 int length = sizeof(struct ast_context) + name_bytes + registrar_bytes + 2;
6173
6174 if (!contexts_table) {
6175 /* Protect creation of contexts_table from reentrancy. */
6177 if (!contexts_table) {
6183 0);
6184 }
6186 }
6187
6188 if (!extcontexts) {
6191 tmp = ast_hashtab_lookup(contexts_table, &search);
6192 if (tmp) {
6193 tmp->refcount++;
6195 return tmp;
6196 }
6197 } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
6198 local_contexts = extcontexts;
6199 tmp = ast_hashtab_lookup(exttable, &search);
6200 if (tmp) {
6201 tmp->refcount++;
6202 return tmp;
6203 }
6204 }
6205
6206 if ((tmp = ast_calloc(1, length))) {
6207 ast_rwlock_init(&tmp->lock);
6208 tmp->name = memcpy(&tmp->data[0], name, name_bytes);
6209 tmp->registrar = memcpy(&tmp->data[name_bytes + 1], registrar, registrar_bytes);
6210 tmp->root = NULL;
6211 tmp->root_table = NULL;
6212 AST_VECTOR_INIT(&tmp->includes, 0);
6213 AST_VECTOR_INIT(&tmp->ignorepats, 0);
6214 AST_VECTOR_INIT(&tmp->alts, 0);
6215 tmp->refcount = 1;
6216
6217 /* The context 'name' must be stored at the beginning of 'data.' The
6218 * order of subsequent strings (currently only 'registrar') is not
6219 * relevant. */
6220 ast_assert(tmp->name == &tmp->data[0]);
6221 } else {
6222 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
6223 if (!extcontexts) {
6225 }
6226 return NULL;
6227 }
6228
6229 if (!extcontexts) {
6230 tmp->next = *local_contexts;
6231 *local_contexts = tmp;
6232 ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
6234 } else {
6235 tmp->next = *local_contexts;
6236 if (exttable)
6237 ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
6238
6239 *local_contexts = tmp;
6240 }
6241 ast_debug(1, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
6242 return tmp;
6243}
6244
6246{
6247 con->autohints = enabled;
6248}
6249
6250void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
6251
6253 char *context;
6254 char *exten;
6260
6262 char data[0];
6263};
6264
6266
6268{
6269 int idx;
6270
6271 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);
6272 /* copy in the includes, switches, and ignorepats */
6273 /* walk through includes */
6274 for (idx = 0; idx < ast_context_includes_count(old); idx++) {
6275 const struct ast_include *i = ast_context_includes_get(old, idx);
6276
6277 if (!strcmp(ast_get_include_registrar(i), registrar)) {
6278 continue; /* not mine */
6279 }
6281 }
6282
6283 /* walk through switches */
6284 for (idx = 0; idx < ast_context_switches_count(old); idx++) {
6285 const struct ast_sw *sw = ast_context_switches_get(old, idx);
6286
6287 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
6288 continue; /* not mine */
6289 }
6291 }
6292
6293 /* walk thru ignorepats ... */
6294 for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) {
6295 const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx);
6296
6297 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) {
6298 continue; /* not mine */
6299 }
6301 }
6302}
6303
6304/*! Set up an autohint placeholder in the hints container */
6306{
6307 struct ast_context *con;
6308 struct ast_hashtab_iter *iter;
6309
6310 /* Remove all autohints as the below iteration will recreate them */
6312
6314 while ((con = ast_hashtab_next(iter))) {
6315 size_t name_len = strlen(con->name) + 1;
6316 size_t registrar_len = strlen(con->registrar) + 1;
6317 struct ast_autohint *autohint;
6318
6319 if (!con->autohints) {
6320 continue;
6321 }
6322
6323 autohint = ao2_alloc_options(sizeof(*autohint) + name_len + registrar_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
6324 if (!autohint) {
6325 continue;
6326 }
6327
6328 ast_copy_string(autohint->context, con->name, name_len);
6329 autohint->registrar = autohint->context + name_len;
6330 ast_copy_string(autohint->registrar, con->registrar, registrar_len);
6331
6332 ao2_link(autohints, autohint);
6333 ao2_ref(autohint, -1);
6334
6335 ast_verb(3, "Enabled autohints support on context '%s'\n", con->name);
6336 }
6338}
6339
6340/* the purpose of this routine is to duplicate a context, with all its substructure,
6341 except for any extens that have a matching registrar */
6342static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
6343{
6344 struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
6345 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
6346 struct ast_hashtab_iter *exten_iter;
6347 struct ast_hashtab_iter *prio_iter;
6348 int insert_count = 0;
6349 int first = 1;
6350
6351 /* We'll traverse all the extensions/prios, and see which are not registrar'd with
6352 the current registrar, and copy them to the new context. If the new context does not
6353 exist, we'll create it "on demand". If no items are in this context to copy, then we'll
6354 only create the empty matching context if the old one meets the criteria */
6355
6356 if (context->root_table) {
6357 exten_iter = ast_hashtab_start_traversal(context->root_table);
6358 while ((exten_item=ast_hashtab_next(exten_iter))) {
6359 if (new) {
6360 new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
6361 } else {
6362 new_exten_item = NULL;
6363 }
6364 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
6365 while ((prio_item=ast_hashtab_next(prio_iter))) {
6366 int res1;
6367 char *dupdstr;
6368
6369 if (new_exten_item) {
6370 new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
6371 } else {
6372 new_prio_item = NULL;
6373 }
6374 if (strcmp(prio_item->registrar,registrar) == 0) {
6375 continue;
6376 }
6377 /* make sure the new context exists, so we have somewhere to stick this exten/prio */
6378 if (!new) {
6379 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 */
6380 if (new) {
6381 new->autohints = context->autohints;
6382 }
6383 }
6384
6385 /* copy in the includes, switches, and ignorepats */
6386 if (first) { /* but, only need to do this once */
6388 first = 0;
6389 }
6390
6391 if (!new) {
6392 ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
6393 ast_hashtab_end_traversal(prio_iter);
6394 ast_hashtab_end_traversal(exten_iter);
6395 return; /* no sense continuing. */
6396 }
6397 /* we will not replace existing entries in the new context with stuff from the old context.
6398 but, if this is because of some sort of registrar conflict, we ought to say something... */
6399
6400 dupdstr = ast_strdup(prio_item->data);
6401
6402 res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label,
6403 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar,
6404 prio_item->registrar_file, prio_item->registrar_line);
6405 if (!res1 && new_exten_item && new_prio_item){
6406 ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
6407 context->name, prio_item->name, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
6408 } else {
6409 /* 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,
6410 and no double frees take place, either! */
6411 insert_count++;
6412 }
6413 }
6414 ast_hashtab_end_traversal(prio_iter);
6415 }
6416 ast_hashtab_end_traversal(exten_iter);
6417 } else if (new) {
6418 /* If the context existed but had no extensions, we still want to merge
6419 * the includes, switches and ignore patterns.
6420 */
6422 }
6423
6424 if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
6425 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
6426 /* we could have given it the registrar of the other module who incremented the refcount,
6427 but that's not available, so we give it the registrar we know about */
6428 new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
6429
6430 if (new) {
6431 new->autohints = context->autohints;
6432 }
6433
6434 /* copy in the includes, switches, and ignorepats */
6436 }
6437}
6438
6439
6440/* XXX this does not check that multiple contexts are merged */
6441void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
6442{
6443 double ft;
6444 struct ast_context *tmp;
6445 struct ast_context *oldcontextslist;
6446 struct ast_hashtab *oldtable;
6447 struct store_hints hints_stored = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
6448 struct store_hints hints_removed = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
6449 struct store_hint *saved_hint;
6450 struct ast_hint *hint;
6451 struct ast_exten *exten;
6452 int length;
6453 struct ast_state_cb *thiscb;
6454 struct ast_hashtab_iter *iter;
6455 struct ao2_iterator i;
6456 int ctx_count = 0;
6457 struct timeval begintime;
6458 struct timeval writelocktime;
6459 struct timeval endlocktime;
6460 struct timeval enddeltime;
6461
6462 /*
6463 * It is very important that this function hold the hints
6464 * container lock _and_ the conlock during its operation; not
6465 * only do we need to ensure that the list of contexts and
6466 * extensions does not change, but also that no hint callbacks
6467 * (watchers) are added or removed during the merge/delete
6468 * process
6469 *
6470 * In addition, the locks _must_ be taken in this order, because
6471 * there are already other code paths that use this order
6472 */
6473
6474 begintime = ast_tvnow();
6475 ast_mutex_lock(&context_merge_lock);/* Serialize ast_merge_contexts_and_delete */
6477
6478 if (!contexts_table) {
6479 /* Create any autohint contexts */
6481
6482 /* Well, that's odd. There are no contexts. */
6483 contexts_table = exttable;
6484 contexts = *extcontexts;
6487 return;
6488 }
6489
6491 while ((tmp = ast_hashtab_next(iter))) {
6492 ++ctx_count;
6493 context_merge(extcontexts, exttable, tmp, registrar);
6494 }
6496
6497 ao2_lock(hints);
6498 writelocktime = ast_tvnow();
6499
6500 /* preserve all watchers for hints */
6502 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
6503 if (ao2_container_count(hint->callbacks)) {
6504 size_t exten_len;
6505
6506 ao2_lock(hint);
6507 if (!hint->exten) {
6508 /* The extension has already been destroyed. (Should never happen here) */
6509 ao2_unlock(hint);
6510 continue;
6511 }
6512
6513 exten_len = strlen(hint->exten->exten) + 1;
6514 length = exten_len + strlen(hint->exten->parent->name) + 1
6515 + sizeof(*saved_hint);
6516 if (!(saved_hint = ast_calloc(1, length))) {
6517 ao2_unlock(hint);
6518 continue;
6519 }
6520
6521 /* This removes all the callbacks from the hint into saved_hint. */
6522 while ((thiscb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
6523 AST_LIST_INSERT_TAIL(&saved_hint->callbacks, thiscb, entry);
6524 /*
6525 * We intentionally do not unref thiscb to account for the
6526 * non-ao2 reference in saved_hint->callbacks
6527 */
6528 }
6529
6530 saved_hint->laststate = hint->laststate;
6531 saved_hint->context = saved_hint->data;
6532 strcpy(saved_hint->data, hint->exten->parent->name);
6533 saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
6534 ast_copy_string(saved_hint->exten, hint->exten->exten, exten_len);
6535 if (hint->last_presence_subtype) {
6536 saved_hint->last_presence_subtype = ast_strdup(hint->last_presence_subtype);
6537 }
6538 if (hint->last_presence_message) {
6539 saved_hint->last_presence_message = ast_strdup(hint->last_presence_message);
6540 }
6541 saved_hint->last_presence_state = hint->last_presence_state;
6542 ao2_unlock(hint);
6543 AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
6544 }
6545 }
6547
6548 /* save the old table and list */
6549 oldtable = contexts_table;
6550 oldcontextslist = contexts;
6551
6552 /* move in the new table and list */
6553 contexts_table = exttable;
6554 contexts = *extcontexts;
6555
6556 /*
6557 * Restore the watchers for hints that can be found; notify
6558 * those that cannot be restored.
6559 */
6560 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_stored, list))) {
6561 struct pbx_find_info q = { .stacklen = 0 };
6562
6563 exten = pbx_find_extension(NULL, NULL, &q, saved_hint->context, saved_hint->exten,
6564 PRIORITY_HINT, NULL, "", E_MATCH);
6565 /*
6566 * If this is a pattern, dynamically create a new extension for this
6567 * particular match. Note that this will only happen once for each
6568 * individual extension, because the pattern will no longer match first.
6569 */
6570 if (exten && exten->exten[0] == '_') {
6571 ast_add_extension_nolock(exten->parent->name, 0, saved_hint->exten,
6572 PRIORITY_HINT, NULL, 0, exten->app, ast_strdup(exten->data), ast_free_ptr,
6573 exten->registrar);
6574 /* rwlocks are not recursive locks */
6575 exten = ast_hint_extension_nolock(NULL, saved_hint->context,
6576 saved_hint->exten);
6577 }
6578
6579 /* Find the hint in the hints container */
6580 hint = exten ? ao2_find(hints, exten, 0) : NULL;
6581 if (!hint) {
6582 /*
6583 * Notify watchers of this removed hint later when we aren't
6584 * encumbered by so many locks.
6585 */
6586 AST_LIST_INSERT_HEAD(&hints_removed, saved_hint, list);
6587 } else {
6588 ao2_lock(hint);
6589 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
6590 ao2_link(hint->callbacks, thiscb);
6591 /* Ref that we added when putting into saved_hint->callbacks */
6592 ao2_ref(thiscb, -1);
6593 }
6594 hint->laststate = saved_hint->laststate;
6595 hint->last_presence_state = saved_hint->last_presence_state;
6596 hint->last_presence_subtype = saved_hint->last_presence_subtype;
6597 hint->last_presence_message = saved_hint->last_presence_message;
6598 ao2_unlock(hint);
6599 ao2_ref(hint, -1);
6600 /*
6601 * The free of saved_hint->last_presence_subtype and
6602 * saved_hint->last_presence_message is not necessary here.
6603 */
6604 ast_free(saved_hint);
6605 }
6606 }
6607
6608 /* Create all applicable autohint contexts */
6610
6613
6614 /*
6615 * Notify watchers of all removed hints with the same lock
6616 * environment as device_state_cb().
6617 */
6618 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
6619 /* this hint has been removed, notify the watchers */
6620 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
6622 saved_hint->context,
6623 saved_hint->exten,
6624 thiscb->data,
6626 NULL,
6627 NULL);
6628 /* Ref that we added when putting into saved_hint->callbacks */
6629 ao2_ref(thiscb, -1);
6630 }
6631 ast_free(saved_hint->last_presence_subtype);
6632 ast_free(saved_hint->last_presence_message);
6633 ast_free(saved_hint);
6634 }
6635
6637 endlocktime = ast_tvnow();
6638
6639 /*
6640 * The old list and hashtab no longer are relevant, delete them
6641 * while the rest of asterisk is now freely using the new stuff
6642 * instead.
6643 */
6644
6645 ast_hashtab_destroy(oldtable, NULL);
6646
6647 for (tmp = oldcontextslist; tmp; ) {
6648 struct ast_context *next; /* next starting point */
6649
6650 next = tmp->next;
6652 tmp = next;
6653 }
6654 enddeltime = ast_tvnow();
6655
6656 ft = ast_tvdiff_us(writelocktime, begintime);
6657 ft /= 1000000.0;
6658 ast_verb(5,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
6659
6660 ft = ast_tvdiff_us(endlocktime, writelocktime);
6661 ft /= 1000000.0;
6662 ast_verb(5,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
6663
6664 ft = ast_tvdiff_us(enddeltime, endlocktime);
6665 ft /= 1000000.0;
6666 ast_verb(5,"Time to delete the old dialplan: %8.6f sec\n", ft);
6667
6668 ft = ast_tvdiff_us(enddeltime, begintime);
6669 ft /= 1000000.0;
6670 ast_verb(5,"Total time merge_contexts_delete: %8.6f sec\n", ft);
6671 ast_verb(5, "%s successfully loaded %d contexts (enable debug for details).\n", registrar, ctx_count);
6672}
6673
6674/*
6675 * errno values
6676 * EBUSY - can't lock
6677 * ENOENT - no existence of context
6678 */
6679int ast_context_add_include(const char *context, const char *include, const char *registrar)
6680{
6681 int ret = -1;
6682 struct ast_context *c;
6683
6685 if (c) {
6686 ret = ast_context_add_include2(c, include, registrar);
6688 }
6689 return ret;
6690}
6691
6692/*
6693 * errno values
6694 * ENOMEM - out of memory
6695 * EBUSY - can't lock
6696 * EEXIST - already included
6697 * EINVAL - there is no existence of context for inclusion
6698 */
6699int ast_context_add_include2(struct ast_context *con, const char *value,
6700 const char *registrar)
6701{
6702 struct ast_include *new_include;
6703 int idx;
6704
6705 /* allocate new include structure ... */
6706 new_include = include_alloc(value, registrar);
6707 if (!new_include) {
6708 return -1;
6709 }
6710
6711 ast_wrlock_context(con);
6712
6713 /* ... go to last include and check if context is already included too... */
6714 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
6715 const struct ast_include *i = ast_context_includes_get(con, idx);
6716
6717 if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) {
6718 include_free(new_include);
6719 ast_unlock_context(con);
6720 errno = EEXIST;
6721 return -1;
6722 }
6723 }
6724
6725 /* ... include new context into context list, unlock, return */
6726 if (AST_VECTOR_APPEND(&con->includes, new_include)) {
6727 include_free(new_include);
6728 ast_unlock_context(con);
6729 return -1;
6730 }
6731 ast_debug(1, "Including context '%s' in context '%s'\n",
6732 ast_get_include_name(new_include), ast_get_context_name(con));
6733
6734 ast_unlock_context(con);
6735
6736 return 0;
6737}
6738
6739/*
6740 * errno values
6741 * EBUSY - can't lock
6742 * ENOENT - no existence of context
6743 */
6744int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
6745{
6746 int ret = -1;
6747 struct ast_context *c;
6748
6750 if (c) { /* found, add switch to this context */
6751 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
6753 }
6754 return ret;
6755}
6756
6757/*
6758 * errno values
6759 * ENOMEM - out of memory
6760 * EBUSY - can't lock
6761 * EEXIST - already included
6762 * EINVAL - there is no existence of context for inclusion
6763 */
6764int ast_context_add_switch2(struct ast_context *con, const char *value,
6765 const char *data, int eval, const char *registrar)
6766{
6767 int idx;
6768 struct ast_sw *new_sw;
6769
6770 /* allocate new sw structure ... */
6771 if (!(new_sw = sw_alloc(value, data, eval, registrar))) {
6772 return -1;
6773 }
6774
6775 /* ... try to lock this context ... */
6776 ast_wrlock_context(con);
6777
6778 /* ... go to last sw and check if context is already swd too... */
6779 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
6780 const struct ast_sw *i = ast_context_switches_get(con, idx);
6781
6782 if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) &&
6783 !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) {
6784 sw_free(new_sw);
6785 ast_unlock_context(con);
6786 errno = EEXIST;
6787 return -1;
6788 }
6789 }
6790
6791 /* ... sw new context into context list, unlock, return */
6792 if (AST_VECTOR_APPEND(&con->alts, new_sw)) {
6793 sw_free(new_sw);
6794 ast_unlock_context(con);
6795 return -1;
6796 }
6797
6798 ast_verb(3, "Including switch '%s/%s' in context '%s'\n",
6800
6801 ast_unlock_context(con);
6802
6803 return 0;
6804}
6805
6806/*
6807 * EBUSY - can't lock
6808 * ENOENT - there is not context existence
6809 */
6810int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
6811{
6812 int ret = -1;
6813 struct ast_context *c;
6814
6816 if (c) {
6817 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
6819 }
6820 return ret;
6821}
6822
6823int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
6824{
6825 int idx;
6826
6827 ast_wrlock_context(con);
6828
6829 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6830 struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx);
6831
6832 if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) &&
6835 ignorepat_free(ip);
6836 ast_unlock_context(con);
6837 return 0;
6838 }
6839 }
6840
6841 ast_unlock_context(con);
6842 errno = EINVAL;
6843 return -1;
6844}
6845
6846/*
6847 * EBUSY - can't lock
6848 * ENOENT - there is no existence of context
6849 */
6850int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
6851{
6852 int ret = -1;
6853 struct ast_context *c;
6854
6856 if (c) {
6859 }
6860 return ret;
6861}
6862
6863int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
6864{
6865 struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar);
6866 int idx;
6867
6868 if (!ignorepat) {
6869 return -1;
6870 }
6871
6872 ast_wrlock_context(con);
6873 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6874 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
6875
6876 if (!strcasecmp(ast_get_ignorepat_name(i), value)) {
6877 /* Already there */
6878 ast_unlock_context(con);
6879 ignorepat_free(ignorepat);
6880 errno = EEXIST;
6881 return -1;
6882 }
6883 }
6884 if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) {
6885 ignorepat_free(ignorepat);
6886 ast_unlock_context(con);
6887 return -1;
6888 }
6889 ast_unlock_context(con);
6890
6891 return 0;
6892}
6893
6894int ast_ignore_pattern(const char *context, const char *pattern)
6895{
6896 int ret = 0;
6897 struct ast_context *con;
6898
6901 if (con) {
6902 int idx;
6903
6904 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
6905 const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx);
6906
6908 ret = 1;
6909 break;
6910 }
6911 }
6912 }
6914
6915 return ret;
6916}
6917
6918/*
6919 * ast_add_extension_nolock -- use only in situations where the conlock is already held
6920 * ENOENT - no existence of context
6921 *
6922 */
6923static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
6924 int priority, const char *label, const char *callerid,
6925 const char *application, void *data, void (*datad)(void *), const char *registrar)
6926{
6927 int ret = -1;
6928 struct ast_context *c;
6929
6931 if (c) {
6932 ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
6933 application, data, datad, registrar, NULL, 0, 1);
6934 }
6935
6936 return ret;
6937}
6938/*
6939 * EBUSY - can't lock
6940 * ENOENT - no existence of context
6941 *
6942 */
6943int ast_add_extension(const char *context, int replace, const char *extension,
6944 int priority, const char *label, const char *callerid,
6945 const char *application, void *data, void (*datad)(void *), const char *registrar)
6946{
6947 int ret = -1;
6948 struct ast_context *c;
6949
6951 if (c) {
6952 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
6953 application, data, datad, registrar, NULL, 0);
6955 }
6956
6957 return ret;
6958}
6959
6960int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
6961{
6962 if (!chan)
6963 return -1;
6964
6965 ast_channel_lock(chan);
6966
6969 if (!ast_strlen_zero(exten))
6970 ast_channel_exten_set(chan, exten);
6971 if (priority > -1) {
6972 /* see flag description in channel.h for explanation */
6974 --priority;
6975 }
6977 }
6978
6979 ast_channel_unlock(chan);
6980
6981 return 0;
6982}
6983
6984int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
6985{
6986 struct ast_channel *newchan;
6987
6988 ast_channel_lock(chan);
6989 /* Channels in a bridge or running a PBX can be sent directly to the specified destination */
6990 if (ast_channel_is_bridged(chan) || ast_channel_pbx(chan)) {
6992 priority += 1;
6993 }
6996 ast_channel_unlock(chan);
6997 return 0;
6998 }
6999 ast_channel_unlock(chan);
7000
7001 /* Otherwise, we need to gain control of the channel first */
7002 newchan = ast_channel_yank(chan);
7003 if (!newchan) {
7004 ast_log(LOG_WARNING, "Unable to gain control of channel %s\n", ast_channel_name(chan));
7005 return -1;
7006 }
7008 if (ast_pbx_start(newchan)) {
7009 ast_hangup(newchan);
7010 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(newchan));
7011 return -1;
7012 }
7013
7014 return 0;
7015}
7016
7017int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
7018{
7019 struct ast_channel *chan;
7020 int res = -1;
7021
7022 if ((chan = ast_channel_get_by_name(channame))) {
7023 res = ast_async_goto(chan, context, exten, priority);
7024 chan = ast_channel_unref(chan);
7025 }
7026
7027 return res;
7028}
7029
7030/*!
7031 * \internal
7032 * \brief Copy a string skipping whitespace and optionally dashes.
7033 *
7034 * \param dst Destination buffer to copy src string.
7035 * \param src Null terminated string to copy.
7036 * \param dst_size Number of bytes in the dst buffer.
7037 * \param nofluff Nonzero if '-' chars are not copied.
7038 *
7039 * \return Number of bytes written to dst including null terminator.
7040 */
7041static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
7042{
7043 unsigned int count;
7044 unsigned int insquares;
7045 unsigned int is_pattern;
7046
7047 if (!dst_size--) {
7048 /* There really is no dst buffer */
7049 return 0;
7050 }
7051
7052 count = 0;
7053 insquares = 0;
7054 is_pattern = *src == '_';
7055 while (*src && count < dst_size) {
7056 if (*src == '[') {
7057 if (is_pattern) {
7058 insquares = 1;
7059 }
7060 } else if (*src == ']') {
7061 insquares = 0;
7062 } else if (*src == ' ' && !insquares) {
7063 ++src;
7064 continue;
7065 } else if (*src == '-' && !insquares && nofluff) {
7066 ++src;
7067 continue;
7068 }
7069 *dst++ = *src++;
7070 ++count;
7071 }
7072 *dst = '\0';
7073
7074 return count + 1;
7075}
7076
7077/*!
7078 * \brief add the extension in the priority chain.
7079 * \retval 0 on success.
7080 * \retval -1 on failure.
7081*/
7082static int add_priority(struct ast_context *con, struct ast_exten *tmp,
7083 struct ast_exten *el, struct ast_exten *e, int replace)
7084{
7085 struct ast_exten *ep;
7086 struct ast_exten *eh=e;
7087 int repeated_label = 0; /* Track if this label is a repeat, assume no. */
7088
7089 for (ep = NULL; e ; ep = e, e = e->peer) {
7090 if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
7091 if (strcmp(e->name, tmp->name)) {
7093 "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
7094 tmp->name, tmp->priority, con->name, tmp->label, e->name, e->priority);
7095 } else {
7097 "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
7098 tmp->name, tmp->priority, con->name, tmp->label, e->priority);
7099 }
7100 repeated_label = 1;
7101 }
7102 if (e->priority >= tmp->priority) {
7103 break;
7104 }
7105 }
7106
7107 if (repeated_label) { /* Discard the label since it's a repeat. */
7108 tmp->label = NULL;
7109 }
7110
7111 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
7113
7114 if (tmp->label) {
7116 }
7117 ep->peer = tmp;
7118 return 0; /* success */
7119 }
7120 if (e->priority == tmp->priority) {
7121 /* Can't have something exactly the same. Is this a
7122 replacement? If so, replace, otherwise, bonk. */
7123 if (!replace) {
7124 if (strcmp(e->name, tmp->name)) {
7126 "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
7127 tmp->name, tmp->priority, con->name, e->name);
7128 } else {
7130 "Unable to register extension '%s' priority %d in '%s', already in use\n",
7131 tmp->name, tmp->priority, con->name);
7132 }
7133
7134 return -1;
7135 }
7136 /* we are replacing e, so copy the link fields and then update
7137 * whoever pointed to e to point to us
7138 */
7139 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
7140 tmp->peer = e->peer; /* always meaningful */
7141 if (ep) { /* We're in the peer list, just insert ourselves */
7143
7144 if (e->label) {
7146 }
7147
7149 if (tmp->label) {
7151 }
7152
7153 ep->peer = tmp;
7154 } else if (el) { /* We're the first extension. Take over e's functions */
7155 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7156 tmp->peer_table = e->peer_table;
7160 if (e->label) {
7162 }
7163 if (tmp->label) {
7165 }
7166
7169 el->next = tmp;
7170 /* The pattern trie points to this exten; replace the pointer,
7171 and all will be well */
7172 if (x) { /* if the trie isn't formed yet, don't sweat this */
7173 if (x->exten) { /* this test for safety purposes */
7174 x->exten = tmp; /* replace what would become a bad pointer */
7175 } else {
7176 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7177 }
7178 }
7179 } else { /* We're the very first extension. */
7180 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
7183 tmp->peer_table = e->peer_table;
7187 if (e->label) {
7189 }
7190 if (tmp->label) {
7192 }
7193
7196 con->root = tmp;
7197 /* The pattern trie points to this exten; replace the pointer,
7198 and all will be well */
7199 if (x) { /* if the trie isn't formed yet; no problem */
7200 if (x->exten) { /* this test for safety purposes */
7201 x->exten = tmp; /* replace what would become a bad pointer */
7202 } else {
7203 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
7204 }
7205 }
7206 }
7207 if (tmp->priority == PRIORITY_HINT)
7208 ast_change_hint(e,tmp);
7209 /* Destroy the old one */
7210 if (e->datad)
7211 e->datad(e->data);
7212 ast_free(e);
7213 } else { /* Slip ourselves in just before e */
7214 tmp->peer = e;
7215 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
7216 if (ep) { /* Easy enough, we're just in the peer list */
7217 if (tmp->label) {
7219 }
7221 ep->peer = tmp;
7222 } else { /* we are the first in some peer list, so link in the ext list */
7223 tmp->peer_table = e->peer_table;
7225 e->peer_table = 0;
7226 e->peer_label_table = 0;
7228 if (tmp->label) {
7230 }
7233 if (el)
7234 el->next = tmp; /* in the middle... */
7235 else
7236 con->root = tmp; /* ... or at the head */
7237 e->next = NULL; /* e is no more at the head, so e->next must be reset */
7238 }
7239 /* And immediately return success. */
7240 if (tmp->priority == PRIORITY_HINT) {
7241 ast_add_hint(tmp);
7242 }
7243 }
7244 return 0;
7245}
7246
7247/*! \brief
7248 * Main interface to add extensions to the list for out context.
7249 *
7250 * We sort extensions in order of matching preference, so that we can
7251 * stop the search as soon as we find a suitable match.
7252 * This ordering also takes care of wildcards such as '.' (meaning
7253 * "one or more of any character") and '!' (which is 'earlymatch',
7254 * meaning "zero or more of any character" but also impacts the
7255 * return value from CANMATCH and EARLYMATCH.
7256 *
7257 * The extension match rules defined in the devmeeting 2006.05.05 are
7258 * quite simple: WE SELECT THE LONGEST MATCH.
7259 * In detail, "longest" means the number of matched characters in
7260 * the extension. In case of ties (e.g. _XXX and 333) in the length
7261 * of a pattern, we give priority to entries with the smallest cardinality
7262 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
7263 * while the latter has 7, etc.
7264 * In case of same cardinality, the first element in the range counts.
7265 * If we still have a tie, any final '!' will make this as a possibly
7266 * less specific pattern.
7267 *
7268 * EBUSY - can't lock
7269 * EEXIST - extension with the same priority exist and no replace is set
7270 *
7271 */
7273 int replace, const char *extension, int priority, const char *label, const char *callerid,
7274 const char *application, void *data, void (*datad)(void *),
7275 const char *registrar, const char *registrar_file, int registrar_line)
7276{
7277 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
7278 application, data, datad, registrar, registrar_file, registrar_line, 1);
7279}
7280
7282 int replace, const char *extension, int priority, const char *label, const char *callerid,
7283 const char *application, void *data, void (*datad)(void *),
7284 const char *registrar, const char *registrar_file, int registrar_line)
7285{
7286 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
7287 application, data, datad, registrar, registrar_file, registrar_line, 0);
7288}
7289
7290
7291/*!
7292 * \brief Same as ast_add_extension2() but controls the context locking.
7293 *
7294 * \details
7295 * Does all the work of ast_add_extension2, but adds an arg to
7296 * determine if context locking should be done.
7297 */
7299 int replace, const char *extension, int priority, const char *label, const char *callerid,
7300 const char *application, void *data, void (*datad)(void *),
7301 const char *registrar, const char *registrar_file, int registrar_line, int lock_context)
7302{
7303 /*
7304 * Sort extensions (or patterns) according to the rules indicated above.
7305 * These are implemented by the function ext_cmp()).
7306 * All priorities for the same ext/pattern/cid are kept in a list,
7307 * using the 'peer' field as a link field..
7308 */
7309 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
7310 int res;
7311 int length;
7312 char *p;
7313 char expand_buf[VAR_BUF_SIZE];
7314 struct ast_exten dummy_exten = {0};
7315 char dummy_name[1024];
7316 int exten_fluff;
7317 int callerid_fluff;
7318
7320 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",
7321 con->name);
7322 /* We always need to deallocate 'data' on failure */
7323 if (datad) {
7324 datad(data);
7325 }
7326 return -1;
7327 }
7328
7329 /* If we are adding a hint evaluate in variables and global variables */
7330 if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
7331 int inhibited;
7333
7334 if (c) {
7337 }
7338
7339 /*
7340 * We can allow dangerous functions when adding a hint since
7341 * altering dialplan is itself a privileged activity. Otherwise,
7342 * we could never execute dangerous functions.
7343 */
7345 pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
7346 if (0 < inhibited) {
7348 }
7349
7350 application = expand_buf;
7351 if (c) {
7353 }
7354 }
7355
7356 if (priority == PRIORITY_HINT) {
7357 /* Fluff in a hint is fine. This prevents the removal of dashes from dynamically
7358 * created hints during a reload. */
7359 exten_fluff = 0;
7360 } else {
7361 exten_fluff = ext_fluff_count(extension);
7362 }
7363
7364 callerid_fluff = callerid ? ext_fluff_count(callerid) : 0;
7365
7366 length = sizeof(struct ast_exten);
7367 length += strlen(extension) + 1;
7368 if (exten_fluff) {
7369 length += strlen(extension) + 1 - exten_fluff;
7370 }
7371 length += strlen(application) + 1;
7372 if (label) {
7373 length += strlen(label) + 1;
7374 }
7375 if (callerid) {
7376 length += strlen(callerid) + 1;
7377 if (callerid_fluff) {
7378 length += strlen(callerid) + 1 - callerid_fluff;
7379 }
7380 } else {
7381 length ++; /* just the '\0' */
7382 }
7383 if (registrar_file) {
7384 length += strlen(registrar_file) + 1;
7385 }
7386
7387 /* Be optimistic: Build the extension structure first */
7388 tmp = ast_calloc(1, length);
7389 if (!tmp) {
7390 /* We always need to deallocate 'data' on failure */
7391 if (datad) {
7392 datad(data);
7393 }
7394 return -1;
7395 }
7396
7397 if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
7398 label = 0;
7399
7400 /* use p as dst in assignments, as the fields are const char * */
7401 p = tmp->stuff;
7402 if (label) {
7403 tmp->label = p;
7404 strcpy(p, label);
7405 p += strlen(label) + 1;
7406 }
7407 tmp->name = p;
7408 p += ext_strncpy(p, extension, strlen(extension) + 1, 0);
7409 if (exten_fluff) {
7410 tmp->exten = p;
7411 p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
7412 } else {
7413 /* no fluff, we don't need a copy. */
7414 tmp->exten = tmp->name;
7415 }
7416 tmp->priority = priority;
7417 tmp->cidmatch_display = tmp->cidmatch = p; /* but use p for assignments below */
7418
7419 /* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */
7420 if (callerid) {
7421 p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
7422 if (callerid_fluff) {
7423 tmp->cidmatch = p;
7424 p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
7425 }
7427 } else {
7428 *p++ = '\0';
7430 }
7431
7432 if (registrar_file) {
7433 tmp->registrar_file = p;
7434 strcpy(p, registrar_file);
7435 p += strlen(registrar_file) + 1;
7436 } else {
7437 tmp->registrar_file = NULL;
7438 }
7439
7440 tmp->app = p;
7441 strcpy(p, application);
7442 tmp->parent = con;
7443 tmp->data = data;
7444 tmp->datad = datad;
7445 tmp->registrar = registrar;
7447
7448 if (lock_context) {
7449 ast_wrlock_context(con);
7450 }
7451
7452 if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
7453 an extension, and the trie exists, then we need to incrementally add this pattern to it. */
7454 ext_strncpy(dummy_name, tmp->exten, sizeof(dummy_name), 1);
7455 dummy_exten.exten = dummy_name;
7456 dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
7457 dummy_exten.cidmatch = 0;
7458 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
7459 if (!tmp2) {
7460 /* hmmm, not in the trie; */
7461 add_exten_to_pattern_tree(con, tmp, 0);
7462 ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
7463 }
7464 }
7465 res = 0; /* some compilers will think it is uninitialized otherwise */
7466 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
7467 res = ext_cmp(e->exten, tmp->exten);
7468 if (res == 0) { /* extension match, now look at cidmatch */
7470 res = 0;
7472 res = 1;
7474 res = -1;
7475 else
7476 res = ext_cmp(e->cidmatch, tmp->cidmatch);
7477 }
7478 if (res >= 0)
7479 break;
7480 }
7481 if (e && res == 0) { /* exact match, insert in the priority chain */
7482 res = add_priority(con, tmp, el, e, replace);
7483 if (res < 0) {
7484 if (con->pattern_tree) {
7485 struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
7486
7487 if (x->exten) {
7488 x->deleted = 1;
7489 x->exten = 0;
7490 }
7491
7493 }
7494
7495 if (tmp->datad) {
7496 tmp->datad(tmp->data);
7497 /* if you free this, null it out */
7498 tmp->data = NULL;
7499 }
7500
7501 ast_free(tmp);
7502 }
7503 if (lock_context) {
7504 ast_unlock_context(con);
7505 }
7506 if (res < 0) {
7507 errno = EEXIST;
7508 return -1;
7509 }
7510 } else {
7511 /*
7512 * not an exact match, this is the first entry with this pattern,
7513 * so insert in the main list right before 'e' (if any)
7514 */
7515 tmp->next = e;
7521 0);
7527 0);
7528
7529 if (el) { /* there is another exten already in this context */
7530 el->next = tmp;
7531 } else { /* this is the first exten in this context */
7532 if (!con->root_table) {
7538 0);
7539 }
7540 con->root = tmp;
7541 }
7542 if (label) {
7544 }
7547
7548 if (lock_context) {
7549 ast_unlock_context(con);
7550 }
7551 if (tmp->priority == PRIORITY_HINT) {
7552 ast_add_hint(tmp);
7553 }
7554 }
7555 if (DEBUG_ATLEAST(1)) {
7556 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
7557 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
7558 tmp->name, tmp->priority, tmp->cidmatch_display, con->name, con);
7559 } else {
7560 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s (%p)\n",
7561 tmp->name, tmp->priority, con->name, con);
7562 }
7563 }
7564
7565 return 0;
7566}
7567
7568/*! \brief Structure which contains information about an outgoing dial */
7570 /*! \brief Dialing structure being used */
7572 /*! \brief Condition for synchronous dialing */
7574 /*! \brief Application to execute */
7576 /*! \brief Application data to pass to application */
7577 char *appdata;
7578 /*! \brief Dialplan context */
7580 /*! \brief Dialplan extension */
7582 /*! \brief Dialplan priority */
7584 /*! \brief Result of the dial operation when dialed is set */
7586 /*! \brief Set when dialing is completed */
7587 unsigned int dialed:1;
7588 /*! \brief Set if we've spawned a thread to do our work */
7589 unsigned int in_separate_thread:1;
7590};
7591
7592/*! \brief Destructor for outgoing structure */
7593static void pbx_outgoing_destroy(void *obj)
7594{
7595 struct pbx_outgoing *outgoing = obj;
7596
7597 if (outgoing->dial) {
7599 }
7600
7601 ast_cond_destroy(&outgoing->cond);
7602
7603 ast_free(outgoing->appdata);
7604}
7605
7606/*! \brief Internal function which dials an outgoing leg and sends it to a provided extension or application */
7607static void *pbx_outgoing_exec(void *data)
7608{
7609 RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
7610 enum ast_dial_result res;
7611 struct ast_channel *chan;
7612
7613 res = ast_dial_run(outgoing->dial, NULL, 0);
7614
7615 if (outgoing->in_separate_thread) {
7616 /* Notify anyone interested that dialing is complete */
7618 outgoing->dial_res = res;
7619 outgoing->dialed = 1;
7620 ast_cond_signal(&outgoing->cond);
7622 } else {
7623 /* We still need the dial result, but we don't need to lock */
7624 outgoing->dial_res = res;
7625 }
7626
7627 /* If the outgoing leg was not answered we can immediately return and go no further */
7628 if (res != AST_DIAL_RESULT_ANSWERED) {
7629 return NULL;
7630 }
7631
7632 /* We steal the channel so we get ownership of when it is hung up */
7633 chan = ast_dial_answered_steal(outgoing->dial);
7634
7635 if (!ast_strlen_zero(outgoing->app)) {
7636 struct ast_app *app = pbx_findapp(outgoing->app);
7637
7638 if (app) {
7639 ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
7640 ast_channel_name(chan));
7641 pbx_exec(chan, app, outgoing->appdata);
7642 } else {
7643 ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app);
7644 }
7645
7646 ast_hangup(chan);
7647 } else {
7650 }
7651
7654 }
7655
7656 if (outgoing->priority > 0) {
7658 }
7659
7660 if (ast_pbx_run(chan)) {
7661 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan));
7662 ast_hangup(chan);
7663 }
7664 }
7665
7666 return NULL;
7667}
7668
7669/*! \brief Internal dialing state callback which causes early media to trigger an answer */
7670static void pbx_outgoing_state_callback(struct ast_dial *dial)
7671{
7672 struct ast_channel *channel;
7673
7675 return;
7676 }
7677
7678 if (!(channel = ast_dial_get_channel(dial, 0))) {
7679 return;
7680 }
7681
7682 ast_verb(4, "Treating progress as answer on '%s' due to early media option\n",
7683 ast_channel_name(channel));
7684
7686}
7687
7688/*!
7689 * \brief Attempt to convert disconnect cause to old originate reason.
7690 *
7691 * \todo XXX The old originate reasons need to be trashed and replaced
7692 * with normal disconnect cause codes if the call was not answered.
7693 * The internal consumers of the reason values would also need to be
7694 * updated: app_originate, call files, and AMI OriginateResponse.
7695 */
7696static enum ast_control_frame_type pbx_dial_reason(enum ast_dial_result dial_result, int cause)
7697{
7698 enum ast_control_frame_type pbx_reason;
7699
7700 if (dial_result == AST_DIAL_RESULT_ANSWERED) {
7701 /* Remote end answered. */
7702 pbx_reason = AST_CONTROL_ANSWER;
7703 } else if (dial_result == AST_DIAL_RESULT_HANGUP) {
7704 /* Caller hungup */
7705 pbx_reason = AST_CONTROL_HANGUP;
7706 } else {
7707 switch (cause) {
7709 pbx_reason = AST_CONTROL_BUSY;
7710 break;
7717 pbx_reason = AST_CONTROL_CONGESTION;
7718 break;
7721 /* Remote end was ringing (but isn't anymore) */
7722 pbx_reason = AST_CONTROL_RINGING;
7723 break;
7725 default:
7726 /* Call Failure (not BUSY, and not NO_ANSWER, maybe Circuit busy or down?) */
7727 pbx_reason = 0;
7728 break;
7729 }
7730 }
7731
7732 return pbx_reason;
7733}
7734
7735static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
7736 const char *addr, int timeout, const char *context, const char *exten, int priority,
7737 const char *app, const char *appdata, int *reason, int synchronous,
7738 const char *cid_num, const char *cid_name, struct ast_variable *vars,
7739 const char *account, struct ast_channel **locked_channel, int early_media,
7740 const struct ast_assigned_ids *assignedids, const char *predial_callee)
7741{
7743 struct ast_channel *dialed;
7744 pthread_t thread;
7745 char tmp_cid_name[128];
7746 char tmp_cid_num[128];
7747
7749 if (!outgoing) {
7750 return -1;
7751 }
7752 ast_cond_init(&outgoing->cond, NULL);
7753
7754 if (!ast_strlen_zero(app)) {
7756 outgoing->appdata = ast_strdup(appdata);
7757 } else {
7761 }
7762
7763 if (!(outgoing->dial = ast_dial_create())) {
7764 return -1;
7765 }
7766
7767 if (ast_dial_append(outgoing->dial, type, addr, assignedids)) {
7768 return -1;
7769 }
7770
7771 ast_dial_set_global_timeout(outgoing->dial, timeout);
7772
7773 if (!ast_strlen_zero(predial_callee)) {
7774 /* note casting to void * here to suppress compiler warning message (passing const to non-const function) */
7775 ast_dial_option_global_enable(outgoing->dial, AST_DIAL_OPTION_PREDIAL, (void *)predial_callee);
7776 }
7777
7778 if (ast_dial_prerun(outgoing->dial, NULL, cap)) {
7779 if (synchronous && reason) {
7781 ast_dial_reason(outgoing->dial, 0));
7782 }
7783 return -1;
7784 }
7785
7787 if (!dialed) {
7788 return -1;
7789 }
7790
7792 if (vars) {
7794 }
7795 if (!ast_strlen_zero(account)) {
7797 ast_channel_accountcode_set(dialed, account);
7798 ast_channel_peeraccount_set(dialed, account);
7800 }
7802
7803 if (!ast_strlen_zero(predial_callee)) {
7804 char *tmp = NULL;
7805 /*
7806 * The predial sub routine may have set callerid so set this into the new channel
7807 * Note... cid_num and cid_name parameters to this function will always be NULL if
7808 * predial_callee is non-NULL so we are not overwriting anything here.
7809 */
7811 if (tmp) {
7812 ast_copy_string(tmp_cid_num, tmp, sizeof(tmp_cid_num));
7813 cid_num = tmp_cid_num;
7814 }
7816 if (tmp) {
7817 ast_copy_string(tmp_cid_name, tmp, sizeof(tmp_cid_name));
7818 cid_name = tmp_cid_name;
7819 }
7820 }
7822
7823 if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
7825
7826 /*
7827 * It seems strange to set the CallerID on an outgoing call leg
7828 * to whom we are calling, but this function's callers are doing
7829 * various Originate methods. This call leg goes to the local
7830 * user. Once the called party answers, the dialplan needs to
7831 * be able to access the CallerID from the CALLERID function as
7832 * if the called party had placed this call.
7833 */
7834 ast_set_callerid(dialed, cid_num, cid_name, cid_num);
7835
7837 if (!ast_strlen_zero(cid_num)) {
7838 connected.id.number.valid = 1;
7839 connected.id.number.str = (char *) cid_num;
7841 }
7842 if (!ast_strlen_zero(cid_name)) {
7843 connected.id.name.valid = 1;
7844 connected.id.name.str = (char *) cid_name;
7846 }
7848 }
7849
7850 if (early_media) {
7852 }
7853
7854 if (locked_channel) {
7855 /*
7856 * Keep a dialed channel ref since the caller wants
7857 * the channel returned. We must get the ref before
7858 * spawning off pbx_outgoing_exec().
7859 */
7860 ast_channel_ref(dialed);
7861 if (!synchronous) {
7862 /*
7863 * Lock it now to hold off pbx_outgoing_exec() in case the
7864 * calling function needs the channel state/snapshot before
7865 * dialing actually happens.
7866 */
7867 ast_channel_lock(dialed);
7868 }
7869 }
7870
7871 /* This extra reference is dereferenced by pbx_outgoing_exec */
7872 ao2_ref(outgoing, +1);
7873
7874 if (synchronous == AST_OUTGOING_WAIT_COMPLETE) {
7875 /*
7876 * Because we are waiting until this is complete anyway, there is no
7877 * sense in creating another thread that we will just need to wait
7878 * for, so instead we commandeer the current thread.
7879 */
7881 } else {
7882 outgoing->in_separate_thread = 1;
7883
7885 ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
7886 ao2_ref(outgoing, -1);
7887 if (locked_channel) {
7888 if (!synchronous) {
7889 ast_channel_unlock(dialed);
7890 }
7891 ast_channel_unref(dialed);
7892 }
7893 return -1;
7894 }
7895
7896 if (synchronous) {
7898 /* Wait for dialing to complete */
7899 while (!outgoing->dialed) {
7901 }
7903 }
7904 }
7905
7906 if (synchronous) {
7907 /* Determine the outcome of the dialing attempt up to it being answered. */
7908 if (reason) {
7909 *reason = pbx_dial_reason(outgoing->dial_res,
7910 ast_dial_reason(outgoing->dial, 0));
7911 }
7912
7913 if (outgoing->dial_res != AST_DIAL_RESULT_ANSWERED) {
7914 /* The dial operation failed. */
7915 if (locked_channel) {
7916 ast_channel_unref(dialed);
7917 }
7918 return -1;
7919 }
7920 if (locked_channel) {
7921 ast_channel_lock(dialed);
7922 }
7923 }
7924
7925 if (locked_channel) {
7926 *locked_channel = dialed;
7927 }
7928 return 0;
7929}
7930
7931int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
7932 int timeout, const char *context, const char *exten, int priority, int *reason,
7933 int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
7934 const char *account, struct ast_channel **locked_channel, int early_media,
7935 const struct ast_assigned_ids *assignedids)
7936{
7937 return ast_pbx_outgoing_exten_predial(type, cap, addr, timeout, context, exten, priority, reason,
7938 synchronous, cid_num, cid_name, vars, account, locked_channel, early_media, assignedids, NULL);
7939}
7940
7941int ast_pbx_outgoing_exten_predial(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, const char *predial_callee)
7946{
7947 int res;
7948 int my_reason;
7949
7950 if (!reason) {
7951 reason = &my_reason;
7952 }
7953 *reason = 0;
7954 if (locked_channel) {
7955 *locked_channel = NULL;
7956 }
7957
7958 res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
7959 NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
7960 early_media, assignedids, predial_callee);
7961
7962 if (res < 0 /* Call failed to get connected for some reason. */
7963 && 0 < synchronous
7964 && ast_exists_extension(NULL, context, "failed", 1, NULL)) {
7965 struct ast_channel *failed;
7966
7967 /* We do not have to worry about a locked_channel if dialing failed. */
7968 ast_assert(!locked_channel || !*locked_channel);
7969
7970 /*!
7971 * \todo XXX Not good. The channel name is not unique if more than
7972 * one originate fails at a time.
7973 */
7974 failed = ast_channel_alloc(0, AST_STATE_DOWN, cid_num, cid_name, account,
7975 "failed", context, NULL, NULL, 0, "OutgoingSpoolFailed");
7976 if (failed) {
7977 char failed_reason[12];
7978
7979 ast_set_variables(failed, vars);
7980 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
7981 pbx_builtin_setvar_helper(failed, "REASON", failed_reason);
7982 ast_channel_unlock(failed);
7983
7984 if (ast_pbx_run(failed)) {
7985 ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n",
7986 ast_channel_name(failed));
7987 ast_hangup(failed);
7988 }
7989 }
7990 }
7991
7992 return res;
7993}
7994
7995int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
7996 int timeout, const char *app, const char *appdata, int *reason, int synchronous,
7997 const char *cid_num, const char *cid_name, struct ast_variable *vars,
7998 const char *account, struct ast_channel **locked_channel,
7999 const struct ast_assigned_ids *assignedids)
8000{
8001 return ast_pbx_outgoing_app_predial(type, cap, addr, timeout, app, appdata, reason, synchronous,
8002 cid_num, cid_name, vars, account, locked_channel, assignedids, NULL);
8003}
8004
8005int ast_pbx_outgoing_app_predial(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, const char *predial_callee)
8010{
8011 if (reason) {
8012 *reason = 0;
8013 }
8014 if (locked_channel) {
8015 *locked_channel = NULL;
8016 }
8017 if (ast_strlen_zero(app)) {
8018 return -1;
8019 }
8020
8021 return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
8022 reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
8023 assignedids, predial_callee);
8024}
8025
8026/* this is the guts of destroying a context --
8027 freeing up the structure, traversing and destroying the
8028 extensions, switches, ignorepats, includes, etc. etc. */
8029
8031{
8032 struct ast_exten *e, *el, *en;
8033 struct ast_context *tmp = con;
8034
8035 /* Free includes */
8038
8039 /* Free ignorepats */
8042
8043 /* Free switches */
8045 AST_VECTOR_FREE(&tmp->alts);
8046
8047 /* destroy the hash tabs */
8048 if (tmp->root_table) {
8050 }
8051 /* and destroy the pattern tree */
8052 if (tmp->pattern_tree)
8054
8055 for (e = tmp->root; e;) {
8056 for (en = e->peer; en;) {
8057 el = en;
8058 en = en->peer;
8060 }
8061 el = e;
8062 e = e->next;
8064 }
8065 tmp->root = NULL;
8066 ast_rwlock_destroy(&tmp->lock);
8067 ast_free(tmp);
8068}
8069
8070
8071void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
8072{
8073 struct ast_context *tmp, *tmpl=NULL;
8074 struct ast_exten *exten_item, *prio_item;
8075
8076 for (tmp = list; tmp; ) {
8077 struct ast_context *next = NULL; /* next starting point */
8078 /* The following code used to skip forward to the next
8079 context with matching registrar, but this didn't
8080 make sense; individual priorities registrar'd to
8081 the matching registrar could occur in any context! */
8082 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
8083 if (con) {
8084 for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
8085 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
8086 if ( !strcasecmp(tmp->name, con->name) ) {
8087 break; /* found it */
8088 }
8089 }
8090 }
8091
8092 if (!tmp) /* not found, we are done */
8093 break;
8094 ast_wrlock_context(tmp);
8095
8096 if (registrar) {
8097 /* then search thru and remove any extens that match registrar. */
8098 struct ast_hashtab_iter *exten_iter;
8099 struct ast_hashtab_iter *prio_iter;
8100 int idx;
8101
8102 /* remove any ignorepats whose registrar matches */
8103 for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) {
8104 struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx);
8105
8106 if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
8108 ignorepat_free(ip);
8109 }
8110 }
8111 /* remove any includes whose registrar matches */
8112 for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) {
8113 struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx);
8114
8115 if (!strcmp(ast_get_include_registrar(i), registrar)) {
8117 include_free(i);
8118 }
8119 }
8120 /* remove any switches whose registrar matches */
8121 for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) {
8122 struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx);
8123
8124 if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
8125 AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx);
8126 sw_free(sw);
8127 }
8128 }
8129
8130 if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
8131 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
8132 while ((exten_item=ast_hashtab_next(exten_iter))) {
8133 int end_traversal = 1;
8134
8135 /*
8136 * If the extension could not be removed from the root_table due to
8137 * a loaded PBX app, it can exist here but have its peer_table be
8138 * destroyed due to a previous pass through this function.
8139 */
8140 if (!exten_item->peer_table) {
8141 continue;
8142 }
8143
8144 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
8145 while ((prio_item=ast_hashtab_next(prio_iter))) {
8147 char cidmatch[AST_MAX_EXTENSION];
8148 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
8149 continue;
8150 }
8151 ast_verb(5, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
8152 tmp->name, prio_item->name, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
8153 ast_copy_string(extension, prio_item->exten, sizeof(extension));
8154 if (prio_item->cidmatch) {
8155 ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
8156 }
8157 end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
8158 }
8159 /* Explanation:
8160 * ast_context_remove_extension_callerid2 will destroy the extension that it comes across. This
8161 * destruction includes destroying the exten's peer_table, which we are currently traversing. If
8162 * ast_context_remove_extension_callerid2 ever should return '0' then this means we have destroyed
8163 * the hashtable which we are traversing, and thus calling ast_hashtab_end_traversal will result
8164 * in reading invalid memory. Thus, if we detect that we destroyed the hashtable, then we will simply
8165 * free the iterator
8166 */
8167 if (end_traversal) {
8168 ast_hashtab_end_traversal(prio_iter);
8169 } else {
8170 ast_free(prio_iter);
8171 }
8172 }
8173 ast_hashtab_end_traversal(exten_iter);
8174 }
8175
8176 /* delete the context if it's registrar matches, is empty, has refcount of 1, */
8177 /* it's not empty, if it has includes, ignorepats, or switches that are registered from
8178 another registrar. It's not empty if there are any extensions */
8179 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)) {
8180 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
8181 ast_hashtab_remove_this_object(contexttab, tmp);
8182
8183 next = tmp->next;
8184 if (tmpl)
8185 tmpl->next = next;
8186 else
8187 contexts = next;
8188 /* Okay, now we're safe to let it go -- in a sense, we were
8189 ready to let it go as soon as we locked it. */
8190 ast_unlock_context(tmp);
8192 } else {
8193 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
8194 tmp->refcount, tmp->root);
8195 ast_unlock_context(tmp);
8196 next = tmp->next;
8197 tmpl = tmp;
8198 }
8199 } else if (con) {
8200 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
8201 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
8202 ast_hashtab_remove_this_object(contexttab, tmp);
8203
8204 next = tmp->next;
8205 if (tmpl)
8206 tmpl->next = next;
8207 else
8208 contexts = next;
8209 /* Okay, now we're safe to let it go -- in a sense, we were
8210 ready to let it go as soon as we locked it. */
8211 ast_unlock_context(tmp);
8213 }
8214
8215 /* if we have a specific match, we are done, otherwise continue */
8216 tmp = con ? NULL : next;
8217 }
8218}
8219
8220int ast_context_destroy_by_name(const char *context, const char *registrar)
8221{
8222 struct ast_context *con;
8223 int ret = -1;
8224
8227 if (con) {
8229 ret = 0;
8230 }
8232
8233 return ret;
8234}
8235
8236void ast_context_destroy(struct ast_context *con, const char *registrar)
8237{
8241}
8242
8243void wait_for_hangup(struct ast_channel *chan, const void *data)
8244{
8245 int res;
8246 struct ast_frame *f;
8247 double waitsec;
8248 int waittime;
8249
8250 if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
8251 waitsec = -1;
8252 if (waitsec > -1) {
8253 waittime = waitsec * 1000.0;
8254 ast_safe_sleep_without_silence(chan, waittime);
8255 } else do {
8256 res = ast_waitfor(chan, -1);
8257 if (res < 0)
8258 return;
8259 f = ast_read(chan);
8260 if (f)
8261 ast_frfree(f);
8262 } while(f);
8263}
8264
8265/*!
8266 * \ingroup functions
8267 */
8268static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
8269{
8270 struct ast_tm tm;
8271 struct timeval tv;
8272 char *remainder, result[30], timezone[80];
8273
8274 /* Turn off testing? */
8275 if (!pbx_checkcondition(value)) {
8276 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
8277 return 0;
8278 }
8279
8280 /* Parse specified time */
8281 if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
8282 return -1;
8283 }
8284 sscanf(remainder, "%79s", timezone);
8285 tv = ast_mktime(&tm, S_OR(timezone, NULL));
8286
8287 snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
8288 pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
8289 return 0;
8290}
8291
8293 .name = "TESTTIME",
8294 .write = testtime_write,
8295};
8296
8297int pbx_checkcondition(const char *condition)
8298{
8299 int res;
8300 if (ast_strlen_zero(condition)) { /* NULL or empty strings are false */
8301 return 0;
8302 } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
8303 return res;
8304 } else { /* Strings are true */
8305 return 1;
8306 }
8307}
8308
8309static void presence_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
8310{
8311 struct ast_presence_state_message *presence_state;
8312 struct ast_str *hint_app = NULL;
8313 struct ast_hintdevice *device;
8314 struct ast_hintdevice *cmpdevice;
8315 struct ao2_iterator *dev_iter;
8316
8318 return;
8319 }
8320
8321 presence_state = stasis_message_data(msg);
8322
8323 if (ao2_container_count(hintdevices) == 0) {
8324 /* There are no hints monitoring devices. */
8325 return;
8326 }
8327
8328 hint_app = ast_str_create(1024);
8329 if (!hint_app) {
8330 return;
8331 }
8332
8333 cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(presence_state->provider));
8334 strcpy(cmpdevice->hintdevice, presence_state->provider);
8335
8336 ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
8337 dev_iter = ao2_t_callback(hintdevices,
8340 cmpdevice,
8341 "find devices in container");
8342 if (!dev_iter) {
8344 ast_free(hint_app);
8345 return;
8346 }
8347
8348 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
8349 if (device->hint) {
8350 presence_state_notify_callbacks(device->hint, &hint_app, presence_state);
8351 }
8352 }
8353 ao2_iterator_destroy(dev_iter);
8355
8356 ast_free(hint_app);
8357}
8358
8359static int action_extensionstatelist(struct mansession *s, const struct message *m)
8360{
8361 const char *action_id = astman_get_header(m, "ActionID");
8362 struct ast_hint *hint;
8363 struct ao2_iterator it_hints;
8364 int hint_count = 0;
8365
8366 if (!hints) {
8367 astman_send_error(s, m, "No dialplan hints are available");
8368 return 0;
8369 }
8370
8371 astman_send_listack(s, m, "Extension Statuses will follow", "start");
8372
8373 ao2_lock(hints);
8374 it_hints = ao2_iterator_init(hints, 0);
8375 for (; (hint = ao2_iterator_next(&it_hints)); ao2_ref(hint, -1)) {
8376
8377 ao2_lock(hint);
8378
8379 /* Ignore pattern matching hints; they are stored in the
8380 * hints container but aren't real from the perspective of
8381 * an AMI user
8382 */
8383 if (hint->exten->exten[0] == '_') {
8384 ao2_unlock(hint);
8385 continue;
8386 }
8387
8388 ++hint_count;
8389
8390 astman_append(s, "Event: ExtensionStatus\r\n");
8391 if (!ast_strlen_zero(action_id)) {
8392 astman_append(s, "ActionID: %s\r\n", action_id);
8393 }
8394 astman_append(s,
8395 "Exten: %s\r\n"
8396 "Context: %s\r\n"
8397 "Hint: %s\r\n"
8398 "Status: %d\r\n"
8399 "StatusText: %s\r\n\r\n",
8400 hint->exten->exten,
8401 hint->exten->parent->name,
8402 hint->exten->app,
8403 hint->laststate,
8405 ao2_unlock(hint);
8406 }
8407
8408 ao2_iterator_destroy(&it_hints);
8410
8411 astman_send_list_complete_start(s, m, "ExtensionStateListComplete", hint_count);
8413
8414 return 0;
8415}
8416
8417
8418/*!
8419 * \internal
8420 * \brief Clean up resources on Asterisk shutdown.
8421 *
8422 * \note Cleans up resources allocated in load_pbx
8423 */
8424static void unload_pbx(void)
8425{
8428
8429 ast_manager_unregister("ShowDialPlan");
8430 ast_manager_unregister("ExtensionStateList");
8434}
8435
8436int load_pbx(void)
8437{
8438 int res = 0;
8439
8441
8442 /* Initialize the PBX */
8443 ast_verb(1, "Asterisk PBX Core Initializing\n");
8444
8445 ast_verb(5, "Registering builtin functions:\n");
8449
8450 /* Register manager application */
8453
8454 if (res) {
8455 return -1;
8456 }
8457
8459 return -1;
8460 }
8462 stasis_subscription_accept_message_type(device_state_sub, hint_change_message_type());
8463 stasis_subscription_accept_message_type(device_state_sub, hint_remove_message_type());
8465
8467 return -1;
8468 }
8471
8472 return 0;
8473}
8474
8475/*
8476 * Lock context list functions ...
8477 */
8479{
8480 return ast_mutex_lock(&conlock);
8481}
8482
8484{
8485 return ast_mutex_lock(&conlock);
8486}
8487
8489{
8490 return ast_mutex_unlock(&conlock);
8491}
8492
8493/*
8494 * Lock context ...
8495 */
8497{
8498 return ast_rwlock_wrlock(&con->lock);
8499}
8500
8502{
8503 return ast_rwlock_rdlock(&con->lock);
8504}
8505
8507{
8508 return ast_rwlock_unlock(&con->lock);
8509}
8510
8511/*
8512 * Name functions ...
8513 */
8514const char *ast_get_context_name(struct ast_context *con)
8515{
8516 return con ? con->name : NULL;
8517}
8518
8520{
8521 return exten ? exten->parent : NULL;
8522}
8523
8524const char *ast_get_extension_name(struct ast_exten *exten)
8525{
8526 return exten ? exten->name : NULL;
8527}
8528
8529const char *ast_get_extension_label(struct ast_exten *exten)
8530{
8531 return exten ? exten->label : NULL;
8532}
8533
8535{
8536 return exten ? exten->priority : -1;
8537}
8538
8539/*
8540 * Registrar info functions ...
8541 */
8543{
8544 return c ? c->registrar : NULL;
8545}
8546
8548{
8549 return e ? e->registrar : NULL;
8550}
8551
8553{
8554 return e ? e->registrar_file : NULL;
8555}
8556
8558{
8559 return e ? e->registrar_line : 0;
8560}
8561
8563{
8564 return e ? e->matchcid : 0;
8565}
8566
8568{
8569 return e ? e->cidmatch_display : NULL;
8570}
8571
8572const char *ast_get_extension_app(struct ast_exten *e)
8573{
8574 return e ? e->app : NULL;
8575}
8576
8578{
8579 return e ? e->data : NULL;
8580}
8581
8582int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c,
8583 const char *context, const char *exten, int priority)
8584{
8585 struct ast_exten *e;
8586 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
8588 e = pbx_find_extension(c, NULL, &q, context, exten, priority, NULL, "", E_MATCH);
8589 if (e) {
8590 if (buf) {
8591 const char *tmp = ast_get_extension_app_data(e);
8592 if (tmp) {
8593 ast_copy_string(buf, tmp, bufsize);
8594 }
8595 }
8597 return 0;
8598 }
8600 return -1;
8601}
8602
8603/*
8604 * Walking functions ...
8605 */
8607{
8608 return con ? con->next : contexts;
8609}
8610
8612 struct ast_exten *exten)
8613{
8614 if (!exten)
8615 return con ? con->root : NULL;
8616 else
8617 return exten->next;
8618}
8619
8620const struct ast_sw *ast_walk_context_switches(const struct ast_context *con,
8621 const struct ast_sw *sw)
8622{
8623 if (sw) {
8624 int idx;
8625 int next = 0;
8626
8627 for (idx = 0; idx < ast_context_switches_count(con); idx++) {
8628 const struct ast_sw *s = ast_context_switches_get(con, idx);
8629
8630 if (next) {
8631 return s;
8632 }
8633
8634 if (sw == s) {
8635 next = 1;
8636 }
8637 }
8638
8639 return NULL;
8640 }
8641
8642 if (!ast_context_switches_count(con)) {
8643 return NULL;
8644 }
8645
8646 return ast_context_switches_get(con, 0);
8647}
8648
8650{
8651 return AST_VECTOR_SIZE(&con->alts);
8652}
8653
8654const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx)
8655{
8656 return AST_VECTOR_GET(&con->alts, idx);
8657}
8658
8660 struct ast_exten *priority)
8661{
8662 return priority ? priority->peer : exten;
8663}
8664
8665const struct ast_include *ast_walk_context_includes(const struct ast_context *con,
8666 const struct ast_include *inc)
8667{
8668 if (inc) {
8669 int idx;
8670 int next = 0;
8671
8672 for (idx = 0; idx < ast_context_includes_count(con); idx++) {
8673 const struct ast_include *include = AST_VECTOR_GET(&con->includes, idx);
8674
8675 if (next) {
8676 return include;
8677 }
8678
8679 if (inc == include) {
8680 next = 1;
8681 }
8682 }
8683
8684 return NULL;
8685 }
8686
8687 if (!ast_context_includes_count(con)) {
8688 return NULL;
8689 }
8690
8691 return ast_context_includes_get(con, 0);
8692}
8693
8695{
8696 return AST_VECTOR_SIZE(&con->includes);
8697}
8698
8699const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx)
8700{
8701 return AST_VECTOR_GET(&con->includes, idx);
8702}
8703
8705 const struct ast_ignorepat *ip)
8706{
8707 if (!con) {
8708 return NULL;
8709 }
8710
8711 if (ip) {
8712 int idx;
8713 int next = 0;
8714
8715 for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
8716 const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
8717
8718 if (next) {
8719 return i;
8720 }
8721
8722 if (ip == i) {
8723 next = 1;
8724 }
8725 }
8726
8727 return NULL;
8728 }
8729
8730 if (!ast_context_ignorepats_count(con)) {
8731 return NULL;
8732 }
8733
8734 return ast_context_ignorepats_get(con, 0);
8735}
8736
8738{
8739 return AST_VECTOR_SIZE(&con->ignorepats);
8740}
8741
8742const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx)
8743{
8744 return AST_VECTOR_GET(&con->ignorepats, idx);
8745}
8746
8748{
8749 int idx;
8750 int res = 0;
8751 int includecount = ast_context_includes_count(con);
8752
8753 if (includecount >= AST_PBX_MAX_STACK) {
8754 ast_log(LOG_WARNING, "Context %s contains too many includes (%d). Maximum is %d.\n",
8755 ast_get_context_name(con), includecount, AST_PBX_MAX_STACK);
8756 }
8757
8758 for (idx = 0; idx < includecount; idx++) {
8759 const struct ast_include *inc = ast_context_includes_get(con, idx);
8760
8761 if (ast_context_find(include_rname(inc))) {
8762 continue;
8763 }
8764
8765 res = -1;
8766 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
8768 break;
8769 }
8770
8771 return res;
8772}
8773
8774
8775static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
8776{
8777 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
8778
8779 if (!chan)
8780 return -2;
8781
8782 if (context == NULL)
8784 if (exten == NULL)
8785 exten = ast_channel_exten(chan);
8786
8787 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
8789 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)))
8790 return goto_func(chan, context, exten, priority);
8791 else {
8792 return AST_PBX_GOTO_FAILED;
8793 }
8794}
8795
8796int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
8797{
8798 return __ast_goto_if_exists(chan, context, exten, priority, 0);
8799}
8800
8801int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
8802{
8803 return __ast_goto_if_exists(chan, context, exten, priority, 1);
8804}
8805
8806int pbx_parse_location(struct ast_channel *chan, char **contextp, char **extenp, char **prip, int *ipri, int *mode, char *rest)
8807{
8808 char *context, *exten, *pri;
8809 /* do the strsep before here, so we don't have to alloc and free */
8810 if (!*extenp) {
8811 /* Only a priority in this one */
8812 *prip = *contextp;
8813 *extenp = NULL;
8814 *contextp = NULL;
8815 } else if (!*prip) {
8816 /* Only an extension and priority in this one */
8817 *prip = *extenp;
8818 *extenp = *contextp;
8819 *contextp = NULL;
8820 }
8821 context = *contextp;
8822 exten = *extenp;
8823 pri = *prip;
8824 if (mode) {
8825 if (*pri == '+') {
8826 *mode = 1;
8827 pri++;
8828 } else if (*pri == '-') {
8829 *mode = -1;
8830 pri++;
8831 }
8832 }
8833 if ((rest && sscanf(pri, "%30d%1s", ipri, rest) != 1) || sscanf(pri, "%30d", ipri) != 1) {
8835 exten ? exten : ast_channel_exten(chan), pri,
8836 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
8837 if (*ipri < 1) {
8838 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
8839 return -1;
8840 } else if (mode) {
8841 *mode = 0;
8842 }
8843 }
8844 return 0;
8845}
8846
8847static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
8848{
8849 char *exten, *pri, *context;
8850 char *stringp;
8851 int ipri;
8852 int mode = 0;
8853 char rest[2] = "";
8854
8855 if (ast_strlen_zero(goto_string)) {
8856 ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
8857 return -1;
8858 }
8859 stringp = ast_strdupa(goto_string);
8860 context = strsep(&stringp, ","); /* guaranteed non-null */
8861 exten = strsep(&stringp, ",");
8862 pri = strsep(&stringp, ",");
8863
8864 if (pbx_parse_location(chan, &context, &exten, &pri, &ipri, &mode, rest)) {
8865 return -1;
8866 }
8867 /* At this point we have a priority and maybe an extension and a context */
8868
8869 if (mode)
8870 ipri = ast_channel_priority(chan) + (ipri * mode);
8871
8872 if (async)
8873 ast_async_goto(chan, context, exten, ipri);
8874 else
8875 ast_explicit_goto(chan, context, exten, ipri);
8876
8877 return 0;
8878
8879}
8880
8881int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
8882{
8883 return pbx_parseable_goto(chan, goto_string, 0);
8884}
8885
8886int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
8887{
8888 return pbx_parseable_goto(chan, goto_string, 1);
8889}
8890
8891static int hint_hash(const void *obj, const int flags)
8892{
8893 const struct ast_hint *hint = obj;
8894 const char *exten_name;
8895 int res;
8896
8899 /*
8900 * If the exten or extension name isn't set, return 0 so that
8901 * the ao2_find() search will start in the first bucket.
8902 */
8903 res = 0;
8904 } else {
8906 }
8907
8908 return res;
8909}
8910
8911static int hint_cmp(void *obj, void *arg, int flags)
8912{
8913 const struct ast_hint *hint = obj;
8914 const struct ast_exten *exten = arg;
8915
8916 return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
8917}
8918
8919static int statecbs_cmp(void *obj, void *arg, int flags)
8920{
8921 const struct ast_state_cb *state_cb = obj;
8923
8924 return (state_cb->change_cb == change_cb) ? CMP_MATCH | CMP_STOP : 0;
8925}
8926
8927/*!
8928 * \internal
8929 * \brief Clean up resources on Asterisk shutdown
8930 */
8931static void pbx_shutdown(void)
8932{
8933 STASIS_MESSAGE_TYPE_CLEANUP(hint_change_message_type);
8934 STASIS_MESSAGE_TYPE_CLEANUP(hint_remove_message_type);
8935
8936 if (hints) {
8937 ao2_container_unregister("hints");
8938 ao2_ref(hints, -1);
8939 hints = NULL;
8940 }
8941 if (hintdevices) {
8942 ao2_container_unregister("hintdevices");
8943 ao2_ref(hintdevices, -1);
8944 hintdevices = NULL;
8945 }
8946 if (autohints) {
8947 ao2_container_unregister("autohints");
8948 ao2_ref(autohints, -1);
8949 autohints = NULL;
8950 }
8951 if (statecbs) {
8952 ao2_container_unregister("statecbs");
8953 ao2_ref(statecbs, -1);
8954 statecbs = NULL;
8955 }
8956 if (contexts_table) {
8958 }
8959}
8960
8961static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8962{
8963 struct ast_hint *hint = v_obj;
8964
8965 if (!hint) {
8966 return;
8967 }
8968 prnt(where, "%s@%s", ast_get_extension_name(hint->exten),
8970}
8971
8972static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8973{
8974 struct ast_hintdevice *hintdevice = v_obj;
8975
8976 if (!hintdevice) {
8977 return;
8978 }
8979 prnt(where, "%s => %s@%s", hintdevice->hintdevice,
8980 ast_get_extension_name(hintdevice->hint->exten),
8982}
8983
8984static void print_autohint_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8985{
8986 struct ast_autohint *autohint = v_obj;
8987
8988 if (!autohint) {
8989 return;
8990 }
8991 prnt(where, "%s", autohint->context);
8992}
8993
8994static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
8995{
8996 struct ast_state_cb *state_cb = v_obj;
8997
8998 if (!state_cb) {
8999 return;
9000 }
9001 prnt(where, "%d", state_cb->id);
9002}
9003
9005{
9008 if (hints) {
9010 }
9013 if (hintdevices) {
9015 }
9016 /* This is protected by the context_and_merge lock */
9019 if (autohints) {
9021 }
9023 if (statecbs) {
9025 }
9026
9028
9029 if (STASIS_MESSAGE_TYPE_INIT(hint_change_message_type) != 0) {
9030 return -1;
9031 }
9032 if (STASIS_MESSAGE_TYPE_INIT(hint_remove_message_type) != 0) {
9033 return -1;
9034 }
9035
9036 return (hints && hintdevices && autohints && statecbs) ? 0 : -1;
9037}
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:346
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:2387
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:3203
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:2414
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2461
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:1415
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
#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:1387
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:8334
#define ast_channel_lock(chan)
Definition: channel.h:2970
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1449
void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
adds a list of channel variables to a channel
Definition: channel.c:8141
struct ast_channel * ast_channel_yank(struct ast_channel *yankee)
Gain control of a channel in the system.
Definition: channel.c:10619
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3190
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1258
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:2995
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
ast_callid ast_channel_callid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
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:7355
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10571
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2500
#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:3006
@ AST_FLAG_BRIDGE_HANGUP_RUN
Definition: channel.h:1038
@ AST_FLAG_IN_AUTOLOOP
Definition: channel.h:1017
@ AST_FLAG_ORIGINATED
Definition: channel.h:1059
#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:2487
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:2072
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:1606
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#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:2428
@ 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
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
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:2028
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
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:2064
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
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:8268
int ast_option_maxcalls
Definition: options.c:79
double ast_option_maxload
Definition: options.c:77
struct ast_flags ast_options
Definition: options.c:61
long option_minmemfree
Definition: options.c:86
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:58
#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:240
#define ast_cond_destroy(cond)
Definition: lock.h:206
#define ast_cond_wait(cond, mutex)
Definition: lock.h:209
#define ast_cond_init(cond, attr)
Definition: lock.h:205
#define ast_rwlock_rdlock(a)
Definition: lock.h:239
#define ast_mutex_unlock(a)
Definition: lock.h:194
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:228
pthread_cond_t ast_cond_t
Definition: lock.h:182
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:237
#define ast_rwlock_unlock(a)
Definition: lock.h:238
#define ast_mutex_lock(a)
Definition: lock.h:193
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:524
#define ast_cond_signal(cond)
Definition: lock.h:207
size_t current
Definition: main/cli.c:113
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)
Asterisk file paths, configured in asterisk.conf.
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:8577
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:7670
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:8654
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:6145
void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
Definition: pbx.c:8071
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:6943
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:8220
static int manager_show_dialplan(struct mansession *s, const struct message *m)
Manager listing of dial plan.
Definition: pbx.c:5985
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
Remove an ignorepat.
Definition: pbx.c:6810
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:3241
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:3156
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:4195
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:7696
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:7941
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:3844
const char * ast_extension_state2str(int extension_state)
Return extension_state as string.
Definition: pbx.c:3141
static int handle_hint_change_message_type(struct stasis_message *msg, enum ast_state_cb_update_reason reason)
Definition: pbx.c:3552
static void hintdevice_destroy(void *obj)
Definition: pbx.c:560
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8534
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8478
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:8359
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:6245
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:8984
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:4931
static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str **hint_app)
Definition: pbx.c:3385
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:8005
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:8557
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:4993
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:7298
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8562
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8665
int ast_async_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8801
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:8994
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:7995
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:4750
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:8496
void wait_for_hangup(struct ast_channel *chan, const void *data)
Definition: pbx.c:8243
static char * parse_hint_presence(struct ast_str *hint_args)
Definition: pbx.c:3052
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:8309
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:7082
int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
Add an ignorepat.
Definition: pbx.c:6850
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:3096
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:8572
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:6679
static int publish_hint_remove(struct ast_hint *hint)
Publish a hint removed event
Definition: pbx.c:3935
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:3021
static char * complete_show_dialplan_context(const char *line, const char *word, int pos, int state)
Definition: pbx.c:5413
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:7272
static void decrease_call_count(void)
Definition: pbx.c:4681
int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition: pbx.c:6823
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:7607
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:3832
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:4770
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:5234
#define BITS_PER
static int hint_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:8911
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:4085
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8567
#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:7041
int ast_active_calls(void)
Retrieve the number of active calls.
Definition: pbx.c:4775
#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:6267
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:3265
static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
Definition: pbx.c:8775
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:6305
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:5171
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:6923
static char * handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx.c:6099
static char * parse_hint_device(struct ast_str *hint_args)
Definition: pbx.c:3071
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:4190
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:8891
static int statecbs_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:8919
int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
Definition: pbx.c:6863
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:6164
static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
Definition: pbx.c:6342
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:5467
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:8806
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:7931
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
Definition: pbx.c:4780
static void manager_dpsendack(struct mansession *s, const struct message *m)
Send ack once.
Definition: pbx.c:5821
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:4963
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:8542
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:6744
#define NEW_MATCHER_RECURSE
void pbx_set_overrideswitch(const char *newval)
Definition: pbx.c:4799
static void print_hintdevices_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: pbx.c:8972
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8506
static void unload_pbx(void)
Definition: pbx.c:8424
static int increase_call_count(const struct ast_channel *c)
Increase call count for channel.
Definition: pbx.c:4632
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:6441
const char * ast_get_extension_label(struct ast_exten *exten)
Definition: pbx.c:8529
static struct ast_context * find_context_locked(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4829
int pbx_set_extenpatternmatchnew(int newval)
Definition: pbx.c:4792
static void destroy_hint(void *obj)
Definition: pbx.c:3918
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:7593
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:5270
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:4874
static void print_hints_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
Definition: pbx.c:8961
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: pbx.c:8606
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:8796
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
Definition: pbx.c:8519
static int ast_remove_hint(struct ast_exten *e)
Remove hint from extension.
Definition: pbx.c:3956
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
Definition: pbx.c:4220
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition: pbx.c:6699
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:3128
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:4998
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:4205
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:4215
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:8236
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:7735
int ast_pbx_init(void)
Definition: pbx.c:9004
static void print_ext(struct ast_exten *e, char *buf, int buflen)
helper function to print an extension
Definition: pbx.c:5453
static char * handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Send ack once.
Definition: pbx.c:5765
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:4909
#define MAX_EXTENBUF_SIZE
Definition: pbx.c:1677
static void destroy_state_cb(void *doomed)
Definition: pbx.c:3729
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:4723
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:5643
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:3742
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:6960
static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
Definition: pbx.c:8847
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8483
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8886
#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:4200
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:3850
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:6894
int ast_context_ignorepats_count(const struct ast_context *con)
Definition: pbx.c:8737
#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:3871
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8699
static struct ast_custom_function testtime_function
Definition: pbx.c:8292
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:3479
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:8620
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:3838
static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, struct ast_pbx_args *args)
Definition: pbx.c:4321
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:8514
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:8582
int load_pbx(void)
Definition: pbx.c:8436
static struct ao2_container * alloc_device_state_info(void)
Definition: pbx.c:3091
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:3012
static int find_hint_by_cb_id(void *obj, void *arg, int flags)
Find Hint by callback id.
Definition: pbx.c:3857
static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
Definition: pbx.c:3215
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: pbx.c:3599
static void device_state_info_dt(void *obj)
Definition: pbx.c:3084
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:4210
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:4152
static struct ast_cli_entry pbx_cli[]
Definition: pbx.c:6130
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8297
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:8747
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:5482
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:4851
const struct ast_ignorepat * ast_walk_context_ignorepats(const struct ast_context *con, const struct ast_ignorepat *ip)
Definition: pbx.c:8704
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:3006
static void pbx_shutdown(void)
Definition: pbx.c:8931
const struct ast_ignorepat * ast_context_ignorepats_get(const struct ast_context *con, int idx)
Definition: pbx.c:8742
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:6071
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: pbx.c:8659
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:7281
static char * handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx.c:5698
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
Change hint for an extension.
Definition: pbx.c:4107
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:6984
static int hint_id_cmp(void *obj, void *arg, int flags)
Definition: pbx.c:3904
static void destroy_exten(struct ast_exten *e)
Definition: pbx.c:4689
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:6764
static struct ast_context * find_context(const char *context)
lookup for a context with a given name,
Definition: pbx.c:4815
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:3993
static unsigned int hashtab_hash_labels(const void *obj)
Definition: pbx.c:777
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8488
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:8611
int ast_context_switches_count(const struct ast_context *con)
Definition: pbx.c:8649
#define NEW_MATCHER_CHK_MATCH
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8881
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:4170
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:4968
int pbx_set_autofallthrough(int newval)
Definition: pbx.c:4785
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8694
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:4294
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:3185
static void * pbx_thread(void *data)
Definition: pbx.c:4703
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:5830
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:7017
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:8524
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:8501
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:8552
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8547
static void get_device_state_causing_channels(struct ao2_container *c)
Definition: pbx.c:3311
static void __ast_internal_context_destroy(struct ast_context *con)
Definition: pbx.c:8030
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:3191
#define INC_DST_OVERFLOW_CHECK
void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
Definition: pbx.c:4279
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:1143
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:119
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::@228 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
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
struct ast_hint::@379 devices
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:161
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
ast_state_cb_type change_cb
Definition: pbx.c:331
int id
Definition: pbx.c:325
struct ast_state_cb::@378 entry
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:5443
int total_items
Definition: pbx.c:5444
int total_context
Definition: pbx.c:5445
int context_existence
Definition: pbx.c:5448
int total_exten
Definition: pbx.c:5446
int total_prio
Definition: pbx.c:5447
int extension_existence
Definition: pbx.c:5449
structure to hold extensions
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:327
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:7569
int dial_res
Result of the dial operation when dialed is set.
Definition: pbx.c:7585
ast_cond_t cond
Condition for synchronous dialing.
Definition: pbx.c:7573
char app[AST_MAX_APP]
Application to execute.
Definition: pbx.c:7575
unsigned int in_separate_thread
Set if we've spawned a thread to do our work.
Definition: pbx.c:7589
struct ast_dial * dial
Dialing structure being used.
Definition: pbx.c:7571
unsigned int dialed
Set when dialing is completed.
Definition: pbx.c:7587
char exten[AST_MAX_EXTENSION]
Dialplan extension.
Definition: pbx.c:7581
char context[AST_MAX_CONTEXT]
Dialplan context.
Definition: pbx.c:7579
int priority
Dialplan priority.
Definition: pbx.c:7583
char * appdata
Application data to pass to application.
Definition: pbx.c:7577
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:6256
char * exten
Definition: pbx.c:6254
struct store_hint::@380 callbacks
int last_presence_state
Definition: pbx.c:6257
struct store_hint::@381 list
char * last_presence_subtype
Definition: pbx.c:6258
char * context
Definition: pbx.c:6253
char data[0]
Definition: pbx.c:6262
char * last_presence_message
Definition: pbx.c:6259
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:941
#define ast_assert(a)
Definition: utils.h:739
#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:588
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
Vector container support.
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition: vector.h:448
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
Definition: vector.h:438
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#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:680
Asterisk XML Documentation API.