Asterisk - The Open Source Telephony Project GIT-master-0034c23
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",