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