2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief Core PBX routines.
23 * \author Mark Spencer <markster@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include "asterisk/_private.h"
31 #include "asterisk/paths.h" /* use ast_config_AST_SYSTEM_NAME */
35 #if defined(HAVE_SYSINFO)
36 #include <sys/sysinfo.h>
39 #include <sys/loadavg.h>
42 #include "asterisk/lock.h"
43 #include "asterisk/cli.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/file.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/cdr.h"
49 #include "asterisk/config.h"
50 #include "asterisk/term.h"
51 #include "asterisk/manager.h"
52 #include "asterisk/ast_expr.h"
53 #include "asterisk/linkedlists.h"
54 #define SAY_STUBS /* generate declarations and stubs for say methods */
55 #include "asterisk/say.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/causes.h"
58 #include "asterisk/musiconhold.h"
59 #include "asterisk/app.h"
60 #include "asterisk/devicestate.h"
61 #include "asterisk/stringfields.h"
62 #include "asterisk/event.h"
63 #include "asterisk/hashtab.h"
64 #include "asterisk/module.h"
65 #include "asterisk/indications.h"
68 * \note I M P O R T A N T :
70 * The speed of extension handling will likely be among the most important
71 * aspects of this PBX. The switching scheme as it exists right now isn't
72 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
73 * of priorities, but a constant search time here would be great ;-)
75 * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
76 * here, and shows a fairly flat (constant) search time, even for over
77 * 1000 patterns. Might Still needs some work-- there are some fine points of the matching
78 * spec about tie-breaking based on the characters in character sets, but this
79 * should be do-able via the weight system currently being used.
81 * Also, using a hash table for context/priority name lookup can help prevent
82 * the find_extension routines from absorbing exponential cpu cycles. I've tested
83 * find_extension with red-black trees, which have O(log2(n)) speed. Right now,
84 * I'm using hash tables, which do searches (ideally) in O(1) time.
89 #define EXT_DATA_SIZE 256
91 #define EXT_DATA_SIZE 8192
94 #define SWITCH_DATA_LENGTH 256
96 #define VAR_BUF_SIZE 4096
99 #define VAR_SOFTTRAN 2
100 #define VAR_HARDTRAN 3
102 #define BACKGROUND_SKIP (1 << 0)
103 #define BACKGROUND_NOANSWER (1 << 1)
104 #define BACKGROUND_MATCHEXTEN (1 << 2)
105 #define BACKGROUND_PLAYBACK (1 << 3)
107 AST_APP_OPTIONS(background_opts, {
108 AST_APP_OPTION('s', BACKGROUND_SKIP),
109 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
110 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
111 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
114 #define WAITEXTEN_MOH (1 << 0)
115 #define WAITEXTEN_DIALTONE (1 << 1)
117 AST_APP_OPTIONS(waitexten_opts, {
118 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
119 AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
126 \brief ast_exten: An extension
127 The dialplan is saved as a linked list with each context
128 having it's own linked list of extensions - one item per
132 char *exten; /*!< Extension name */
133 int matchcid; /*!< Match caller id ? */
134 const char *cidmatch; /*!< Caller id to match for this extension */
135 int priority; /*!< Priority */
136 const char *label; /*!< Label */
137 struct ast_context *parent; /*!< The context this extension belongs to */
138 const char *app; /*!< Application to execute */
139 struct ast_app *cached_app; /*!< Cached location of application */
140 void *data; /*!< Data to use (arguments) */
141 void (*datad)(void *); /*!< Data destructor */
142 struct ast_exten *peer; /*!< Next higher priority with our extension */
143 struct ast_hashtab *peer_tree; /*!< Priorities list in tree form -- only on the head of the peer list */
144 struct ast_hashtab *peer_label_tree; /*!< labeled priorities in the peer list -- only on the head of the peer list */
145 const char *registrar; /*!< Registrar */
146 struct ast_exten *next; /*!< Extension with a greater ID */
150 /*! \brief ast_include: include= support in extensions.conf */
153 const char *rname; /*!< Context to include */
154 const char *registrar; /*!< Registrar */
155 int hastime; /*!< If time construct exists */
156 struct ast_timing timing; /*!< time construct */
157 struct ast_include *next; /*!< Link them together */
161 /*! \brief ast_sw: Switch statement in extensions.conf */
164 const char *registrar; /*!< Registrar */
165 char *data; /*!< Data load */
167 AST_LIST_ENTRY(ast_sw) list;
172 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
173 struct ast_ignorepat {
174 const char *registrar;
175 struct ast_ignorepat *next;
176 const char pattern[0];
179 /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
182 int is_pattern; /* the pattern started with '_' */
183 int deleted; /* if this is set, then... don't return it */
184 char *x; /* the pattern itself-- matches a single char */
185 int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
186 struct match_char *alt_char;
187 struct match_char *next_char;
188 struct ast_exten *exten; /* attached to last char of a pattern for exten */
191 struct scoreboard /* make sure all fields are 0 before calling new_find_extension */
193 int total_specificity;
195 char last_char; /* set to ! or . if they are the end of the pattern */
196 int canmatch; /* if the string to match was just too short */
197 struct match_char *node;
198 struct ast_exten *canmatch_exten;
199 struct ast_exten *exten;
202 /*! \brief ast_context: An extension context */
204 ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
205 struct ast_exten *root; /*!< The root of the list of extensions */
206 struct ast_hashtab *root_tree; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */
207 struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */
208 struct ast_context *next; /*!< Link them together */
209 struct ast_include *includes; /*!< Include other contexts */
210 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
211 const char *registrar; /*!< Registrar */
212 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
213 ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
214 char name[0]; /*!< Name of the context */
218 /*! \brief ast_app: A registered application */
220 int (*execute)(struct ast_channel *chan, void *data);
221 const char *synopsis; /*!< Synopsis text for 'show applications' */
222 const char *description; /*!< Description (help text) for 'show application <name>' */
223 AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
224 struct ast_module *module; /*!< Module this app belongs to */
225 char name[0]; /*!< Name of the application */
228 /*! \brief ast_state_cb: An extension state notify register item */
229 struct ast_state_cb {
232 ast_state_cb_type callback;
233 struct ast_state_cb *next;
236 /*! \brief Structure for dial plan hints
238 \note Hints are pointers from an extension in the dialplan to one or
239 more devices (tech/name)
240 - See \ref AstExtState
243 struct ast_exten *exten; /*!< Extension */
244 int laststate; /*!< Last known state */
245 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
246 AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
249 static const struct cfextension_states {
251 const char * const text;
252 } extension_states[] = {
253 { AST_EXTENSION_NOT_INUSE, "Idle" },
254 { AST_EXTENSION_INUSE, "InUse" },
255 { AST_EXTENSION_BUSY, "Busy" },
256 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
257 { AST_EXTENSION_RINGING, "Ringing" },
258 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
259 { AST_EXTENSION_ONHOLD, "Hold" },
260 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
264 AST_LIST_ENTRY(statechange) entry;
269 * \brief Data used by the device state thread
272 /*! Set to 1 to stop the thread */
274 /*! The device state monitoring thread */
276 /*! Lock for the state change queue */
278 /*! Condition for the state change queue */
280 /*! Queue of state changes */
281 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
283 .thread = AST_PTHREADT_NULL,
286 struct pbx_exception {
287 AST_DECLARE_STRING_FIELDS(
288 AST_STRING_FIELD(context); /*!< Context associated with this exception */
289 AST_STRING_FIELD(exten); /*!< Exten associated with this exception */
290 AST_STRING_FIELD(reason); /*!< The exception reason */
293 int priority; /*!< Priority associated with this exception */
296 static int pbx_builtin_answer(struct ast_channel *, void *);
297 static int pbx_builtin_goto(struct ast_channel *, void *);
298 static int pbx_builtin_hangup(struct ast_channel *, void *);
299 static int pbx_builtin_background(struct ast_channel *, void *);
300 static int pbx_builtin_wait(struct ast_channel *, void *);
301 static int pbx_builtin_waitexten(struct ast_channel *, void *);
302 static int pbx_builtin_keepalive(struct ast_channel *, void *);
303 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
304 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
305 static int pbx_builtin_ringing(struct ast_channel *, void *);
306 static int pbx_builtin_progress(struct ast_channel *, void *);
307 static int pbx_builtin_congestion(struct ast_channel *, void *);
308 static int pbx_builtin_busy(struct ast_channel *, void *);
309 static int pbx_builtin_noop(struct ast_channel *, void *);
310 static int pbx_builtin_gotoif(struct ast_channel *, void *);
311 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
312 static int pbx_builtin_execiftime(struct ast_channel *, void *);
313 static int pbx_builtin_saynumber(struct ast_channel *, void *);
314 static int pbx_builtin_saydigits(struct ast_channel *, void *);
315 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
316 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
317 static int matchcid(const char *cidpattern, const char *callerid);
318 int pbx_builtin_setvar(struct ast_channel *, void *);
319 void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
320 static int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
321 static int pbx_builtin_importvar(struct ast_channel *, void *);
322 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
323 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid);
324 static struct match_char *already_in_tree(struct match_char *current, char *pat);
325 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly);
326 static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity);
327 static void create_match_char_tree(struct ast_context *con);
328 static struct ast_exten *get_canmatch_exten(struct match_char *node);
329 static void destroy_pattern_tree(struct match_char *pattern_tree);
330 static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
331 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
332 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
333 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
334 static unsigned int hashtab_hash_contexts(const void *obj);
335 static unsigned int hashtab_hash_extens(const void *obj);
336 static unsigned int hashtab_hash_priority(const void *obj);
337 static unsigned int hashtab_hash_labels(const void *obj);
339 /* labels, contexts are case sensitive priority numbers are ints */
340 static int hashtab_compare_contexts(const void *ah_a, const void *ah_b)
342 const struct ast_context *ac = ah_a;
343 const struct ast_context *bc = ah_b;
344 /* assume context names are registered in a string table! */
345 return strcmp(ac->name, bc->name);
348 static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
350 const struct ast_exten *ac = ah_a;
351 const struct ast_exten *bc = ah_b;
352 int x = strcmp(ac->exten, bc->exten);
353 if (x) /* if exten names are diff, then return */
355 /* but if they are the same, do the cidmatch values match? */
356 if (ac->matchcid && bc->matchcid) {
357 return strcmp(ac->cidmatch,bc->cidmatch);
358 } else if (!ac->matchcid && !bc->matchcid) {
359 return 0; /* if there's no matchcid on either side, then this is a match */
361 return 1; /* if there's matchcid on one but not the other, they are different */
365 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
367 const struct ast_exten *ac = ah_a;
368 const struct ast_exten *bc = ah_b;
369 return ac->priority != bc->priority;
372 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
374 const struct ast_exten *ac = ah_a;
375 const struct ast_exten *bc = ah_b;
376 return strcmp(ac->label, bc->label);
379 static unsigned int hashtab_hash_contexts(const void *obj)
381 const struct ast_context *ac = obj;
382 return ast_hashtab_hash_string(ac->name);
385 static unsigned int hashtab_hash_extens(const void *obj)
387 const struct ast_exten *ac = obj;
388 unsigned int x = ast_hashtab_hash_string(ac->exten);
391 y = ast_hashtab_hash_string(ac->cidmatch);
395 static unsigned int hashtab_hash_priority(const void *obj)
397 const struct ast_exten *ac = obj;
398 return ast_hashtab_hash_int(ac->priority);
401 static unsigned int hashtab_hash_labels(const void *obj)
403 const struct ast_exten *ac = obj;
404 return ast_hashtab_hash_string(ac->label);
408 AST_RWLOCK_DEFINE_STATIC(globalslock);
409 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
411 static int autofallthrough = 1;
412 static int extenpatternmatchnew = 0;
414 /*! \brief Subscription for device state change events */
415 static struct ast_event_sub *device_state_sub;
417 AST_MUTEX_DEFINE_STATIC(maxcalllock);
418 static int countcalls;
420 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
422 /*! \brief Declaration of builtin applications */
423 static struct pbx_builtin {
424 char name[AST_MAX_APP];
425 int (*execute)(struct ast_channel *chan, void *data);
430 /* These applications are built into the PBX core and do not
431 need separate modules */
433 { "Answer", pbx_builtin_answer,
434 "Answer a channel if ringing",
435 " Answer([delay]): If the call has not been answered, this application will\n"
436 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
437 "Asterisk will wait this number of milliseconds before returning to\n"
438 "the dialplan after answering the call.\n"
441 { "BackGround", pbx_builtin_background,
442 "Play an audio file while waiting for digits of an extension to go to.",
443 " Background(filename1[&filename2...][,options[,langoverride][,context]]):\n"
444 "This application will play the given list of files while waiting for an\n"
445 "extension to be dialed by the calling channel. To continue waiting for digits\n"
446 "after this application has finished playing files, the WaitExten application\n"
447 "should be used. The 'langoverride' option explicitly specifies which language\n"
448 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
449 "this is the dialplan context that this application will use when exiting to a\n"
451 " If one of the requested sound files does not exist, call processing will be\n"
454 " s - Causes the playback of the message to be skipped\n"
455 " if the channel is not in the 'up' state (i.e. it\n"
456 " hasn't been answered yet). If this happens, the\n"
457 " application will return immediately.\n"
458 " n - Don't answer the channel before playing the files.\n"
459 " m - Only break if a digit hit matches a one digit\n"
460 " extension in the destination context.\n"
461 "This application sets the following channel variable upon completion:\n"
462 " BACKGROUNDSTATUS The status of the background attempt as a text string, one of\n"
463 " SUCCESS | FAILED\n"
466 { "Busy", pbx_builtin_busy,
467 "Indicate the Busy condition",
468 " Busy([timeout]): This application will indicate the busy condition to\n"
469 "the calling channel. If the optional timeout is specified, the calling channel\n"
470 "will be hung up after the specified number of seconds. Otherwise, this\n"
471 "application will wait until the calling channel hangs up.\n"
474 { "Congestion", pbx_builtin_congestion,
475 "Indicate the Congestion condition",
476 " Congestion([timeout]): This application will indicate the congestion\n"
477 "condition to the calling channel. If the optional timeout is specified, the\n"
478 "calling channel will be hung up after the specified number of seconds.\n"
479 "Otherwise, this application will wait until the calling channel hangs up.\n"
482 { "ExecIfTime", pbx_builtin_execiftime,
483 "Conditional application execution based on the current time",
484 " ExecIfTime(<times>,<weekdays>,<mdays>,<months>?appname[(appargs)]):\n"
485 "This application will execute the specified dialplan application, with optional\n"
486 "arguments, if the current time matches the given time specification.\n"
489 { "Goto", pbx_builtin_goto,
490 "Jump to a particular priority, extension, or context",
491 " Goto([[context,]extension,]priority): This application will set the current\n"
492 "context, extension, and priority in the channel structure. After it completes, the\n"
493 "pbx engine will continue dialplan execution at the specified location.\n"
494 "If no specific extension, or extension and context, are specified, then this\n"
495 "application will just set the specified priority of the current extension.\n"
496 " At least a priority is required as an argument, or the goto will return a -1,\n"
497 "and the channel and call will be terminated.\n"
498 " If the location that is put into the channel information is bogus, and asterisk cannot\n"
499 "find that location in the dialplan,\n"
500 "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
501 "extension in the current context. If that does not exist, it will try to execute the\n"
502 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
503 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
504 "What this means is that, for example, you specify a context that does not exist, then\n"
505 "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
508 { "GotoIf", pbx_builtin_gotoif,
510 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
511 "context, extension, and priority in the channel structure based on the evaluation of\n"
512 "the given condition. After this application completes, the\n"
513 "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
514 "The channel will continue at\n"
515 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
516 "false. The labels are specified with the same syntax as used within the Goto\n"
517 "application. If the label chosen by the condition is omitted, no jump is\n"
518 "performed, and the execution passes to the next instruction.\n"
519 "If the target location is bogus, and does not exist, the execution engine will try \n"
520 "to find and execute the code in the 'i' (invalid)\n"
521 "extension in the current context. If that does not exist, it will try to execute the\n"
522 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
523 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
524 "Remember that this command can set the current context, and if the context specified\n"
525 "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
526 "the channel and call will both be terminated!\n"
529 { "GotoIfTime", pbx_builtin_gotoiftime,
530 "Conditional Goto based on the current time",
531 " GotoIfTime(<times>,<weekdays>,<mdays>,<months>?[[context,]exten,]priority):\n"
532 "This application will set the context, extension, and priority in the channel structure\n"
533 "if the current time matches the given time specification. Otherwise, nothing is done.\n"
534 "Further information on the time specification can be found in examples\n"
535 "illustrating how to do time-based context includes in the dialplan.\n"
536 "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
539 { "ImportVar", pbx_builtin_importvar,
540 "Import a variable from a channel into a new variable",
541 " ImportVar(newvar=channelname,variable): This application imports a variable\n"
542 "from the specified channel (as opposed to the current one) and stores it as\n"
543 "a variable in the current channel (the channel that is calling this\n"
544 "application). Variables created by this application have the same inheritance\n"
545 "properties as those created with the Set application. See the documentation for\n"
546 "Set for more information.\n"
549 { "Hangup", pbx_builtin_hangup,
550 "Hang up the calling channel",
551 " Hangup([causecode]): This application will hang up the calling channel.\n"
552 "If a causecode is given the channel's hangup cause will be set to the given\n"
556 { "NoOp", pbx_builtin_noop,
557 "Do Nothing (No Operation)",
558 " NoOp(): This application does nothing. However, it is useful for debugging\n"
559 "purposes. Any text that is provided as arguments to this application can be\n"
560 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
561 "variables or functions without having any effect. Alternatively, see the\n"
562 "Verbose() application for finer grain control of output at custom verbose levels.\n"
565 { "Progress", pbx_builtin_progress,
567 " Progress(): This application will request that in-band progress information\n"
568 "be provided to the calling channel.\n"
571 { "RaiseException", pbx_builtin_raise_exception,
572 "Handle an exceptional condition",
573 " RaiseException(<reason>): This application will jump to the \"e\" extension\n"
574 "in the current context, setting the dialplan function EXCEPTION(). If the \"e\"\n"
575 "extension does not exist, the call will hangup.\n"
578 { "ResetCDR", pbx_builtin_resetcdr,
579 "Resets the Call Data Record",
580 " ResetCDR([options]): This application causes the Call Data Record to be\n"
583 " w -- Store the current CDR record before resetting it.\n"
584 " a -- Store any stacked records.\n"
585 " v -- Save CDR variables.\n"
588 { "Ringing", pbx_builtin_ringing,
589 "Indicate ringing tone",
590 " Ringing(): This application will request that the channel indicate a ringing\n"
591 "tone to the user.\n"
594 { "SayAlpha", pbx_builtin_saycharacters,
596 " SayAlpha(string): This application will play the sounds that correspond to\n"
597 "the letters of the given string.\n"
600 { "SayDigits", pbx_builtin_saydigits,
602 " SayDigits(digits): This application will play the sounds that correspond\n"
603 "to the digits of the given number. This will use the language that is currently\n"
604 "set for the channel. See the LANGUAGE function for more information on setting\n"
605 "the language for the channel.\n"
608 { "SayNumber", pbx_builtin_saynumber,
610 " SayNumber(digits[,gender]): This application will play the sounds that\n"
611 "correspond to the given number. Optionally, a gender may be specified.\n"
612 "This will use the language that is currently set for the channel. See the\n"
613 "LANGUAGE function for more information on setting the language for the channel.\n"
616 { "SayPhonetic", pbx_builtin_sayphonetic,
618 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
619 "alphabet that correspond to the letters in the given string.\n"
622 { "Set", pbx_builtin_setvar,
623 "Set channel variable or function value",
625 "This function can be used to set the value of channel variables or dialplan\n"
626 "functions. When setting variables, if the variable name is prefixed with _,\n"
627 "the variable will be inherited into channels created from the current\n"
628 "channel. If the variable name is prefixed with __, the variable will be\n"
629 "inherited into channels created from the current channel and all children\n"
633 { "MSet", pbx_builtin_setvar_multiple,
634 "Set channel variable(s) or function value(s)",
635 " MSet(name1=value1,name2=value2,...)\n"
636 "This function can be used to set the value of channel variables or dialplan\n"
637 "functions. When setting variables, if the variable name is prefixed with _,\n"
638 "the variable will be inherited into channels created from the current\n"
639 "channel. If the variable name is prefixed with __, the variable will be\n"
640 "inherited into channels created from the current channel and all children\n"
642 "MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus\n"
643 "prone to doing things that you may not expect. Avoid its use if possible.\n"
646 { "SetAMAFlags", pbx_builtin_setamaflags,
648 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
649 " billing purposes.\n"
652 { "Wait", pbx_builtin_wait,
653 "Waits for some time",
654 " Wait(seconds): This application waits for a specified number of seconds.\n"
655 "Then, dialplan execution will continue at the next priority.\n"
656 " Note that the seconds can be passed with fractions of a second. For example,\n"
657 "'1.5' will ask the application to wait for 1.5 seconds.\n"
660 { "WaitExten", pbx_builtin_waitexten,
661 "Waits for an extension to be entered",
662 " WaitExten([seconds][,options]): This application waits for the user to enter\n"
663 "a new extension for a specified number of seconds.\n"
664 " Note that the seconds can be passed with fractions of a second. For example,\n"
665 "'1.5' will ask the application to wait for 1.5 seconds.\n"
667 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
668 " Optionally, specify the class for music on hold within parenthesis.\n"
671 { "KeepAlive", pbx_builtin_keepalive,
672 "returns AST_PBX_KEEPALIVE value",
673 " KeepAlive(): This application is chiefly meant for internal use with Gosubs.\n"
674 "Please do not run it alone from the dialplan!\n"
679 static struct ast_context *contexts;
680 static struct ast_hashtab *contexts_tree = NULL;
682 AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
684 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
686 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
688 static int stateid = 1;
690 When holding this list's lock, do _not_ do anything that will cause conlock
691 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
692 function will take the locks in conlock/hints order, so any other
693 paths that require both locks must also take them in that order.
695 static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
696 struct ast_state_cb *statecbs;
699 \note This function is special. It saves the stack so that no matter
700 how many times it is called, it returns to the same place */
701 int pbx_exec(struct ast_channel *c, /*!< Channel */
702 struct ast_app *app, /*!< Application */
703 void *data) /*!< Data for execution */
706 struct ast_module_user *u = NULL;
707 const char *saved_c_appl;
708 const char *saved_c_data;
710 if (c->cdr && !ast_check_hangup(c))
711 ast_cdr_setapp(c->cdr, app->name, data);
713 /* save channel values */
714 saved_c_appl= c->appl;
715 saved_c_data= c->data;
720 u = __ast_module_user_add(app->module, c);
721 res = app->execute(c, data);
722 if (app->module && u)
723 __ast_module_user_remove(app->module, u);
724 /* restore channel values */
725 c->appl = saved_c_appl;
726 c->data = saved_c_data;
731 /*! Go no deeper than this through includes (not counting loops) */
732 #define AST_PBX_MAX_STACK 128
734 /*! \brief Find application handle in linked list
736 struct ast_app *pbx_findapp(const char *app)
740 AST_RWLIST_RDLOCK(&apps);
741 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
742 if (!strcasecmp(tmp->name, app))
745 AST_RWLIST_UNLOCK(&apps);
750 static struct ast_switch *pbx_findswitch(const char *sw)
752 struct ast_switch *asw;
754 AST_RWLIST_RDLOCK(&switches);
755 AST_RWLIST_TRAVERSE(&switches, asw, list) {
756 if (!strcasecmp(asw->name, sw))
759 AST_RWLIST_UNLOCK(&switches);
764 static inline int include_valid(struct ast_include *i)
769 return ast_check_timing(&(i->timing));
772 static void pbx_destroy(struct ast_pbx *p)
777 /* form a tree that fully describes all the patterns in a context's extensions
778 * in this tree, a "node" consists of a series of match_char structs linked in a chain
779 * via the alt_char pointers. More than one pattern can share the same parts of the
780 * tree as other extensions with the same pattern to that point. The algorithm to
781 * find which pattern best matches a string, would follow **all** matching paths. As
782 * complete matches are found, a "max" match record would be updated if the match first involves
783 * a longer string, then, on a tie, a smaller total of specificity. This can be accomplished
784 * by recursive calls affecting a shared scoreboard.
785 * As and example, consider these 4 extensions:
791 * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
792 * most numbers. For all numbers beginning with 307754, (b) should always win.
794 * These pattern should form a tree that looks like this:
795 * { "N" } --next--> { "X" } --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
799 * | { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
801 * { "3" } --next--> { "0" } --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
805 * { "f" } --next--> { "a" } --next--> { "x" exten_match: (c) }
807 * In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
808 * fewer CPU cycles than a call to index("23456789",*z), where *z is the char to match...
810 * traversal is pretty simple: one routine merely traverses the alt list, and for each match in the pattern, it calls itself
811 * on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
812 * We pass a pointer to a scoreboard down through, also.
813 * When an exten_match pointer is set, or a '.' or a '!' is encountered, we update the scoreboard only if the length is greater, or in case
814 * of equal length, if the specificity is lower, and return. Hope the limit on stack depth won't be a problem... this routine should
815 * be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
817 * In the above example, with the number "3077549999" as the pattern, the traversor should match extensions a, b and d. All are
818 * of length 10; but they have total specificities of 96, 46, and 98, respectively. (b) wins with its lower specificity number!
820 * Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown. But, it should
821 * be pretty close to optimal for this sort of overall algorithm.
825 /* you only really update the scoreboard, if the new score is BETTER than the
826 * one stored there. ignore it otherwise.
830 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)
832 /* doing a matchcid() check here would be easy and cheap, but...
833 unfortunately, it only works if an extension can have only one
834 cid to match. That's not real life. CID patterns need to exist
835 in the tree for this sort of thing to work properly. */
837 /* if this extension is marked as deleted, then skip this -- if it never shows
838 on the scoreboard, it will never be found */
841 if (length > board->total_length) {
842 board->total_specificity = spec;
843 board->total_length = length;
844 board->exten = exten;
845 board->last_char = last;
847 } else if (length == board->total_length && spec < board->total_specificity) {
848 board->total_specificity = spec;
849 board->total_length = length;
850 board->exten = exten;
851 board->last_char = last;
856 void log_match_char_tree(struct match_char *node, char *prefix)
858 char my_prefix[1024];
862 if (node && node->exten && node->exten)
863 sprintf(extenstr,"(%p)",node->exten);
865 if (strlen(node->x) > 1 )
866 ast_log(LOG_DEBUG,"%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
868 ast_log(LOG_DEBUG,"%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
869 strcpy(my_prefix,prefix);
870 strcat(my_prefix,"+ ");
872 log_match_char_tree(node->next_char, my_prefix);
874 log_match_char_tree(node->alt_char, prefix);
877 static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
879 char my_prefix[1024];
883 if (node && node->exten && node->exten)
884 sprintf(extenstr,"(%p)",node->exten);
886 if (strlen(node->x) > 1)
887 ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
889 ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
890 strcpy(my_prefix,prefix);
891 strcat(my_prefix,"+ ");
893 cli_match_char_tree(node->next_char, my_prefix, fd);
895 cli_match_char_tree(node->alt_char, prefix, fd);
898 static struct ast_exten *get_canmatch_exten(struct match_char *node)
900 /* find the exten at the end of the rope */
901 struct match_char *node2 = node;
902 for (node2 = node; node2; node2 = node2->next_char)
908 static struct ast_exten *trie_find_next_match(struct match_char *node)
910 struct match_char *m3;
911 struct match_char *m4;
912 struct ast_exten *e3;
914 if (node && node->x[0] == '.' && !node->x[1]) /* dot and ! will ALWAYS be next match in a matchmore */
917 if (node && node->x[0] == '!' && !node->x[1])
920 if (!node || !node->next_char)
923 m3 = node->next_char;
927 for(m4=m3->alt_char; m4; m4 = m4->alt_char) {
931 for(m4=m3; m4; m4 = m4->alt_char) {
932 e3 = trie_find_next_match(m3);
939 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid)
941 struct match_char *p; /* note minimal stack storage requirements */
944 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s\n", str, tree->x);
946 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL\n", str);
948 for (p=tree; p; p=p->alt_char) {
949 if (p->x[0] == 'N' && p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
950 if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
951 update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);
953 if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
955 new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
957 new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
958 } else if (p->next_char && !*(str+1)) {
960 score->canmatch_exten = get_canmatch_exten(p);
964 } else if (p->x[0] == 'Z' && p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
965 if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
966 update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted,p);
968 if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
970 new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
972 new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
973 } else if (p->next_char && !*(str+1)) {
975 score->canmatch_exten = get_canmatch_exten(p);
979 } else if (p->x[0] == 'X' && p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
980 if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
981 update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted,p);
983 if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
985 new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
987 new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
988 } else if (p->next_char && !*(str+1)) {
990 score->canmatch_exten = get_canmatch_exten(p);
994 } else if (p->x[0] == '.' && p->x[1] == 0) {
995 /* how many chars will the . match against? */
997 const char *str2 = str;
1001 if (p->exten && !(*(str+1)))
1002 update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
1003 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1004 new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid);
1007 } else if (p->x[0] == '!' && p->x[1] == 0) {
1008 /* how many chars will the . match against? */
1010 const char *str2 = str;
1014 if (p->exten && !(*(str+1)))
1015 update_scoreboard(score, length+1, spec+(p->specificity*i), p->exten, '!', callerid, p->deleted, p);
1016 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1017 new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid);
1020 } else if (p->x[0] == '/' && p->x[1] == 0) {
1021 /* the pattern in the tree includes the cid match! */
1022 if (p->next_char && callerid && *callerid) {
1023 new_find_extension(callerid, score, p->next_char, length+1, spec, callerid);
1025 } else if (index(p->x, *str)) {
1026 if (p->exten && !(*(str+1))) /* if a shorter pattern matches along the way, might as well report it */
1027 update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);
1030 if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
1032 new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
1034 new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
1036 } else if (p->next_char && !*(str+1)) {
1037 score->canmatch = 1;
1038 score->canmatch_exten = get_canmatch_exten(p);
1046 /* the algorithm for forming the extension pattern tree is also a bit simple; you
1047 * traverse all the extensions in a context, and for each char of the extension,
1048 * you see if it exists in the tree; if it doesn't, you add it at the appropriate
1049 * spot. What more can I say? At the end of the list, you cap it off by adding the
1050 * address of the extension involved. Duplicate patterns will be complained about.
1052 * Ideally, this would be done for each context after it is created and fully
1053 * filled. It could be done as a finishing step after extensions.conf or .ael is
1054 * loaded, or it could be done when the first search is encountered. It should only
1055 * have to be done once, until the next unload or reload.
1057 * I guess forming this pattern tree would be analogous to compiling a regex.
1060 static struct match_char *already_in_tree(struct match_char *current, char *pat)
1062 struct match_char *t;
1065 for (t=current; t; t=t->alt_char) {
1066 if (strcmp(pat,t->x) == 0) /* uh, we may want to sort exploded [] contents to make matching easy */
1072 static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity)
1074 struct match_char *m = ast_calloc(1,sizeof(struct match_char));
1075 m->x = ast_strdup(pattern);
1076 m->is_pattern = is_pattern;
1077 if (specificity == 1 && is_pattern && pattern[0] == 'N')
1078 m->specificity = 98;
1079 else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
1080 m->specificity = 99;
1081 else if (specificity == 1 && is_pattern && pattern[0] == 'X')
1082 m->specificity = 100;
1083 else if (specificity == 1 && is_pattern && pattern[0] == '.')
1084 m->specificity = 200;
1085 else if (specificity == 1 && is_pattern && pattern[0] == '!')
1086 m->specificity = 200;
1088 m->specificity = specificity;
1090 if (!con->pattern_tree) {
1091 con->pattern_tree = m;
1093 if (already) { /* switch to the new regime (traversing vs appending)*/
1094 m->alt_char = current->alt_char;
1095 current->alt_char = m;
1097 if (current->next_char) {
1098 m->alt_char = current->next_char->alt_char;
1099 current->next_char = m;
1101 current->next_char = m;
1108 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
1110 struct match_char *m1=0,*m2=0;
1116 char *s1 = extenbuf;
1117 int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
1120 strncpy(extenbuf,e1->exten,sizeof(extenbuf));
1121 if (e1->matchcid && l1 <= sizeof(extenbuf)) {
1122 strcat(extenbuf,"/");
1123 strcat(extenbuf,e1->cidmatch);
1124 } else if (l1 > sizeof(extenbuf)) {
1125 ast_log(LOG_ERROR,"The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
1129 ast_log(LOG_DEBUG,"Adding exten %s%c%s to tree\n", s1, e1->matchcid? '/':' ', e1->matchcid? e1->cidmatch : "");
1131 m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
1139 if (pattern && *s1 == '[' && *(s1-1) != '\\') {
1142 s1++; /* get past the '[' */
1143 while (*s1 != ']' && *(s1-1) != '\\' ) {
1145 if (*(s1+1) == ']') {
1148 } else if (*(s1+1) == '\\') {
1151 } else if (*(s1+1) == '-') {
1154 } else if (*(s1+1) == '[') {
1158 } else if (*s1 == '-') { /* remember to add some error checking to all this! */
1161 for (s3++; s3 <= s4; s3++) {
1169 *s2 = 0; /* null terminate the exploded range */
1170 specif = strlen(buf);
1178 if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
1180 else if (*s1 == 'x')
1182 else if (*s1 == 'z')
1191 if (already && (m2=already_in_tree(m1,buf)) && m2->next_char) {
1192 if (!(*(s1+1))) { /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
1193 a shorter pattern might win if the longer one doesn't match */
1197 m1 = m2->next_char; /* m1 points to the node to compare against */
1206 m1 = add_pattern_node(con, m1, buf, pattern, already,specif); /* m1 is the node just added */
1216 s1++; /* advance to next char */
1221 static void create_match_char_tree(struct ast_context *con)
1223 struct ast_hashtab_iter *t1;
1224 struct ast_exten *e1;
1226 int biggest_bucket, resizes, numobjs, numbucks;
1228 ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
1229 ast_hashtab_get_stats(con->root_tree, &biggest_bucket, &resizes, &numobjs, &numbucks);
1230 ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
1231 numobjs, numbucks, biggest_bucket, resizes);
1233 t1 = ast_hashtab_start_traversal(con->root_tree);
1234 while( (e1 = ast_hashtab_next(t1)) ) {
1236 add_exten_to_pattern_tree(con, e1, 0);
1238 ast_log(LOG_ERROR,"Attempt to create extension with no extension name.\n");
1240 ast_hashtab_end_traversal(t1);
1243 static 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! */
1245 /* destroy all the alternates */
1246 if (pattern_tree->alt_char) {
1247 destroy_pattern_tree(pattern_tree->alt_char);
1248 pattern_tree->alt_char = 0;
1250 /* destroy all the nexts */
1251 if (pattern_tree->next_char) {
1252 destroy_pattern_tree(pattern_tree->next_char);
1253 pattern_tree->next_char = 0;
1255 pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
1256 if (pattern_tree->x)
1257 free(pattern_tree->x);
1262 * Special characters used in patterns:
1263 * '_' underscore is the leading character of a pattern.
1264 * In other position it is treated as a regular char.
1265 * ' ' '-' space and '-' are separator and ignored.
1266 * . one or more of any character. Only allowed at the end of
1268 * ! zero or more of anything. Also impacts the result of CANMATCH
1269 * and MATCHMORE. Only allowed at the end of a pattern.
1270 * In the core routine, ! causes a match with a return code of 2.
1271 * In turn, depending on the search mode: (XXX check if it is implemented)
1272 * - E_MATCH retuns 1 (does match)
1273 * - E_MATCHMORE returns 0 (no match)
1274 * - E_CANMATCH returns 1 (does match)
1276 * / should not appear as it is considered the separator of the CID info.
1277 * XXX at the moment we may stop on this char.
1279 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
1280 * [ denotes the start of a set of character. Everything inside
1281 * is considered literally. We can have ranges a-d and individual
1282 * characters. A '[' and '-' can be considered literally if they
1283 * are just before ']'.
1284 * XXX currently there is no way to specify ']' in a range, nor \ is
1285 * considered specially.
1287 * When we compare a pattern with a specific extension, all characters in the extension
1288 * itself are considered literally with the only exception of '-' which is considered
1289 * as a separator and thus ignored.
1290 * XXX do we want to consider space as a separator as well ?
1291 * XXX do we want to consider the separators in non-patterns as well ?
1295 * \brief helper functions to sort extensions and patterns in the desired way,
1296 * so that more specific patterns appear first.
1298 * ext_cmp1 compares individual characters (or sets of), returning
1299 * an int where bits 0-7 are the ASCII code of the first char in the set,
1300 * while bit 8-15 are the cardinality of the set minus 1.
1301 * This way more specific patterns (smaller cardinality) appear first.
1302 * Wildcards have a special value, so that we can directly compare them to
1303 * sets by subtracting the two values. In particular:
1304 * 0x000xx one character, xx
1305 * 0x0yyxx yy character set starting with xx
1306 * 0x10000 '.' (one or more of anything)
1307 * 0x20000 '!' (zero or more of anything)
1308 * 0x30000 NUL (end of string)
1309 * 0x40000 error in set.
1310 * The pointer to the string is advanced according to needs.
1312 * 1. the empty set is equivalent to NUL.
1313 * 2. given that a full set has always 0 as the first element,
1314 * we could encode the special cases as 0xffXX where XX
1315 * is 1, 2, 3, 4 as used above.
1317 static int ext_cmp1(const char **p)
1320 int c, cmin = 0xff, count = 0;
1323 /* load, sign extend and advance pointer until we find
1324 * a valid character.
1326 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
1327 ; /* ignore some characters */
1329 /* always return unless we have a set of chars */
1331 default: /* ordinary character */
1332 return 0x0000 | (c & 0xff);
1334 case 'N': /* 2..9 */
1335 return 0x0700 | '2' ;
1337 case 'X': /* 0..9 */
1338 return 0x0900 | '0';
1340 case 'Z': /* 1..9 */
1341 return 0x0800 | '1';
1343 case '.': /* wildcard */
1346 case '!': /* earlymatch */
1347 return 0x20000; /* less specific than NULL */
1349 case '\0': /* empty string */
1353 case '[': /* pattern */
1356 /* locate end of set */
1357 end = strchr(*p, ']');
1360 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
1361 return 0x40000; /* XXX make this entry go last... */
1364 bzero(chars, sizeof(chars)); /* clear all chars in the set */
1365 for (; *p < end ; (*p)++) {
1366 unsigned char c1, c2; /* first-last char in range */
1367 c1 = (unsigned char)((*p)[0]);
1368 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
1369 c2 = (unsigned char)((*p)[2]);
1370 *p += 2; /* skip a total of 3 chars */
1371 } else /* individual character */
1375 for (; c1 <= c2; c1++) {
1376 uint32_t mask = 1 << (c1 % 32);
1377 if ( (chars[ c1 / 32 ] & mask) == 0)
1379 chars[ c1 / 32 ] |= mask;
1383 return count == 0 ? 0x30000 : (count | cmin);
1387 * \brief the full routine to compare extensions in rules.
1389 static int ext_cmp(const char *a, const char *b)
1391 /* make sure non-patterns come first.
1392 * If a is not a pattern, it either comes first or
1393 * we use strcmp to compare the strings.
1398 return (b[0] == '_') ? -1 : strcmp(a, b);
1400 /* Now we know a is a pattern; if b is not, a comes first */
1403 #if 0 /* old mode for ext matching */
1404 return strcmp(a, b);
1406 /* ok we need full pattern sorting routine */
1407 while (!ret && a && b)
1408 ret = ext_cmp1(&a) - ext_cmp1(&b);
1412 return (ret > 0) ? 1 : -1;
1415 int ast_extension_cmp(const char *a, const char *b)
1417 return ext_cmp(a, b);
1422 * \brief used ast_extension_{match|close}
1423 * mode is as follows:
1424 * E_MATCH success only on exact match
1425 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
1426 * E_CANMATCH either of the above.
1427 * \retval 0 on no-match
1428 * \retval 1 on match
1429 * \retval 2 on early match.
1432 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
1434 mode &= E_MATCH_MASK; /* only consider the relevant bits */
1436 if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
1439 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
1440 int ld = strlen(data), lp = strlen(pattern);
1442 if (lp < ld) /* pattern too short, cannot match */
1444 /* depending on the mode, accept full or partial match or both */
1445 if (mode == E_MATCH)
1446 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
1447 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
1448 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
1452 pattern++; /* skip leading _ */
1454 * XXX below we stop at '/' which is a separator for the CID info. However we should
1455 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
1457 while (*data && *pattern && *pattern != '/') {
1460 if (*data == '-') { /* skip '-' in data (just a separator) */
1464 switch (toupper(*pattern)) {
1465 case '[': /* a range */
1466 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
1468 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
1469 return 0; /* unconditional failure */
1471 for (pattern++; pattern != end; pattern++) {
1472 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
1473 if (*data >= pattern[0] && *data <= pattern[2])
1474 break; /* match found */
1476 pattern += 2; /* skip a total of 3 chars */
1479 } else if (*data == pattern[0])
1480 break; /* match found */
1484 pattern = end; /* skip and continue */
1487 if (*data < '2' || *data > '9')
1491 if (*data < '0' || *data > '9')
1495 if (*data < '1' || *data > '9')
1498 case '.': /* Must match, even with more digits */
1500 case '!': /* Early match */
1503 case '-': /* Ignore these in patterns */
1504 data--; /* compensate the final data++ */
1507 if (*data != *pattern)
1513 if (*data) /* data longer than pattern, no match */
1516 * match so far, but ran off the end of the data.
1517 * Depending on what is next, determine match or not.
1519 if (*pattern == '\0' || *pattern == '/') /* exact match */
1520 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
1521 else if (*pattern == '!') /* early match */
1523 else /* partial match */
1524 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
1528 * Wrapper around _extension_match_core() to do performance measurement
1529 * using the profiling code.
1531 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
1534 static int prof_id = -2; /* marker for 'unallocated' id */
1536 prof_id = ast_add_profile("ext_match", 0);
1537 ast_mark(prof_id, 1);
1538 i = _extension_match_core(pattern, data, mode);
1539 ast_mark(prof_id, 0);
1543 int ast_extension_match(const char *pattern, const char *data)
1545 return extension_match_core(pattern, data, E_MATCH);
1548 int ast_extension_close(const char *pattern, const char *data, int needmore)
1550 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
1551 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
1552 return extension_match_core(pattern, data, needmore);
1555 struct fake_context /* this struct is purely for matching in the hashtab */
1558 struct ast_exten *root;
1559 struct ast_hashtab *root_tree;
1560 struct match_char *pattern_tree;
1561 struct ast_context *next;
1562 struct ast_include *includes;
1563 struct ast_ignorepat *ignorepats;
1564 const char *registrar;
1565 AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
1566 ast_mutex_t macrolock;
1570 struct ast_context *ast_context_find(const char *name)
1572 struct ast_context *tmp = NULL;
1573 struct fake_context item;
1574 strncpy(item.name,name,256);
1575 ast_rdlock_contexts();
1576 if( contexts_tree ) {
1577 tmp = ast_hashtab_lookup(contexts_tree,&item);
1579 while ( (tmp = ast_walk_contexts(tmp)) ) {
1580 if (!name || !strcasecmp(name, tmp->name))
1584 ast_unlock_contexts();
1588 #define STATUS_NO_CONTEXT 1
1589 #define STATUS_NO_EXTENSION 2
1590 #define STATUS_NO_PRIORITY 3
1591 #define STATUS_NO_LABEL 4
1592 #define STATUS_SUCCESS 5
1594 static int matchcid(const char *cidpattern, const char *callerid)
1596 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
1597 failing to get a number should count as a match, otherwise not */
1599 if (ast_strlen_zero(callerid))
1600 return ast_strlen_zero(cidpattern) ? 1 : 0;
1602 return ast_extension_match(cidpattern, callerid);
1605 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
1606 struct ast_context *bypass, struct pbx_find_info *q,
1607 const char *context, const char *exten, int priority,
1608 const char *label, const char *callerid, enum ext_match_t action)
1611 struct ast_context *tmp=0;
1612 struct ast_exten *e=0, *eroot=0;
1613 struct ast_include *i = 0;
1614 struct ast_sw *sw = 0;
1615 struct ast_exten pattern = {0};
1616 struct scoreboard score = {0};
1618 pattern.label = label;
1619 pattern.priority = priority;
1621 ast_log(LOG_NOTICE,"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int)action);
1623 /* Initialize status if appropriate */
1624 if (q->stacklen == 0) {
1625 q->status = STATUS_NO_CONTEXT;
1628 q->foundcontext = NULL;
1629 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
1630 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
1634 /* Check first to see if we've already been checked */
1635 for (x = 0; x < q->stacklen; x++) {
1636 if (!strcasecmp(q->incstack[x], context))
1640 if (bypass) /* bypass means we only look there */
1642 else { /* look in contexts */
1643 struct fake_context item;
1644 strncpy(item.name,context,256);
1645 tmp = ast_hashtab_lookup(contexts_tree,&item);
1648 while ((tmp = ast_walk_contexts(tmp)) ) {
1649 if (!strcmp(tmp->name, context))
1658 if (q->status < STATUS_NO_EXTENSION)
1659 q->status = STATUS_NO_EXTENSION;
1661 /* Do a search for matching extension */
1664 score.total_specificity = 0;
1666 score.total_length = 0;
1667 if (!tmp->pattern_tree && tmp->root_tree)
1669 create_match_char_tree(tmp);
1671 ast_log(LOG_DEBUG,"Tree Created in context %s:\n", context);
1672 log_match_char_tree(tmp->pattern_tree," ");
1676 ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
1677 log_match_char_tree(tmp->pattern_tree, ":: ");
1680 if (extenpatternmatchnew) {
1681 new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid);
1682 eroot = score.exten;
1684 if (score.last_char == '!' && action == E_MATCHMORE) {
1685 /* We match an extension ending in '!'.
1686 * The decision in this case is final and is NULL (no match).
1689 ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
1694 if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
1695 q->status = STATUS_SUCCESS;
1697 ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
1699 return score.canmatch_exten;
1702 if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
1704 struct ast_exten *z = trie_find_next_match(score.node);
1707 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
1709 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
1714 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
1716 return NULL; /* according to the code, complete matches are null matches in MATCHMORE mode */
1720 /* found entry, now look for the right priority */
1721 if (q->status < STATUS_NO_PRIORITY)
1722 q->status = STATUS_NO_PRIORITY;
1724 if (action == E_FINDLABEL && label ) {
1725 if (q->status < STATUS_NO_LABEL)
1726 q->status = STATUS_NO_LABEL;
1727 e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
1729 e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
1731 if (e) { /* found a valid match */
1732 q->status = STATUS_SUCCESS;
1733 q->foundcontext = context;
1735 ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
1742 /* scan the list trying to match extension and CID */
1744 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
1745 int match = extension_match_core(eroot->exten, exten, action);
1746 /* 0 on fail, 1 on match, 2 on earlymatch */
1748 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
1749 continue; /* keep trying */
1750 if (match == 2 && action == E_MATCHMORE) {
1751 /* We match an extension ending in '!'.
1752 * The decision in this case is final and is NULL (no match).
1756 /* found entry, now look for the right priority */
1757 if (q->status < STATUS_NO_PRIORITY)
1758 q->status = STATUS_NO_PRIORITY;
1760 if (action == E_FINDLABEL && label ) {
1761 if (q->status < STATUS_NO_LABEL)
1762 q->status = STATUS_NO_LABEL;
1763 e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
1765 e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
1768 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
1769 /* Match label or priority */
1770 if (action == E_FINDLABEL) {
1771 if (q->status < STATUS_NO_LABEL)
1772 q->status = STATUS_NO_LABEL;
1773 if (label && e->label && !strcmp(label, e->label))
1774 break; /* found it */
1775 } else if (e->priority == priority) {
1776 break; /* found it */
1777 } /* else keep searching */
1780 if (e) { /* found a valid match */
1781 q->status = STATUS_SUCCESS;
1782 q->foundcontext = context;
1789 /* Check alternative switches */
1790 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
1791 struct ast_switch *asw = pbx_findswitch(sw->name);
1792 ast_switch_f *aswf = NULL;
1796 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
1799 /* Substitute variables now */
1802 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
1804 /* equivalent of extension_match_core() at the switch level */
1805 if (action == E_CANMATCH)
1806 aswf = asw->canmatch;
1807 else if (action == E_MATCHMORE)
1808 aswf = asw->matchmore;
1809 else /* action == E_MATCH */
1811 datap = sw->eval ? sw->tmpdata : sw->data;
1812 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
1813 if (res) { /* Got a match */
1816 q->foundcontext = context;
1817 /* XXX keep status = STATUS_NO_CONTEXT ? */
1821 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
1822 /* Now try any includes we have in this context */
1823 for (i = tmp->includes; i; i = i->next) {
1824 if (include_valid(i)) {
1825 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
1827 ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
1839 * \brief extract offset:length from variable name.
1840 * \return 1 if there is a offset:length part, which is
1841 * trimmed off (values go into variables)
1843 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
1850 for (; *var; var++) {
1854 } else if (*var == ')') {
1856 } else if (*var == ':' && parens == 0) {
1858 sscanf(var, "%d:%d", offset, length);
1859 return 1; /* offset:length valid */
1866 *\brief takes a substring. It is ok to call with value == workspace.
1868 * \param offset < 0 means start from the end of the string and set the beginning
1869 * to be that many characters back.
1870 * \param length is the length of the substring, a value less than 0 means to leave
1871 * that many off the end.
1873 * \param workspace_len
1874 * Always return a copy in workspace.
1876 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
1878 char *ret = workspace;
1879 int lr; /* length of the input string after the copy */
1881 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
1883 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
1885 /* Quick check if no need to do anything */
1886 if (offset == 0 && length >= lr) /* take the whole string */
1889 if (offset < 0) { /* translate negative offset into positive ones */
1890 offset = lr + offset;
1891 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1895 /* too large offset result in empty string so we know what to return */
1897 return ret + lr; /* the final '\0' */
1899 ret += offset; /* move to the start position */
1900 if (length >= 0 && length < lr - offset) /* truncate if necessary */
1902 else if (length < 0) {
1903 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
1904 ret[lr + length - offset] = '\0';
1912 /*! \brief Support for Asterisk built-in variables in the dialplan
1915 - \ref AstVar Channel variables
1916 - \ref AstCauses The HANGUPCAUSE variable
1918 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
1920 const char not_found = '\0';
1922 const char *s; /* the result */
1924 int i, need_substring;
1925 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
1928 ast_channel_lock(c);
1929 places[0] = &c->varshead;
1932 * Make a copy of var because parse_variable_name() modifies the string.
1933 * Then if called directly, we might need to run substring() on the result;
1934 * remember this for later in 'need_substring', 'offset' and 'length'
1936 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
1937 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
1940 * Look first into predefined variables, then into variable lists.
1941 * Variable 's' points to the result, according to the following rules:
1942 * s == ¬_found (set at the beginning) means that we did not find a
1943 * matching variable and need to look into more places.
1944 * If s != ¬_found, s is a valid result string as follows:
1945 * s = NULL if the variable does not have a value;
1946 * you typically do this when looking for an unset predefined variable.
1947 * s = workspace if the result has been assembled there;
1948 * typically done when the result is built e.g. with an snprintf(),
1949 * so we don't need to do an additional copy.
1950 * s != workspace in case we have a string, that needs to be copied
1951 * (the ast_copy_string is done once for all at the end).
1952 * Typically done when the result is already available in some string.
1954 s = ¬_found; /* default value */
1955 if (c) { /* This group requires a valid channel */
1956 /* Names with common parts are looked up a piece at a time using strncmp. */
1957 if (!strncmp(var, "CALL", 4)) {
1958 if (!strncmp(var + 4, "ING", 3)) {
1959 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
1960 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
1962 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
1963 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1965 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
1966 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1968 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
1969 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1973 } else if (!strcmp(var, "HINT")) {
1974 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1975 } else if (!strcmp(var, "HINTNAME")) {
1976 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1977 } else if (!strcmp(var, "EXTEN")) {
1979 } else if (!strcmp(var, "CONTEXT")) {
1981 } else if (!strcmp(var, "PRIORITY")) {
1982 snprintf(workspace, workspacelen, "%d", c->priority);
1984 } else if (!strcmp(var, "CHANNEL")) {
1986 } else if (!strcmp(var, "UNIQUEID")) {
1988 } else if (!strcmp(var, "HANGUPCAUSE")) {
1989 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1993 if (s == ¬_found) { /* look for more */
1994 if (!strcmp(var, "EPOCH")) {
1995 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1997 } else if (!strcmp(var, "SYSTEMNAME")) {
1998 s = ast_config_AST_SYSTEM_NAME;
2001 /* if not found, look into chanvars or global vars */
2002 for (i = 0; s == ¬_found && i < (sizeof(places) / sizeof(places[0])); i++) {
2003 struct ast_var_t *variables;
2006 if (places[i] == &globals)
2007 ast_rwlock_rdlock(&globalslock);
2008 AST_LIST_TRAVERSE(places[i], variables, entries) {
2009 if (strcasecmp(ast_var_name(variables), var)==0) {
2010 s = ast_var_value(variables);
2014 if (places[i] == &globals)
2015 ast_rwlock_unlock(&globalslock);
2017 if (s == ¬_found || s == NULL)
2021 ast_copy_string(workspace, s, workspacelen);
2024 *ret = substring(*ret, offset, length, workspace, workspacelen);
2028 ast_channel_unlock(c);
2031 static void exception_store_free(void *data)
2033 struct pbx_exception *exception = data;
2034 ast_string_field_free_memory(exception);
2035 ast_free(exception);
2038 static struct ast_datastore_info exception_store_info = {
2039 .type = "EXCEPTION",
2040 .destroy = exception_store_free,
2043 int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
2045 const char *reason = vreason;
2046 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
2047 struct pbx_exception *exception = NULL;
2050 ds = ast_channel_datastore_alloc(&exception_store_info, NULL);
2053 exception = ast_calloc(1, sizeof(struct pbx_exception));
2055 ast_channel_datastore_free(ds);
2058 if (ast_string_field_init(exception, 128)) {
2059 ast_free(exception);
2060 ast_channel_datastore_free(ds);
2063 ds->data = exception;
2064 ast_channel_datastore_add(chan, ds);
2066 exception = ds->data;
2068 ast_string_field_set(exception, reason, reason);
2069 ast_string_field_set(exception, context, chan->context);
2070 ast_string_field_set(exception, exten, chan->exten);
2071 exception->priority = chan->priority;
2072 set_ext_pri(chan, "e", 0);
2076 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
2078 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
2079 struct pbx_exception *exception = NULL;
2080 if (!ds || !ds->data)
2082 exception = ds->data;
2083 if (!strcasecmp(data, "REASON"))
2084 ast_copy_string(buf, exception->reason, buflen);
2085 else if (!strcasecmp(data, "CONTEXT"))
2086 ast_copy_string(buf, exception->context, buflen);
2087 else if (!strncasecmp(data, "EXTEN", 5))
2088 ast_copy_string(buf, exception->exten, buflen);
2089 else if (!strcasecmp(data, "PRIORITY"))
2090 snprintf(buf, buflen, "%d", exception->priority);
2096 static struct ast_custom_function exception_function = {
2097 .name = "EXCEPTION",
2098 .synopsis = "Retrieve the details of the current dialplan exception",
2100 "The following fields are available for retrieval:\n"
2101 " reason INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom\n"
2102 " value set by the RaiseException() application\n"
2103 " context The context executing when the exception occurred\n"
2104 " exten The extension executing when the exception occurred\n"
2105 " priority The numeric priority executing when the exception occurred\n",
2106 .syntax = "EXCEPTION(<field>)",
2107 .read = acf_exception_read,
2110 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2112 struct ast_custom_function *acf;
2118 e->command = "core show functions [like]";
2120 "Usage: core show functions [like <text>]\n"
2121 " List builtin functions, optionally only those matching a given string\n";
2127 if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
2129 } else if (a->argc != 3) {
2130 return CLI_SHOWUSAGE;
2133 ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
2135 AST_RWLIST_RDLOCK(&acf_root);
2136 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
2137 if (!like || strstr(acf->name, a->argv[4])) {
2139 ast_cli(a->fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
2142 AST_RWLIST_UNLOCK(&acf_root);
2144 ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
2149 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2151 struct ast_custom_function *acf;
2152 /* Maximum number of characters added by terminal coloring is 22 */
2153 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2154 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2155 char stxtitle[40], *syntax = NULL;
2156 int synopsis_size, description_size, syntax_size;
2163 e->command = "core show function";
2165 "Usage: core show function <function>\n"
2166 " Describe a particular dialplan function.\n";
2169 wordlen = strlen(a->word);
2170 /* case-insensitive for convenience in this 'complete' function */
2171 AST_RWLIST_RDLOCK(&acf_root);
2172 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
2173 if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
2174 ret = ast_strdup(acf->name);
2178 AST_RWLIST_UNLOCK(&acf_root);
2184 return CLI_SHOWUSAGE;
2186 if (!(acf = ast_custom_function_find(a->argv[3]))) {
2187 ast_cli(a->fd, "No function by that name registered.\n");
2193 synopsis_size = strlen(acf->synopsis) + 23;
2195 synopsis_size = strlen("Not available") + 23;
2196 synopsis = alloca(synopsis_size);
2199 description_size = strlen(acf->desc) + 23;
2201 description_size = strlen("Not available") + 23;
2202 description = alloca(description_size);
2205 syntax_size = strlen(acf->syntax) + 23;
2207 syntax_size = strlen("Not available") + 23;
2208 syntax = alloca(syntax_size);
2210 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
2211 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2212 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
2213 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2214 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2216 acf->syntax ? acf->syntax : "Not available",
2217 COLOR_CYAN, 0, syntax_size);
2218 term_color(synopsis,
2219 acf->synopsis ? acf->synopsis : "Not available",
2220 COLOR_CYAN, 0, synopsis_size);
2221 term_color(description,
2222 acf->desc ? acf->desc : "Not available",
2223 COLOR_CYAN, 0, description_size);
2225 ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
2230 struct ast_custom_function *ast_custom_function_find(const char *name)
2232 struct ast_custom_function *acf = NULL;
2234 AST_RWLIST_RDLOCK(&acf_root);
2235 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
2236 if (!strcmp(name, acf->name))
2239 AST_RWLIST_UNLOCK(&acf_root);
2244 int ast_custom_function_unregister(struct ast_custom_function *acf)
2246 struct ast_custom_function *cur;
2251 AST_RWLIST_WRLOCK(&acf_root);
2252 if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
2253 ast_verb(2, "Unregistered custom function %s\n", cur->name);
2254 AST_RWLIST_UNLOCK(&acf_root);
2256 return cur ? 0 : -1;
2259 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
2261 struct ast_custom_function *cur;
2268 AST_RWLIST_WRLOCK(&acf_root);
2270 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
2271 if (!strcmp(acf->name, cur->name)) {
2272 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
2273 AST_RWLIST_UNLOCK(&acf_root);
2278 /* Store in alphabetical order */
2279 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
2280 if (strcasecmp(acf->name, cur->name) < 0) {
2281 AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
2285 AST_RWLIST_TRAVERSE_SAFE_END;
2287 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
2289 AST_RWLIST_UNLOCK(&acf_root);
2291 ast_verb(2, "Registered custom function %s\n", acf->name);
2296 /*! \brief return a pointer to the arguments of the function,
2297 * and terminates the function name with '\\0'
2299 static char *func_args(char *function)
2301 char *args = strchr(function, '(');
2304 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
2308 if ((p = strrchr(args, ')')) )
2311 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
2316 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
2318 char *copy = ast_strdupa(function);
2319 char *args = func_args(copy);
2320 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
2323 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
2324 else if (!acfptr->read)
2325 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
2328 struct ast_module_user *u = NULL;
2330 u = __ast_module_user_add(acfptr->mod, chan);
2331 res = acfptr->read(chan, copy, args, workspace, len);
2332 if (acfptr->mod && u)
2333 __ast_module_user_remove(acfptr->mod, u);
2339 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
2341 char *copy = ast_strdupa(function);
2342 char *args = func_args(copy);
2343 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
2346 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
2347 else if (!acfptr->write)
2348 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
2351 struct ast_module_user *u = NULL;
2353 u = __ast_module_user_add(acfptr->mod, chan);
2354 res = acfptr->write(chan, copy, args, value);
2355 if (acfptr->mod && u)
2356 __ast_module_user_remove(acfptr->mod, u);
2363 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
2365 /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
2367 const char *tmp, *whereweare;
2368 int length, offset, offset2, isfunction;
2369 char *workspace = NULL;
2370 char *ltmp = NULL, *var = NULL;
2371 char *nextvar, *nextexp, *nextthing;
2373 int pos, brackets, needsub, len;
2375 *cp2 = 0; /* just in case nothing ends up there */
2377 while (!ast_strlen_zero(whereweare) && count) {
2378 /* Assume we're copying the whole remaining string */
2379 pos = strlen(whereweare);
2382 nextthing = strchr(whereweare, '$');
2384 switch (nextthing[1]) {
2386 nextvar = nextthing;
2387 pos = nextvar - whereweare;
2390 nextexp = nextthing;
2391 pos = nextexp - whereweare;
2399 /* Can't copy more than 'count' bytes */
2403 /* Copy that many bytes */
2404 memcpy(cp2, whereweare, pos);
2413 /* We have a variable. Find the start and end, and determine
2414 if we are going to have to recursively call ourselves on the
2416 vars = vare = nextvar + 2;
2420 /* Find the end of it */
2421 while (brackets && *vare) {
2422 if ((vare[0] == '$') && (vare[1] == '{')) {
2424 } else if (vare[0] == '{') {
2426 } else if (vare[0] == '}') {
2428 } else if ((vare[0] == '$') && (vare[1] == '['))
2433 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
2434 len = vare - vars - 1;
2436 /* Skip totally over variable string */
2437 whereweare += (len + 3);
2440 var = alloca(VAR_BUF_SIZE);
2442 /* Store variable name (and truncate) */
2443 ast_copy_string(var, vars, len + 1);
2445 /* Substitute if necessary */
2448 ltmp = alloca(VAR_BUF_SIZE);
2450 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
2457 workspace = alloca(VAR_BUF_SIZE);
2459 workspace[0] = '\0';
2461 parse_variable_name(vars, &offset, &offset2, &isfunction);
2463 /* Evaluate function */
2465 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
2467 struct varshead old;
2468 struct ast_channel *c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
2470 memcpy(&old, &c->varshead, sizeof(old));
2471 memcpy(&c->varshead, headp, sizeof(c->varshead));
2472 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
2473 /* Don't deallocate the varshead that was passed in */
2474 memcpy(&c->varshead, &old, sizeof(c->varshead));
2475 ast_channel_free(c);
2477 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
2479 ast_debug(1, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
2481 /* Retrieve variable value */
2482 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
2485 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
2487 length = strlen(cp4);
2490 memcpy(cp2, cp4, length);
2495 } else if (nextexp) {
2496 /* We have an expression. Find the start and end, and determine
2497 if we are going to have to recursively call ourselves on the
2499 vars = vare = nextexp + 2;
2503 /* Find the end of it */
2504 while (brackets && *vare) {
2505 if ((vare[0] == '$') && (vare[1] == '[')) {
2509 } else if (vare[0] == '[') {
2511 } else if (vare[0] == ']') {
2513 } else if ((vare[0] == '$') && (vare[1] == '{')) {
2520 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
2521 len = vare - vars - 1;
2523 /* Skip totally over expression */
2524 whereweare += (len + 3);
2527 var = alloca(VAR_BUF_SIZE);
2529 /* Store variable name (and truncate) */
2530 ast_copy_string(var, vars, len + 1);
2532 /* Substitute if necessary */
2535 ltmp = alloca(VAR_BUF_SIZE);
2537 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
2543 length = ast_expr(vars, cp2, count, c);
2546 ast_debug(1, "Expression result is '%s'\n", cp2);
2555 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
2557 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
2560 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
2562 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
2565 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
2569 /* Nothing more to do */
2573 /* No variables or expressions in e->data, so why scan it? */
2574 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
2575 ast_copy_string(passdata, e->data, datalen);
2579 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
2583 * \brief The return value depends on the action:
2585 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
2586 * and return 0 on failure, -1 on match;
2587 * E_FINDLABEL maps the label to a priority, and returns
2588 * the priority on success, ... XXX
2589 * E_SPAWN, spawn an application,
2591 * \retval 0 on success.
2592 * \retval -1 on failure.
2594 * \note The channel is auto-serviced in this function, because doing an extension
2595 * match may block for a long time. For example, if the lookup has to use a network
2596 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
2597 * auto-service code will queue up any important signalling frames to be processed
2598 * after this is done.
2600 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
2601 const char *context, const char *exten, int priority,
2602 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
2604 struct ast_exten *e;
2605 struct ast_app *app;
2607 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
2608 char passdata[EXT_DATA_SIZE];
2610 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
2613 ast_autoservice_start(c);
2615 ast_rdlock_contexts();
2619 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
2623 if (matching_action) {
2624 ast_unlock_contexts();
2626 ast_autoservice_stop(c);
2627 return -1; /* success, we found it */
2628 } else if (action == E_FINDLABEL) { /* map the label to a priority */
2630 ast_unlock_contexts();
2632 ast_autoservice_stop(c);
2633 return res; /* the priority we were looking for */
2634 } else { /* spawn */
2636 e->cached_app = pbx_findapp(e->app);
2637 app = e->cached_app;
2638 ast_unlock_contexts();
2640 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
2642 ast_autoservice_stop(c);
2645 if (c->context != context)
2646 ast_copy_string(c->context, context, sizeof(c->context));
2647 if (c->exten != exten)
2648 ast_copy_string(c->exten, exten, sizeof(c->exten));
2649 c->priority = priority;
2650 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
2651 ast_debug(1, "Launching '%s'\n", app->name);
2652 if (option_verbose > 2) {
2653 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
2654 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
2655 exten, context, priority,
2656 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
2657 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
2658 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
2661 manager_event(EVENT_FLAG_CALL, "Newexten",
2666 "Application: %s\r\n"
2669 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
2671 ast_autoservice_stop(c);
2672 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
2674 } else if (q.swo) { /* not found here, but in another switch */
2675 ast_unlock_contexts();
2676 if (matching_action) {
2678 ast_autoservice_stop(c);
2682 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
2686 ast_autoservice_stop(c);
2687 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
2689 } else { /* not found anywhere, see what happened */
2690 ast_unlock_contexts();
2692 case STATUS_NO_CONTEXT:
2693 if (!matching_action && !combined_find_spawn)
2694 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
2696 case STATUS_NO_EXTENSION:
2697 if (!matching_action && !combined_find_spawn)
2698 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
2700 case STATUS_NO_PRIORITY:
2701 if (!matching_action && !combined_find_spawn)
2702 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
2704 case STATUS_NO_LABEL:
2705 if (context && !combined_find_spawn)
2706 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
2709 ast_debug(1, "Shouldn't happen!\n");
2713 ast_autoservice_stop(c);
2715 return (matching_action) ? 0 : -1;
2719 /*! \brief Find hint for given extension in context */
2720 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
2722 struct ast_exten *e;
2723 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
2725 ast_rdlock_contexts();
2726 e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
2727 ast_unlock_contexts();
2732 /*! \brief Check state of extension by using hints */
2733 static int ast_extension_state2(struct ast_exten *e)
2735 char hint[AST_MAX_EXTENSION];
2737 int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
2738 int busy = 0, inuse = 0, ring = 0;
2743 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
2745 rest = hint; /* One or more devices separated with a & character */
2746 while ( (cur = strsep(&rest, "&")) ) {
2747 int res = ast_device_state(cur);
2749 case AST_DEVICE_NOT_INUSE:
2754 case AST_DEVICE_INUSE:
2760 case AST_DEVICE_RINGING:
2766 case AST_DEVICE_RINGINUSE:
2773 case AST_DEVICE_ONHOLD:
2777 case AST_DEVICE_BUSY:
2783 case AST_DEVICE_UNAVAILABLE:
2784 case AST_DEVICE_INVALID:
2798 return AST_EXTENSION_RINGING;
2800 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
2802 return AST_EXTENSION_INUSE;
2804 return AST_EXTENSION_NOT_INUSE;
2806 return AST_EXTENSION_ONHOLD;
2808 return AST_EXTENSION_BUSY;
2810 return AST_EXTENSION_UNAVAILABLE;
2812 return AST_EXTENSION_INUSE;
2814 return AST_EXTENSION_NOT_INUSE;
2817 /*! \brief Return extension_state as string */
2818 const char *ast_extension_state2str(int extension_state)
2822 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
2823 if (extension_states[i].extension_state == extension_state)
2824 return extension_states[i].text;
2829 /*! \brief Check extension state for an extension by using hint */
2830 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
2832 struct ast_exten *e;
2834 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
2836 return -1; /* No hint, return -1 */
2838 return ast_extension_state2(e); /* Check all devices in the hint */
2841 static void handle_statechange(const char *device)
2843 struct ast_hint *hint;
2845 AST_RWLIST_RDLOCK(&hints);
2847 AST_RWLIST_TRAVERSE(&hints, hint, list) {
2848 struct ast_state_cb *cblist;
2849 char buf[AST_MAX_EXTENSION];
2854 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
2855 while ( (cur = strsep(&parse, "&")) ) {
2856 if (!strcasecmp(cur, device))
2862 /* Get device state for this hint */
2863 state = ast_extension_state2(hint->exten);
2865 if ((state == -1) || (state == hint->laststate))
2868 /* Device state changed since last check - notify the watchers */
2870 /* For general callbacks */
2871 for (cblist = statecbs; cblist; cblist = cblist->next)
2872 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
2874 /* For extension callbacks */
2875 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
2876 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
2878 hint->laststate = state; /* record we saw the change */
2881 AST_RWLIST_UNLOCK(&hints);
2884 static int statechange_queue(const char *dev)
2886 struct statechange *sc;
2888 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
2891 strcpy(sc->dev, dev);
2893 ast_mutex_lock(&device_state.lock);
2894 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
2895 ast_cond_signal(&device_state.cond);
2896 ast_mutex_unlock(&device_state.lock);
2901 static void *device_state_thread(void *data)
2903 struct statechange *sc;
2905 while (!device_state.stop) {
2906 ast_mutex_lock(&device_state.lock);
2907 while (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
2908 ast_cond_wait(&device_state.cond, &device_state.lock);
2909 /* Check to see if we were woken up to see the request to stop */
2910 if (device_state.stop) {
2911 ast_mutex_unlock(&device_state.lock);
2915 ast_mutex_unlock(&device_state.lock);
2917 handle_statechange(sc->dev);
2925 /*! \brief Add watcher for extension states */
2926 int ast_extension_state_add(const char *context, const char *exten,
2927 ast_state_cb_type callback, void *data)
2929 struct ast_hint *hint;
2930 struct ast_state_cb *cblist;
2931 struct ast_exten *e;
2933 /* If there's no context and extension: add callback to statecbs list */
2934 if (!context && !exten) {
2935 AST_RWLIST_WRLOCK(&hints);
2937 for (cblist = statecbs; cblist; cblist = cblist->next) {
2938 if (cblist->callback == callback) {
2939 cblist->data = data;
2940 AST_RWLIST_UNLOCK(&hints);
2945 /* Now insert the callback */
2946 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
2947 AST_RWLIST_UNLOCK(&hints);
2951 cblist->callback = callback;
2952 cblist->data = data;
2954 cblist->next = statecbs;
2957 AST_RWLIST_UNLOCK(&hints);
2961 if (!context || !exten)
2964 /* This callback type is for only one hint, so get the hint */
2965 e = ast_hint_extension(NULL, context, exten);
2970 /* Find the hint in the list of hints */
2971 AST_RWLIST_WRLOCK(&hints);
2973 AST_RWLIST_TRAVERSE(&hints, hint, list) {
2974 if (hint->exten == e)
2979 /* We have no hint, sorry */
2980 AST_RWLIST_UNLOCK(&hints);
2984 /* Now insert the callback in the callback list */
2985 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
2986 AST_RWLIST_UNLOCK(&hints);
2989 cblist->id = stateid++; /* Unique ID for this callback */
2990 cblist->callback = callback; /* Pointer to callback routine */
2991 cblist->data = data; /* Data for the callback */
2993 cblist->next = hint->callbacks;
2994 hint->callbacks = cblist;
2996 AST_RWLIST_UNLOCK(&hints);
3000 /*! \brief Remove a watcher from the callback list */
3001 int ast_extension_state_del(int id, ast_state_cb_type callback)
3003 struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
3006 if (!id && !callback)
3009 AST_RWLIST_WRLOCK(&hints);
3011 if (!id) { /* id == 0 is a callback without extension */
3012 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
3013 if ((*p_cur)->callback == callback)
3016 } else { /* callback with extension, find the callback based on ID */
3017 struct ast_hint *hint;
3018 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3019 for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
3020 if ((*p_cur)->id == id)
3023 if (*p_cur) /* found in the inner loop */
3027 if (p_cur && *p_cur) {
3028 struct ast_state_cb *cur = *p_cur;
3033 AST_RWLIST_UNLOCK(&hints);
3037 /*! \brief Add hint to hint list, check initial extension state */
3038 static int ast_add_hint(struct ast_exten *e)
3040 struct ast_hint *hint;
3045 AST_RWLIST_WRLOCK(&hints);
3047 /* Search if hint exists, do nothing */
3048 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3049 if (hint->exten == e) {
3050 AST_RWLIST_UNLOCK(&hints);
3051 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3056 ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3058 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
3059 AST_RWLIST_UNLOCK(&hints);
3062 /* Initialize and insert new item at the top */
3064 hint->laststate = ast_extension_state2(e);
3065 AST_RWLIST_INSERT_HEAD(&hints, hint, list);
3067 AST_RWLIST_UNLOCK(&hints);
3071 /*! \brief Change hint for an extension */
3072 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
3074 struct ast_hint *hint;
3077 AST_RWLIST_WRLOCK(&hints);
3078 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3079 if (hint->exten == oe) {
3085 AST_RWLIST_UNLOCK(&hints);
3090 /*! \brief Remove hint from extension */
3091 static int ast_remove_hint(struct ast_exten *e)
3093 /* Cleanup the Notifys if hint is removed */
3094 struct ast_hint *hint;
3095 struct ast_state_cb *cblist, *cbprev;
3101 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
3102 if (hint->exten == e) {
3104 cblist = hint->callbacks;