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