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;
1816 ast_autoservice_start(chan);
1817 res = aswf(chan, context, exten, priority, callerid, datap);
1819 ast_autoservice_stop(chan);
1821 if (res) { /* Got a match */
1824 q->foundcontext = context;
1825 /* XXX keep status = STATUS_NO_CONTEXT ? */
1829 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
1830 /* Now try any includes we have in this context */
1831 for (i = tmp->includes; i; i = i->next) {
1832 if (include_valid(i)) {
1833 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
1835 ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
1847 * \brief extract offset:length from variable name.
1848 * \return 1 if there is a offset:length part, which is
1849 * trimmed off (values go into variables)
1851 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
1858 for (; *var; var++) {
1862 } else if (*var == ')') {
1864 } else if (*var == ':' && parens == 0) {
1866 sscanf(var, "%d:%d", offset, length);
1867 return 1; /* offset:length valid */
1874 *\brief takes a substring. It is ok to call with value == workspace.
1876 * \param offset < 0 means start from the end of the string and set the beginning
1877 * to be that many characters back.
1878 * \param length is the length of the substring, a value less than 0 means to leave
1879 * that many off the end.
1881 * \param workspace_len
1882 * Always return a copy in workspace.
1884 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
1886 char *ret = workspace;
1887 int lr; /* length of the input string after the copy */
1889 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
1891 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
1893 /* Quick check if no need to do anything */
1894 if (offset == 0 && length >= lr) /* take the whole string */
1897 if (offset < 0) { /* translate negative offset into positive ones */
1898 offset = lr + offset;
1899 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1903 /* too large offset result in empty string so we know what to return */
1905 return ret + lr; /* the final '\0' */
1907 ret += offset; /* move to the start position */
1908 if (length >= 0 && length < lr - offset) /* truncate if necessary */
1910 else if (length < 0) {
1911 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
1912 ret[lr + length - offset] = '\0';
1920 /*! \brief Support for Asterisk built-in variables in the dialplan
1923 - \ref AstVar Channel variables
1924 - \ref AstCauses The HANGUPCAUSE variable
1926 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
1928 const char not_found = '\0';
1930 const char *s; /* the result */
1932 int i, need_substring;
1933 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
1936 ast_channel_lock(c);
1937 places[0] = &c->varshead;
1940 * Make a copy of var because parse_variable_name() modifies the string.
1941 * Then if called directly, we might need to run substring() on the result;
1942 * remember this for later in 'need_substring', 'offset' and 'length'
1944 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
1945 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
1948 * Look first into predefined variables, then into variable lists.
1949 * Variable 's' points to the result, according to the following rules:
1950 * s == ¬_found (set at the beginning) means that we did not find a
1951 * matching variable and need to look into more places.
1952 * If s != ¬_found, s is a valid result string as follows:
1953 * s = NULL if the variable does not have a value;
1954 * you typically do this when looking for an unset predefined variable.
1955 * s = workspace if the result has been assembled there;
1956 * typically done when the result is built e.g. with an snprintf(),
1957 * so we don't need to do an additional copy.
1958 * s != workspace in case we have a string, that needs to be copied
1959 * (the ast_copy_string is done once for all at the end).
1960 * Typically done when the result is already available in some string.
1962 s = ¬_found; /* default value */
1963 if (c) { /* This group requires a valid channel */
1964 /* Names with common parts are looked up a piece at a time using strncmp. */
1965 if (!strncmp(var, "CALL", 4)) {
1966 if (!strncmp(var + 4, "ING", 3)) {
1967 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
1968 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
1970 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
1971 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1973 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
1974 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1976 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
1977 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1981 } else if (!strcmp(var, "HINT")) {
1982 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1983 } else if (!strcmp(var, "HINTNAME")) {
1984 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1985 } else if (!strcmp(var, "EXTEN")) {
1987 } else if (!strcmp(var, "CONTEXT")) {
1989 } else if (!strcmp(var, "PRIORITY")) {
1990 snprintf(workspace, workspacelen, "%d", c->priority);
1992 } else if (!strcmp(var, "CHANNEL")) {
1994 } else if (!strcmp(var, "UNIQUEID")) {
1996 } else if (!strcmp(var, "HANGUPCAUSE")) {
1997 snprintf(workspace, workspacelen, "%d", c->hangupcause);
2001 if (s == ¬_found) { /* look for more */
2002 if (!strcmp(var, "EPOCH")) {
2003 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
2005 } else if (!strcmp(var, "SYSTEMNAME")) {
2006 s = ast_config_AST_SYSTEM_NAME;
2009 /* if not found, look into chanvars or global vars */
2010 for (i = 0; s == ¬_found && i < (sizeof(places) / sizeof(places[0])); i++) {
2011 struct ast_var_t *variables;
2014 if (places[i] == &globals)
2015 ast_rwlock_rdlock(&globalslock);
2016 AST_LIST_TRAVERSE(places[i], variables, entries) {
2017 if (strcasecmp(ast_var_name(variables), var)==0) {
2018 s = ast_var_value(variables);
2022 if (places[i] == &globals)
2023 ast_rwlock_unlock(&globalslock);
2025 if (s == ¬_found || s == NULL)
2029 ast_copy_string(workspace, s, workspacelen);
2032 *ret = substring(*ret, offset, length, workspace, workspacelen);
2036 ast_channel_unlock(c);
2039 static void exception_store_free(void *data)
2041 struct pbx_exception *exception = data;
2042 ast_string_field_free_memory(exception);
2043 ast_free(exception);
2046 static struct ast_datastore_info exception_store_info = {
2047 .type = "EXCEPTION",
2048 .destroy = exception_store_free,
2051 int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
2053 const char *reason = vreason;
2054 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
2055 struct pbx_exception *exception = NULL;
2058 ds = ast_channel_datastore_alloc(&exception_store_info, NULL);
2061 exception = ast_calloc(1, sizeof(struct pbx_exception));
2063 ast_channel_datastore_free(ds);
2066 if (ast_string_field_init(exception, 128)) {
2067 ast_free(exception);
2068 ast_channel_datastore_free(ds);
2071 ds->data = exception;
2072 ast_channel_datastore_add(chan, ds);
2074 exception = ds->data;
2076 ast_string_field_set(exception, reason, reason);
2077 ast_string_field_set(exception, context, chan->context);
2078 ast_string_field_set(exception, exten, chan->exten);
2079 exception->priority = chan->priority;
2080 set_ext_pri(chan, "e", 0);
2084 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
2086 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
2087 struct pbx_exception *exception = NULL;
2088 if (!ds || !ds->data)
2090 exception = ds->data;
2091 if (!strcasecmp(data, "REASON"))
2092 ast_copy_string(buf, exception->reason, buflen);
2093 else if (!strcasecmp(data, "CONTEXT"))
2094 ast_copy_string(buf, exception->context, buflen);
2095 else if (!strncasecmp(data, "EXTEN", 5))
2096 ast_copy_string(buf, exception->exten, buflen);
2097 else if (!strcasecmp(data, "PRIORITY"))
2098 snprintf(buf, buflen, "%d", exception->priority);
2104 static struct ast_custom_function exception_function = {
2105 .name = "EXCEPTION",
2106 .synopsis = "Retrieve the details of the current dialplan exception",
2108 "The following fields are available for retrieval:\n"
2109 " reason INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom\n"
2110 " value set by the RaiseException() application\n"
2111 " context The context executing when the exception occurred\n"
2112 " exten The extension executing when the exception occurred\n"
2113 " priority The numeric priority executing when the exception occurred\n",
2114 .syntax = "EXCEPTION(<field>)",
2115 .read = acf_exception_read,
2118 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2120 struct ast_custom_function *acf;
2126 e->command = "core show functions [like]";
2128 "Usage: core show functions [like <text>]\n"
2129 " List builtin functions, optionally only those matching a given string\n";
2135 if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
2137 } else if (a->argc != 3) {
2138 return CLI_SHOWUSAGE;
2141 ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
2143 AST_RWLIST_RDLOCK(&acf_root);
2144 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
2145 if (!like || strstr(acf->name, a->argv[4])) {
2147 ast_cli(a->fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
2150 AST_RWLIST_UNLOCK(&acf_root);
2152 ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
2157 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2159 struct ast_custom_function *acf;
2160 /* Maximum number of characters added by terminal coloring is 22 */
2161 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2162 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2163 char stxtitle[40], *syntax = NULL;
2164 int synopsis_size, description_size, syntax_size;
2171 e->command = "core show function";
2173 "Usage: core show function <function>\n"
2174 " Describe a particular dialplan function.\n";
2177 wordlen = strlen(a->word);
2178 /* case-insensitive for convenience in this 'complete' function */
2179 AST_RWLIST_RDLOCK(&acf_root);
2180 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
2181 if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
2182 ret = ast_strdup(acf->name);
2186 AST_RWLIST_UNLOCK(&acf_root);
2192 return CLI_SHOWUSAGE;
2194 if (!(acf = ast_custom_function_find(a->argv[3]))) {
2195 ast_cli(a->fd, "No function by that name registered.\n");
2201 synopsis_size = strlen(acf->synopsis) + 23;
2203 synopsis_size = strlen("Not available") + 23;
2204 synopsis = alloca(synopsis_size);
2207 description_size = strlen(acf->desc) + 23;
2209 description_size = strlen("Not available") + 23;
2210 description = alloca(description_size);
2213 syntax_size = strlen(acf->syntax) + 23;
2215 syntax_size = strlen("Not available") + 23;
2216 syntax = alloca(syntax_size);
2218 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
2219 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2220 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
2221 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2222 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2224 acf->syntax ? acf->syntax : "Not available",
2225 COLOR_CYAN, 0, syntax_size);
2226 term_color(synopsis,
2227 acf->synopsis ? acf->synopsis : "Not available",
2228 COLOR_CYAN, 0, synopsis_size);
2229 term_color(description,
2230 acf->desc ? acf->desc : "Not available",
2231 COLOR_CYAN, 0, description_size);
2233 ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
2238 struct ast_custom_function *ast_custom_function_find(const char *name)
2240 struct ast_custom_function *acf = NULL;
2242 AST_RWLIST_RDLOCK(&acf_root);
2243 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
2244 if (!strcmp(name, acf->name))
2247 AST_RWLIST_UNLOCK(&acf_root);
2252 int ast_custom_function_unregister(struct ast_custom_function *acf)
2254 struct ast_custom_function *cur;
2259 AST_RWLIST_WRLOCK(&acf_root);
2260 if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
2261 ast_verb(2, "Unregistered custom function %s\n", cur->name);
2262 AST_RWLIST_UNLOCK(&acf_root);
2264 return cur ? 0 : -1;
2267 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
2269 struct ast_custom_function *cur;
2276 AST_RWLIST_WRLOCK(&acf_root);
2278 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
2279 if (!strcmp(acf->name, cur->name)) {
2280 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
2281 AST_RWLIST_UNLOCK(&acf_root);
2286 /* Store in alphabetical order */
2287 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
2288 if (strcasecmp(acf->name, cur->name) < 0) {
2289 AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
2293 AST_RWLIST_TRAVERSE_SAFE_END;
2295 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
2297 AST_RWLIST_UNLOCK(&acf_root);
2299 ast_verb(2, "Registered custom function %s\n", acf->name);
2304 /*! \brief return a pointer to the arguments of the function,
2305 * and terminates the function name with '\\0'
2307 static char *func_args(char *function)
2309 char *args = strchr(function, '(');
2312 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
2316 if ((p = strrchr(args, ')')) )
2319 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
2324 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
2326 char *copy = ast_strdupa(function);
2327 char *args = func_args(copy);
2328 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
2331 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
2332 else if (!acfptr->read)
2333 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
2336 struct ast_module_user *u = NULL;
2338 u = __ast_module_user_add(acfptr->mod, chan);
2339 res = acfptr->read(chan, copy, args, workspace, len);
2340 if (acfptr->mod && u)
2341 __ast_module_user_remove(acfptr->mod, u);
2347 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
2349 char *copy = ast_strdupa(function);
2350 char *args = func_args(copy);
2351 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
2354 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
2355 else if (!acfptr->write)
2356 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
2359 struct ast_module_user *u = NULL;
2361 u = __ast_module_user_add(acfptr->mod, chan);
2362 res = acfptr->write(chan, copy, args, value);
2363 if (acfptr->mod && u)
2364 __ast_module_user_remove(acfptr->mod, u);
2371 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
2373 /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
2375 const char *tmp, *whereweare;
2376 int length, offset, offset2, isfunction;
2377 char *workspace = NULL;
2378 char *ltmp = NULL, *var = NULL;
2379 char *nextvar, *nextexp, *nextthing;
2381 int pos, brackets, needsub, len;
2383 *cp2 = 0; /* just in case nothing ends up there */
2385 while (!ast_strlen_zero(whereweare) && count) {
2386 /* Assume we're copying the whole remaining string */
2387 pos = strlen(whereweare);
2390 nextthing = strchr(whereweare, '$');
2392 switch (nextthing[1]) {
2394 nextvar = nextthing;
2395 pos = nextvar - whereweare;
2398 nextexp = nextthing;
2399 pos = nextexp - whereweare;
2407 /* Can't copy more than 'count' bytes */
2411 /* Copy that many bytes */
2412 memcpy(cp2, whereweare, pos);
2421 /* We have a variable. Find the start and end, and determine
2422 if we are going to have to recursively call ourselves on the
2424 vars = vare = nextvar + 2;
2428 /* Find the end of it */
2429 while (brackets && *vare) {
2430 if ((vare[0] == '$') && (vare[1] == '{')) {
2432 } else if (vare[0] == '{') {
2434 } else if (vare[0] == '}') {
2436 } else if ((vare[0] == '$') && (vare[1] == '['))
2441 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
2442 len = vare - vars - 1;
2444 /* Skip totally over variable string */
2445 whereweare += (len + 3);
2448 var = alloca(VAR_BUF_SIZE);
2450 /* Store variable name (and truncate) */
2451 ast_copy_string(var, vars, len + 1);
2453 /* Substitute if necessary */
2456 ltmp = alloca(VAR_BUF_SIZE);
2458 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
2465 workspace = alloca(VAR_BUF_SIZE);
2467 workspace[0] = '\0';
2469 parse_variable_name(vars, &offset, &offset2, &isfunction);
2471 /* Evaluate function */
2473 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
2475 struct varshead old;
2476 struct ast_channel *c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
2478 memcpy(&old, &c->varshead, sizeof(old));
2479 memcpy(&c->varshead, headp, sizeof(c->varshead));
2480 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
2481 /* Don't deallocate the varshead that was passed in */
2482 memcpy(&c->varshead, &old, sizeof(c->varshead));
2483 ast_channel_free(c);
2485 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
2487 ast_debug(1, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
2489 /* Retrieve variable value */
2490 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
2493 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
2495 length = strlen(cp4);
2498 memcpy(cp2, cp4, length);
2503 } else if (nextexp) {
2504 /* We have an expression. Find the start and end, and determine
2505 if we are going to have to recursively call ourselves on the
2507 vars = vare = nextexp + 2;
2511 /* Find the end of it */
2512 while (brackets && *vare) {
2513 if ((vare[0] == '$') && (vare[1] == '[')) {
2517 } else if (vare[0] == '[') {
2519 } else if (vare[0] == ']') {
2521 } else if ((vare[0] == '$') && (vare[1] == '{')) {
2528 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
2529 len = vare - vars - 1;
2531 /* Skip totally over expression */
2532 whereweare += (len + 3);
2535 var = alloca(VAR_BUF_SIZE);
2537 /* Store variable name (and truncate) */
2538 ast_copy_string(var, vars, len + 1);
2540 /* Substitute if necessary */
2543 ltmp = alloca(VAR_BUF_SIZE);
2545 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
2551 length = ast_expr(vars, cp2, count, c);
2554 ast_debug(1, "Expression result is '%s'\n", cp2);
2563 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
2565 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
2568 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
2570 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
2573 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
2577 /* Nothing more to do */
2581 /* No variables or expressions in e->data, so why scan it? */
2582 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
2583 ast_copy_string(passdata, e->data, datalen);
2587 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
2591 * \brief The return value depends on the action:
2593 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
2594 * and return 0 on failure, -1 on match;
2595 * E_FINDLABEL maps the label to a priority, and returns
2596 * the priority on success, ... XXX
2597 * E_SPAWN, spawn an application,
2599 * \retval 0 on success.
2600 * \retval -1 on failure.
2602 * \note The channel is auto-serviced in this function, because doing an extension
2603 * match may block for a long time. For example, if the lookup has to use a network
2604 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
2605 * auto-service code will queue up any important signalling frames to be processed
2606 * after this is done.
2608 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
2609 const char *context, const char *exten, int priority,
2610 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
2612 struct ast_exten *e;
2613 struct ast_app *app;
2615 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
2616 char passdata[EXT_DATA_SIZE];
2618 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
2620 ast_rdlock_contexts();
2624 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
2628 if (matching_action) {
2629 ast_unlock_contexts();
2630 return -1; /* success, we found it */
2631 } else if (action == E_FINDLABEL) { /* map the label to a priority */
2633 ast_unlock_contexts();
2634 return res; /* the priority we were looking for */
2635 } else { /* spawn */
2637 e->cached_app = pbx_findapp(e->app);
2638 app = e->cached_app;
2639 ast_unlock_contexts();
2641 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
2644 if (c->context != context)
2645 ast_copy_string(c->context, context, sizeof(c->context));
2646 if (c->exten != exten)
2647 ast_copy_string(c->exten, exten, sizeof(c->exten));
2648 c->priority = priority;
2649 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
2650 ast_debug(1, "Launching '%s'\n", app->name);
2651 if (option_verbose > 2) {
2652 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
2653 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
2654 exten, context, priority,
2655 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
2656 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
2657 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
2660 manager_event(EVENT_FLAG_CALL, "Newexten",
2665 "Application: %s\r\n"
2668 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
2669 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
2671 } else if (q.swo) { /* not found here, but in another switch */
2672 ast_unlock_contexts();
2673 if (matching_action) {
2677 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
2680 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
2682 } else { /* not found anywhere, see what happened */
2683 ast_unlock_contexts();
2685 case STATUS_NO_CONTEXT:
2686 if (!matching_action && !combined_find_spawn)
2687 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
2689 case STATUS_NO_EXTENSION:
2690 if (!matching_action && !combined_find_spawn)
2691 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
2693 case STATUS_NO_PRIORITY:
2694 if (!matching_action && !combined_find_spawn)
2695 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
2697 case STATUS_NO_LABEL:
2698 if (context && !combined_find_spawn)
2699 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
2702 ast_debug(1, "Shouldn't happen!\n");
2705 return (matching_action) ? 0 : -1;
2709 /*! \brief Find hint for given extension in context */
2710 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
2712 struct ast_exten *e;
2713 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
2715 ast_rdlock_contexts();
2716 e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
2717 ast_unlock_contexts();
2722 /*! \brief Check state of extension by using hints */
2723 static int ast_extension_state2(struct ast_exten *e)
2725 char hint[AST_MAX_EXTENSION];
2727 int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
2728 int busy = 0, inuse = 0, ring = 0;
2733 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
2735 rest = hint; /* One or more devices separated with a & character */
2736 while ( (cur = strsep(&rest, "&")) ) {
2737 int res = ast_device_state(cur);
2739 case AST_DEVICE_NOT_INUSE:
2744 case AST_DEVICE_INUSE:
2750 case AST_DEVICE_RINGING:
2756 case AST_DEVICE_RINGINUSE:
2763 case AST_DEVICE_ONHOLD:
2767 case AST_DEVICE_BUSY:
2773 case AST_DEVICE_UNAVAILABLE:
2774 case AST_DEVICE_INVALID:
2788 return AST_EXTENSION_RINGING;
2790 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
2792 return AST_EXTENSION_INUSE;
2794 return AST_EXTENSION_NOT_INUSE;
2796 return AST_EXTENSION_ONHOLD;
2798 return AST_EXTENSION_BUSY;
2800 return AST_EXTENSION_UNAVAILABLE;
2802 return AST_EXTENSION_INUSE;
2804 return AST_EXTENSION_NOT_INUSE;
2807 /*! \brief Return extension_state as string */
2808 const char *ast_extension_state2str(int extension_state)
2812 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
2813 if (extension_states[i].extension_state == extension_state)
2814 return extension_states[i].text;
2819 /*! \brief Check extension state for an extension by using hint */
2820 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
2822 struct ast_exten *e;
2824 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
2826 return -1; /* No hint, return -1 */
2828 return ast_extension_state2(e); /* Check all devices in the hint */
2831 static void handle_statechange(const char *device)
2833 struct ast_hint *hint;
2835 AST_RWLIST_RDLOCK(&hints);
2837 AST_RWLIST_TRAVERSE(&hints, hint, list) {
2838 struct ast_state_cb *cblist;
2839 char buf[AST_MAX_EXTENSION];
2844 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
2845 while ( (cur = strsep(&parse, "&")) ) {
2846 if (!strcasecmp(cur, device))
2852 /* Get device state for this hint */
2853 state = ast_extension_state2(hint->exten);
2855 if ((state == -1) || (state == hint->laststate))
2858 /* Device state changed since last check - notify the watchers */
2860 /* For general callbacks */
2861 for (cblist = statecbs; cblist; cblist = cblist->next)
2862 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
2864 /* For extension callbacks */
2865 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
2866 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
2868 hint->laststate = state; /* record we saw the change */
2871 AST_RWLIST_UNLOCK(&hints);
2874 static int statechange_queue(const char *dev)
2876 struct statechange *sc;
2878 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
2881 strcpy(sc->dev, dev);
2883 ast_mutex_lock(&device_state.lock);
2884 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
2885 ast_cond_signal(&device_state.cond);
2886 ast_mutex_unlock(&device_state.lock);
2891 static void *device_state_thread(void *data)
2893 struct statechange *sc;
2895 while (!device_state.stop) {
2896 ast_mutex_lock(&device_state.lock);
2897 while (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
2898 ast_cond_wait(&device_state.cond, &device_state.lock);
2899 /* Check to see if we were woken up to see the request to stop */
2900 if (device_state.stop) {
2901 ast_mutex_unlock(&device_state.lock);
2905 ast_mutex_unlock(&device_state.lock);
2907 handle_statechange(sc->dev);
2915 /*! \brief Add watcher for extension states */
2916 int ast_extension_state_add(const char *context, const char *exten,
2917 ast_state_cb_type callback, void *data)
2919 struct ast_hint *hint;
2920 struct ast_state_cb *cblist;
2921 struct ast_exten *e;
2923 /* If there's no context and extension: add callback to statecbs list */
2924 if (!context && !exten) {
2925 AST_RWLIST_WRLOCK(&hints);
2927 for (cblist = statecbs; cblist; cblist = cblist->next) {
2928 if (cblist->callback == callback) {
2929 cblist->data = data;
2930 AST_RWLIST_UNLOCK(&hints);
2935 /* Now insert the callback */
2936 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
2937 AST_RWLIST_UNLOCK(&hints);
2941 cblist->callback = callback;
2942 cblist->data = data;
2944 cblist->next = statecbs;
2947 AST_RWLIST_UNLOCK(&hints);
2951 if (!context || !exten)
2954 /* This callback type is for only one hint, so get the hint */
2955 e = ast_hint_extension(NULL, context, exten);
2960 /* Find the hint in the list of hints */
2961 AST_RWLIST_WRLOCK(&hints);
2963 AST_RWLIST_TRAVERSE(&hints, hint, list) {
2964 if (hint->exten == e)
2969 /* We have no hint, sorry */
2970 AST_RWLIST_UNLOCK(&hints);
2974 /* Now insert the callback in the callback list */
2975 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
2976 AST_RWLIST_UNLOCK(&hints);
2979 cblist->id = stateid++; /* Unique ID for this callback */
2980 cblist->callback = callback; /* Pointer to callback routine */
2981 cblist->data = data; /* Data for the callback */
2983 cblist->next = hint->callbacks;
2984 hint->callbacks = cblist;
2986 AST_RWLIST_UNLOCK(&hints);
2990 /*! \brief Remove a watcher from the callback list */
2991 int ast_extension_state_del(int id, ast_state_cb_type callback)
2993 struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
2996 if (!id && !callback)
2999 AST_RWLIST_WRLOCK(&hints);
3001 if (!id) { /* id == 0 is a callback without extension */
3002 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
3003 if ((*p_cur)->callback == callback)
3006 } else { /* callback with extension, find the callback based on ID */
3007 struct ast_hint *hint;
3008 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3009 for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
3010 if ((*p_cur)->id == id)
3013 if (*p_cur) /* found in the inner loop */
3017 if (p_cur && *p_cur) {
3018 struct ast_state_cb *cur = *p_cur;
3023 AST_RWLIST_UNLOCK(&hints);
3027 /*! \brief Add hint to hint list, check initial extension state */
3028 static int ast_add_hint(struct ast_exten *e)
3030 struct ast_hint *hint;
3035 AST_RWLIST_WRLOCK(&hints);
3037 /* Search if hint exists, do nothing */
3038 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3039 if (hint->exten == e) {
3040 AST_RWLIST_UNLOCK(&hints);
3041 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3046 ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3048 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
3049 AST_RWLIST_UNLOCK(&hints);
3052 /* Initialize and insert new item at the top */
3054 hint->laststate = ast_extension_state2(e);
3055 AST_RWLIST_INSERT_HEAD(&hints, hint, list);
3057 AST_RWLIST_UNLOCK(&hints);
3061 /*! \brief Change hint for an extension */
3062 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
3064 struct ast_hint *hint;
3067 AST_RWLIST_WRLOCK(&hints);
3068 AST_RWLIST_TRAVERSE(&hints, hint, list) {
3069 if (hint->exten == oe) {
3075 AST_RWLIST_UNLOCK(&hints);
3080 /*! \brief Remove hint from extension */
3081 static int ast_remove_hint(struct ast_exten *e)
3083 /* Cleanup the Notifys if hint is removed */
3084 struct ast_hint *hint;
3085 struct ast_state_cb *cblist, *cbprev;
3091 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
3092 if (hint->exten == e) {
3094 cblist = hint->callbacks;
3096 /* Notify with -1 and remove all callbacks */
3098 cblist = cblist->next;
3099 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);