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 <sys/types.h>
41 #include "asterisk/lock.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/options.h"
46 #include "asterisk/logger.h"
47 #include "asterisk/file.h"
48 #include "asterisk/callerid.h"
49 #include "asterisk/cdr.h"
50 #include "asterisk/config.h"
51 #include "asterisk/term.h"
52 #include "asterisk/manager.h"
53 #include "asterisk/ast_expr.h"
54 #include "asterisk/linkedlists.h"
55 #define SAY_STUBS /* generate declarations and stubs for say methods */
56 #include "asterisk/say.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/causes.h"
59 #include "asterisk/musiconhold.h"
60 #include "asterisk/app.h"
61 #include "asterisk/devicestate.h"
62 #include "asterisk/stringfields.h"
65 * \note I M P O R T A N T :
67 * The speed of extension handling will likely be among the most important
68 * aspects of this PBX. The switching scheme as it exists right now isn't
69 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
70 * of priorities, but a constant search time here would be great ;-)
75 #define EXT_DATA_SIZE 256
77 #define EXT_DATA_SIZE 8192
80 #define SWITCH_DATA_LENGTH 256
82 #define VAR_BUF_SIZE 4096
85 #define VAR_SOFTTRAN 2
86 #define VAR_HARDTRAN 3
88 #define BACKGROUND_SKIP (1 << 0)
89 #define BACKGROUND_NOANSWER (1 << 1)
90 #define BACKGROUND_MATCHEXTEN (1 << 2)
91 #define BACKGROUND_PLAYBACK (1 << 3)
93 AST_APP_OPTIONS(background_opts, {
94 AST_APP_OPTION('s', BACKGROUND_SKIP),
95 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
96 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
97 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
100 #define WAITEXTEN_MOH (1 << 0)
102 AST_APP_OPTIONS(waitexten_opts, {
103 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
109 \brief ast_exten: An extension
110 The dialplan is saved as a linked list with each context
111 having it's own linked list of extensions - one item per
115 char *exten; /*!< Extension name */
116 int matchcid; /*!< Match caller id ? */
117 const char *cidmatch; /*!< Caller id to match for this extension */
118 int priority; /*!< Priority */
119 const char *label; /*!< Label */
120 struct ast_context *parent; /*!< The context this extension belongs to */
121 const char *app; /*!< Application to execute */
122 void *data; /*!< Data to use (arguments) */
123 void (*datad)(void *); /*!< Data destructor */
124 struct ast_exten *peer; /*!< Next higher priority with our extension */
125 const char *registrar; /*!< Registrar */
126 struct ast_exten *next; /*!< Extension with a greater ID */
130 /*! \brief ast_include: include= support in extensions.conf */
133 const char *rname; /*!< Context to include */
134 const char *registrar; /*!< Registrar */
135 int hastime; /*!< If time construct exists */
136 struct ast_timing timing; /*!< time construct */
137 struct ast_include *next; /*!< Link them together */
141 /*! \brief ast_sw: Switch statement in extensions.conf */
144 const char *registrar; /*!< Registrar */
145 char *data; /*!< Data load */
147 AST_LIST_ENTRY(ast_sw) list;
152 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
153 struct ast_ignorepat {
154 const char *registrar;
155 struct ast_ignorepat *next;
156 const char pattern[0];
159 /*! \brief ast_context: An extension context */
161 ast_mutex_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
162 struct ast_exten *root; /*!< The root of the list of extensions */
163 struct ast_context *next; /*!< Link them together */
164 struct ast_include *includes; /*!< Include other contexts */
165 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
166 const char *registrar; /*!< Registrar */
167 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
168 char name[0]; /*!< Name of the context */
172 /*! \brief ast_app: A registered application */
174 int (*execute)(struct ast_channel *chan, void *data);
175 const char *synopsis; /*!< Synopsis text for 'show applications' */
176 const char *description; /*!< Description (help text) for 'show application <name>' */
177 AST_LIST_ENTRY(ast_app) list; /*!< Next app in list */
178 struct module *module; /*!< Module this app belongs to */
179 char name[0]; /*!< Name of the application */
182 /*! \brief ast_state_cb: An extension state notify register item */
183 struct ast_state_cb {
186 ast_state_cb_type callback;
187 struct ast_state_cb *next;
190 /*! \brief Structure for dial plan hints
192 \note Hints are pointers from an extension in the dialplan to one or
193 more devices (tech/name) */
195 struct ast_exten *exten; /*!< Extension */
196 int laststate; /*!< Last known state */
197 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
198 AST_LIST_ENTRY(ast_hint) list; /*!< Pointer to next hint in list */
201 static const struct cfextension_states {
203 const char * const text;
204 } extension_states[] = {
205 { AST_EXTENSION_NOT_INUSE, "Idle" },
206 { AST_EXTENSION_INUSE, "InUse" },
207 { AST_EXTENSION_BUSY, "Busy" },
208 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
209 { AST_EXTENSION_RINGING, "Ringing" },
210 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
211 { AST_EXTENSION_ONHOLD, "Hold" },
212 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
215 static int pbx_builtin_answer(struct ast_channel *, void *);
216 static int pbx_builtin_goto(struct ast_channel *, void *);
217 static int pbx_builtin_hangup(struct ast_channel *, void *);
218 static int pbx_builtin_background(struct ast_channel *, void *);
219 static int pbx_builtin_wait(struct ast_channel *, void *);
220 static int pbx_builtin_waitexten(struct ast_channel *, void *);
221 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
222 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
223 static int pbx_builtin_ringing(struct ast_channel *, void *);
224 static int pbx_builtin_progress(struct ast_channel *, void *);
225 static int pbx_builtin_congestion(struct ast_channel *, void *);
226 static int pbx_builtin_busy(struct ast_channel *, void *);
227 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
228 static int pbx_builtin_noop(struct ast_channel *, void *);
229 static int pbx_builtin_gotoif(struct ast_channel *, void *);
230 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
231 static int pbx_builtin_execiftime(struct ast_channel *, void *);
232 static int pbx_builtin_saynumber(struct ast_channel *, void *);
233 static int pbx_builtin_saydigits(struct ast_channel *, void *);
234 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
235 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
236 int pbx_builtin_setvar(struct ast_channel *, void *);
237 static int pbx_builtin_importvar(struct ast_channel *, void *);
239 AST_MUTEX_DEFINE_STATIC(globalslock);
240 static struct varshead globals;
242 static int autofallthrough = 0;
244 AST_MUTEX_DEFINE_STATIC(maxcalllock);
245 static int countcalls = 0;
247 static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
249 /*! \brief Declaration of builtin applications */
250 static struct pbx_builtin {
251 char name[AST_MAX_APP];
252 int (*execute)(struct ast_channel *chan, void *data);
257 /* These applications are built into the PBX core and do not
258 need separate modules */
260 { "Answer", pbx_builtin_answer,
261 "Answer a channel if ringing",
262 " Answer([delay]): If the call has not been answered, this application will\n"
263 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
264 "Asterisk will wait this number of milliseconds before answering the call.\n"
267 { "BackGround", pbx_builtin_background,
268 "Play an audio file while waiting for digits of an extension to go to.",
269 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
270 "This application will play the given list of files while waiting for an\n"
271 "extension to be dialed by the calling channel. To continue waiting for digits\n"
272 "after this application has finished playing files, the WaitExten application\n"
273 "should be used. The 'langoverride' option explicitly specifies which language\n"
274 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
275 "this is the dialplan context that this application will use when exiting to a\n"
277 " If one of the requested sound files does not exist, call processing will be\n"
280 " s - Causes the playback of the message to be skipped\n"
281 " if the channel is not in the 'up' state (i.e. it\n"
282 " hasn't been answered yet). If this happens, the\n"
283 " application will return immediately.\n"
284 " n - Don't answer the channel before playing the files.\n"
285 " m - Only break if a digit hit matches a one digit\n"
286 " extension in the destination context.\n"
289 { "Busy", pbx_builtin_busy,
290 "Indicate the Busy condition",
291 " Busy([timeout]): This application will indicate the busy condition to\n"
292 "the calling channel. If the optional timeout is specified, the calling channel\n"
293 "will be hung up after the specified number of seconds. Otherwise, this\n"
294 "application will wait until the calling channel hangs up.\n"
297 { "Congestion", pbx_builtin_congestion,
298 "Indicate the Congestion condition",
299 " Congestion([timeout]): This application will indicate the congestion\n"
300 "condition to the calling channel. If the optional timeout is specified, the\n"
301 "calling channel will be hung up after the specified number of seconds.\n"
302 "Otherwise, this application will wait until the calling channel hangs up.\n"
305 { "Goto", pbx_builtin_goto,
306 "Jump to a particular priority, extension, or context",
307 " Goto([[context|]extension|]priority): This application will cause the\n"
308 "calling channel to continue dialplan execution at the specified priority.\n"
309 "If no specific extension, or extension and context, are specified, then this\n"
310 "application will jump to the specified priority of the current extension.\n"
311 " If the attempt to jump to another location in the dialplan is not successful,\n"
312 "then the channel will continue at the next priority of the current extension.\n"
315 { "GotoIf", pbx_builtin_gotoif,
317 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
318 "the calling channel to jump to the specified location in the dialplan based on\n"
319 "the evaluation of the given condition. The channel will continue at\n"
320 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
321 "false. The labels are specified with the same syntax as used within the Goto\n"
322 "application. If the label chosen by the condition is omitted, no jump is\n"
323 "performed, but execution continues with the next priority in the dialplan.\n"
326 { "GotoIfTime", pbx_builtin_gotoiftime,
327 "Conditional Goto based on the current time",
328 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
329 "This application will have the calling channel jump to the specified location\n"
330 "in the dialplan if the current time matches the given time specification.\n"
333 { "ExecIfTime", pbx_builtin_execiftime,
334 "Conditional application execution based on the current time",
335 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
336 "This application will execute the specified dialplan application, with optional\n"
337 "arguments, if the current time matches the given time specification.\n"
340 { "Hangup", pbx_builtin_hangup,
341 "Hang up the calling channel",
342 " Hangup([causecode]): This application will hang up the calling channel.\n"
343 "If a causecode is given the channel's hangup cause will be set to the given\n"
347 { "NoOp", pbx_builtin_noop,
349 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
350 "purposes. Any text that is provided as arguments to this application can be\n"
351 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
352 "variables or functions without having any effect."
355 { "Progress", pbx_builtin_progress,
357 " Progress(): This application will request that in-band progress information\n"
358 "be provided to the calling channel.\n"
361 { "ResetCDR", pbx_builtin_resetcdr,
362 "Resets the Call Data Record",
363 " ResetCDR([options]): This application causes the Call Data Record to be\n"
366 " w -- Store the current CDR record before resetting it.\n"
367 " a -- Store any stacked records.\n"
368 " v -- Save CDR variables.\n"
371 { "Ringing", pbx_builtin_ringing,
372 "Indicate ringing tone",
373 " Ringing(): This application will request that the channel indicate a ringing\n"
374 "tone to the user.\n"
377 { "SayNumber", pbx_builtin_saynumber,
379 " SayNumber(digits[,gender]): This application will play the sounds that\n"
380 "correspond to the given number. Optionally, a gender may be specified.\n"
381 "This will use the language that is currently set for the channel. See the\n"
382 "LANGUAGE function for more information on setting the language for the channel.\n"
385 { "SayDigits", pbx_builtin_saydigits,
387 " SayDigits(digits): This application will play the sounds that correspond\n"
388 "to the digits of the given number. This will use the language that is currently\n"
389 "set for the channel. See the LANGUAGE function for more information on setting\n"
390 "the language for the channel.\n"
393 { "SayAlpha", pbx_builtin_saycharacters,
395 " SayAlpha(string): This application will play the sounds that correspond to\n"
396 "the letters of the given string.\n"
399 { "SayPhonetic", pbx_builtin_sayphonetic,
401 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
402 "alphabet that correspond to the letters in the given string.\n"
405 { "SetAMAFlags", pbx_builtin_setamaflags,
407 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
408 " billing purposes.\n"
411 { "SetGlobalVar", pbx_builtin_setglobalvar,
412 "Set a global variable to a given value",
413 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
414 "the specified value.\n"
417 { "Set", pbx_builtin_setvar,
418 "Set channel variable(s) or function value(s)",
419 " Set(name1=value1|name2=value2|..[|options])\n"
420 "This function can be used to set the value of channel variables or dialplan\n"
421 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
422 "if the variable name is prefixed with _, the variable will be inherited into\n"
423 "channels created from the current channel. If the variable name is prefixed\n"
424 "with __, the variable will be inherited into channels created from the current\n"
425 "channel and all children channels.\n"
427 " g - Set variable globally instead of on the channel\n"
428 " (applies only to variables, not functions)\n"
431 { "ImportVar", pbx_builtin_importvar,
432 "Import a variable from a channel into a new variable",
433 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
434 "from the specified channel (as opposed to the current one) and stores it as\n"
435 "a variable in the current channel (the channel that is calling this\n"
436 "application). Variables created by this application have the same inheritance\n"
437 "properties as those created with the Set application. See the documentation for\n"
438 "Set for more information.\n"
441 { "Wait", pbx_builtin_wait,
442 "Waits for some time",
443 " Wait(seconds): This application waits for a specified number of seconds.\n"
444 "Then, dialplan execution will continue at the next priority.\n"
445 " Note that the seconds can be passed with fractions of a second. For example,\n"
446 "'1.5' will ask the application to wait for 1.5 seconds.\n"
449 { "WaitExten", pbx_builtin_waitexten,
450 "Waits for an extension to be entered",
451 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
452 "a new extension for a specified number of seconds.\n"
453 " Note that the seconds can be passed with fractions of a second. For example,\n"
454 "'1.5' will ask the application to wait for 1.5 seconds.\n"
456 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
457 " Optionally, specify the class for music on hold within parenthesis.\n"
462 static struct ast_context *contexts = NULL;
463 AST_MUTEX_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
465 static AST_LIST_HEAD_STATIC(apps, ast_app);
467 static AST_LIST_HEAD_STATIC(switches, ast_switch);
469 static int stateid = 1;
471 When holding this list's lock, do _not_ do anything that will cause conlock
472 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
473 function will take the locks in conlock/hints order, so any other
474 paths that require both locks must also take them in that order.
476 static AST_LIST_HEAD_STATIC(hints, ast_hint);
477 struct ast_state_cb *statecbs = NULL;
480 \note This function is special. It saves the stack so that no matter
481 how many times it is called, it returns to the same place */
482 int pbx_exec(struct ast_channel *c, /*!< Channel */
483 struct ast_app *app, /*!< Application */
484 void *data) /*!< Data for execution */
488 const char *saved_c_appl;
489 const char *saved_c_data;
492 ast_cdr_setapp(c->cdr, app->name, data);
494 /* save channel values */
495 saved_c_appl= c->appl;
496 saved_c_data= c->data;
500 /* XXX remember what to to when we have linked apps to modules */
502 /* XXX LOCAL_USER_ADD(app->module) */
504 res = app->execute(c, data);
506 /* XXX LOCAL_USER_REMOVE(app->module) */
508 /* restore channel values */
509 c->appl = saved_c_appl;
510 c->data = saved_c_data;
515 /*! Go no deeper than this through includes (not counting loops) */
516 #define AST_PBX_MAX_STACK 128
518 /*! \brief Find application handle in linked list
520 struct ast_app *pbx_findapp(const char *app)
524 AST_LIST_LOCK(&apps);
525 AST_LIST_TRAVERSE(&apps, tmp, list) {
526 if (!strcasecmp(tmp->name, app))
529 AST_LIST_UNLOCK(&apps);
534 static struct ast_switch *pbx_findswitch(const char *sw)
536 struct ast_switch *asw;
538 AST_LIST_LOCK(&switches);
539 AST_LIST_TRAVERSE(&switches, asw, list) {
540 if (!strcasecmp(asw->name, sw))
543 AST_LIST_UNLOCK(&switches);
548 static inline int include_valid(struct ast_include *i)
553 return ast_check_timing(&(i->timing));
556 static void pbx_destroy(struct ast_pbx *p)
562 * Special characters used in patterns:
563 * '_' underscore is the leading character of a pattern.
564 * In other position it is treated as a regular char.
565 * ' ' '-' space and '-' are separator and ignored.
566 * . one or more of any character. Only allowed at the end of
568 * ! zero or more of anything. Also impacts the result of CANMATCH
569 * and MATCHMORE. Only allowed at the end of a pattern.
570 * In the core routine, ! causes a match with a return code of 2.
571 * In turn, depending on the search mode: (XXX check if it is implemented)
572 * - E_MATCH retuns 1 (does match)
573 * - E_MATCHMORE returns 0 (no match)
574 * - E_CANMATCH returns 1 (does match)
576 * / should not appear as it is considered the separator of the CID info.
577 * XXX at the moment we may stop on this char.
579 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
580 * [ denotes the start of a set of character. Everything inside
581 * is considered literally. We can have ranges a-d and individual
582 * characters. A '[' and '-' can be considered literally if they
583 * are just before ']'.
584 * XXX currently there is no way to specify ']' in a range, nor \ is
585 * considered specially.
587 * When we compare a pattern with a specific extension, all characters in the extension
588 * itself are considered literally with the only exception of '-' which is considered
589 * as a separator and thus ignored.
590 * XXX do we want to consider space as a separator as well ?
591 * XXX do we want to consider the separators in non-patterns as well ?
595 * \brief helper functions to sort extensions and patterns in the desired way,
596 * so that more specific patterns appear first.
598 * ext_cmp1 compares individual characters (or sets of), returning
599 * an int where bits 0-7 are the ASCII code of the first char in the set,
600 * while bit 8-15 are the cardinality of the set minus 1.
601 * This way more specific patterns (smaller cardinality) appear first.
602 * Wildcards have a special value, so that we can directly compare them to
603 * sets by subtracting the two values. In particular:
604 * 0x000xx one character, xx
605 * 0x0yyxx yy character set starting with xx
606 * 0x10000 '.' (one or more of anything)
607 * 0x20000 '!' (zero or more of anything)
608 * 0x30000 NUL (end of string)
609 * 0x40000 error in set.
610 * The pointer to the string is advanced according to needs.
612 * 1. the empty set is equivalent to NUL.
613 * 2. given that a full set has always 0 as the first element,
614 * we could encode the special cases as 0xffXX where XX
615 * is 1, 2, 3, 4 as used above.
617 static int ext_cmp1(const char **p)
620 int c, cmin = 0xff, count = 0;
623 /* load, sign extend and advance pointer until we find
626 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
627 ; /* ignore some characters */
629 /* always return unless we have a set of chars */
631 default: /* ordinary character */
632 return 0x0000 | (c & 0xff);
635 return 0x0700 | '2' ;
643 case '.': /* wildcard */
646 case '!': /* earlymatch */
647 return 0x20000; /* less specific than NULL */
649 case '\0': /* empty string */
653 case '[': /* pattern */
656 /* locate end of set */
657 end = strchr(*p, ']');
660 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
661 return 0x40000; /* XXX make this entry go last... */
664 bzero(chars, sizeof(chars)); /* clear all chars in the set */
665 for (; *p < end ; (*p)++) {
666 unsigned char c1, c2; /* first-last char in range */
667 c1 = (unsigned char)((*p)[0]);
668 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
669 c2 = (unsigned char)((*p)[2]);
670 *p += 2; /* skip a total of 3 chars */
671 } else /* individual character */
675 for (; c1 <= c2; c1++) {
676 uint32_t mask = 1 << (c1 % 32);
677 if ( (chars[ c1 / 32 ] & mask) == 0)
679 chars[ c1 / 32 ] |= mask;
683 return count == 0 ? 0x30000 : (count | cmin);
687 * \brief the full routine to compare extensions in rules.
689 static int ext_cmp(const char *a, const char *b)
691 /* make sure non-patterns come first.
692 * If a is not a pattern, it either comes first or
693 * we use strcmp to compare the strings.
698 return (b[0] == '_') ? -1 : strcmp(a, b);
700 /* Now we know a is a pattern; if b is not, a comes first */
703 #if 0 /* old mode for ext matching */
706 /* ok we need full pattern sorting routine */
707 while (!ret && a && b)
708 ret = ext_cmp1(&a) - ext_cmp1(&b);
712 return (ret > 0) ? 1 : -1;
716 * When looking up extensions, we can have different requests
717 * identified by the 'action' argument, as follows.
718 * Note that the coding is such that the low 4 bits are the
719 * third argument to extension_match_core.
722 E_MATCHMORE = 0x00, /* extension can match but only with more 'digits' */
723 E_CANMATCH = 0x01, /* extension can match with or without more 'digits' */
724 E_MATCH = 0x02, /* extension is an exact match */
725 E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
726 E_SPAWN = 0x12, /* want to spawn an extension. Requires exact match */
727 E_FINDLABEL = 0x22 /* returns the priority for a given label. Requires exact match */
731 * Internal function for ast_extension_{match|close}
732 * return 0 on no-match, 1 on match, 2 on early match.
733 * mode is as follows:
734 * E_MATCH success only on exact match
735 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
736 * E_CANMATCH either of the above.
738 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
740 mode &= E_MATCH_MASK; /* only consider the relevant bits */
742 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
743 int ld = strlen(data), lp = strlen(pattern);
745 if (lp < ld) /* pattern too short, cannot match */
747 /* depending on the mode, accept full or partial match or both */
749 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
750 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
751 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
755 pattern++; /* skip leading _ */
757 * XXX below we stop at '/' which is a separator for the CID info. However we should
758 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
760 while (*data && *pattern && *pattern != '/') {
763 if (*data == '-') { /* skip '-' in data (just a separator) */
767 switch (toupper(*pattern)) {
768 case '[': /* a range */
769 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
771 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
772 return 0; /* unconditional failure */
774 for (pattern++; pattern != end; pattern++) {
775 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
776 if (*data >= pattern[0] && *data <= pattern[2])
777 break; /* match found */
779 pattern += 2; /* skip a total of 3 chars */
782 } else if (*data == pattern[0])
783 break; /* match found */
787 pattern = end; /* skip and continue */
790 if (*data < '2' || *data > '9')
794 if (*data < '0' || *data > '9')
798 if (*data < '1' || *data > '9')
801 case '.': /* Must match, even with more digits */
803 case '!': /* Early match */
806 case '-': /* Ignore these in patterns */
807 data--; /* compensate the final data++ */
810 if (*data != *pattern)
816 if (*data) /* data longer than pattern, no match */
819 * match so far, but ran off the end of the data.
820 * Depending on what is next, determine match or not.
822 if (*pattern == '\0' || *pattern == '/') /* exact match */
823 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
824 else if (*pattern == '!') /* early match */
826 else /* partial match */
827 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
831 * Wrapper around _extension_match_core() to do performance measurement
832 * using the profiling code.
834 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
837 static int prof_id = -2; /* marker for 'unallocated' id */
839 prof_id = ast_add_profile("ext_match", 0);
840 ast_mark(prof_id, 1);
841 i = _extension_match_core(pattern, data, mode);
842 ast_mark(prof_id, 0);
846 int ast_extension_match(const char *pattern, const char *data)
848 return extension_match_core(pattern, data, E_MATCH);
851 int ast_extension_close(const char *pattern, const char *data, int needmore)
853 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
854 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
855 return extension_match_core(pattern, data, needmore);
858 struct ast_context *ast_context_find(const char *name)
860 struct ast_context *tmp = NULL;
861 ast_mutex_lock(&conlock);
862 while ( (tmp = ast_walk_contexts(tmp)) ) {
863 if (!name || !strcasecmp(name, tmp->name))
866 ast_mutex_unlock(&conlock);
870 #define STATUS_NO_CONTEXT 1
871 #define STATUS_NO_EXTENSION 2
872 #define STATUS_NO_PRIORITY 3
873 #define STATUS_NO_LABEL 4
874 #define STATUS_SUCCESS 5
876 static int matchcid(const char *cidpattern, const char *callerid)
878 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
879 failing to get a number should count as a match, otherwise not */
881 if (ast_strlen_zero(callerid))
882 return ast_strlen_zero(cidpattern) ? 1 : 0;
884 return ast_extension_match(cidpattern, callerid);
887 /* request and result for pbx_find_extension */
888 struct pbx_find_info {
895 char *incstack[AST_PBX_MAX_STACK]; /* filled during the search */
896 int stacklen; /* modified during the search */
897 int status; /* set on return */
898 struct ast_switch *swo; /* set on return */
899 const char *data; /* set on return */
900 const char *foundcontext; /* set on return */
903 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
904 struct ast_context *bypass, struct pbx_find_info *q,
905 const char *context, const char *exten, int priority,
906 const char *label, const char *callerid, enum ext_match_t action)
909 struct ast_context *tmp;
910 struct ast_exten *e, *eroot;
911 struct ast_include *i;
914 /* Initialize status if appropriate */
915 if (q->stacklen == 0) {
916 q->status = STATUS_NO_CONTEXT;
919 q->foundcontext = NULL;
921 /* Check for stack overflow */
922 if (q->stacklen >= AST_PBX_MAX_STACK) {
923 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
926 /* Check first to see if we've already been checked */
927 for (x = 0; x < q->stacklen; x++) {
928 if (!strcasecmp(q->incstack[x], context))
931 if (bypass) /* bypass means we only look there */
933 else { /* look in contexts */
935 while ((tmp = ast_walk_contexts(tmp)) ) {
936 if (!strcmp(tmp->name, context))
942 if (q->status < STATUS_NO_EXTENSION)
943 q->status = STATUS_NO_EXTENSION;
945 /* scan the list trying to match extension and CID */
947 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
948 int match = extension_match_core(eroot->exten, exten, action);
949 /* 0 on fail, 1 on match, 2 on earlymatch */
951 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
952 continue; /* keep trying */
953 if (match == 2 && action == E_MATCHMORE) {
954 /* We match an extension ending in '!'.
955 * The decision in this case is final and is NULL (no match).
959 /* found entry, now look for the right priority */
960 if (q->status < STATUS_NO_PRIORITY)
961 q->status = STATUS_NO_PRIORITY;
963 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
964 /* Match label or priority */
965 if (action == E_FINDLABEL) {
966 if (q->status < STATUS_NO_LABEL)
967 q->status = STATUS_NO_LABEL;
968 if (label && e->label && !strcmp(label, e->label))
969 break; /* found it */
970 } else if (e->priority == priority) {
971 break; /* found it */
972 } /* else keep searching */
974 if (e) { /* found a valid match */
975 q->status = STATUS_SUCCESS;
976 q->foundcontext = context;
980 /* Check alternative switches */
981 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
982 struct ast_switch *asw = pbx_findswitch(sw->name);
983 ast_switch_f *aswf = NULL;
987 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
990 /* Substitute variables now */
992 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
994 /* equivalent of extension_match_core() at the switch level */
995 if (action == E_CANMATCH)
996 aswf = asw->canmatch;
997 else if (action == E_MATCHMORE)
998 aswf = asw->matchmore;
999 else /* action == E_MATCH */
1001 datap = sw->eval ? sw->tmpdata : sw->data;
1002 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
1003 if (res) { /* Got a match */
1006 q->foundcontext = context;
1007 /* XXX keep status = STATUS_NO_CONTEXT ? */
1011 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
1012 /* Now try any includes we have in this context */
1013 for (i = tmp->includes; i; i = i->next) {
1014 if (include_valid(i)) {
1015 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
1024 /*! \brief extract offset:length from variable name.
1025 * Returns 1 if there is a offset:length part, which is
1026 * trimmed off (values go into variables)
1028 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
1035 for (; *var; var++) {
1039 } else if (*var == ')') {
1041 } else if (*var == ':' && parens == 0) {
1043 sscanf(var, "%d:%d", offset, length);
1044 return 1; /* offset:length valid */
1050 /*! \brief takes a substring. It is ok to call with value == workspace.
1052 * offset < 0 means start from the end of the string and set the beginning
1053 * to be that many characters back.
1054 * length is the length of the substring. A value less than 0 means to leave
1055 * that many off the end.
1056 * Always return a copy in workspace.
1058 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
1060 char *ret = workspace;
1061 int lr; /* length of the input string after the copy */
1063 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
1065 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
1067 /* Quick check if no need to do anything */
1068 if (offset == 0 && length >= lr) /* take the whole string */
1071 if (offset < 0) { /* translate negative offset into positive ones */
1072 offset = lr + offset;
1073 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1077 /* too large offset result in empty string so we know what to return */
1079 return ret + lr; /* the final '\0' */
1081 ret += offset; /* move to the start position */
1082 if (length >= 0 && length < lr - offset) /* truncate if necessary */
1084 else if (length < 0) {
1085 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
1086 ret[lr + length - offset] = '\0';
1094 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
1095 functions in the dialplan
1097 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
1099 const char not_found = '\0';
1101 const char *s; /* the result */
1103 int i, need_substring;
1104 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
1107 places[0] = &c->varshead;
1110 * Make a copy of var because parse_variable_name() modifies the string.
1111 * Then if called directly, we might need to run substring() on the result;
1112 * remember this for later in 'need_substring', 'offset' and 'length'
1114 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
1115 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
1118 * Look first into predefined variables, then into variable lists.
1119 * Variable 's' points to the result, according to the following rules:
1120 * s == ¬_found (set at the beginning) means that we did not find a
1121 * matching variable and need to look into more places.
1122 * If s != ¬_found, s is a valid result string as follows:
1123 * s = NULL if the variable does not have a value;
1124 * you typically do this when looking for an unset predefined variable.
1125 * s = workspace if the result has been assembled there;
1126 * typically done when the result is built e.g. with an snprintf(),
1127 * so we don't need to do an additional copy.
1128 * s != workspace in case we have a string, that needs to be copied
1129 * (the ast_copy_string is done once for all at the end).
1130 * Typically done when the result is already available in some string.
1132 s = ¬_found; /* default value */
1133 if (c) { /* This group requires a valid channel */
1134 /* Names with common parts are looked up a piece at a time using strncmp. */
1135 if (!strncmp(var, "CALL", 4)) {
1136 if (!strncmp(var + 4, "ING", 3)) {
1137 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
1138 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
1140 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
1141 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1143 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
1144 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1146 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
1147 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1151 } else if (!strcmp(var, "HINT")) {
1152 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1153 } else if (!strcmp(var, "HINTNAME")) {
1154 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1155 } else if (!strcmp(var, "EXTEN")) {
1157 } else if (!strcmp(var, "CONTEXT")) {
1159 } else if (!strcmp(var, "PRIORITY")) {
1160 snprintf(workspace, workspacelen, "%d", c->priority);
1162 } else if (!strcmp(var, "CHANNEL")) {
1164 } else if (!strcmp(var, "UNIQUEID")) {
1166 } else if (!strcmp(var, "HANGUPCAUSE")) {
1167 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1171 if (s == ¬_found) { /* look for more */
1172 if (!strcmp(var, "EPOCH")) {
1173 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1175 } else if (!strcmp(var, "SYSTEMNAME")) {
1176 s = ast_config_AST_SYSTEM_NAME;
1179 /* if not found, look into chanvars or global vars */
1180 for (i = 0; s == ¬_found && i < (sizeof(places) / sizeof(places[0])); i++) {
1181 struct ast_var_t *variables;
1184 if (places[i] == &globals)
1185 ast_mutex_lock(&globalslock);
1186 AST_LIST_TRAVERSE(places[i], variables, entries) {
1187 if (strcasecmp(ast_var_name(variables), var)==0) {
1188 s = ast_var_value(variables);
1192 if (places[i] == &globals)
1193 ast_mutex_unlock(&globalslock);
1195 if (s == ¬_found || s == NULL)
1199 ast_copy_string(workspace, s, workspacelen);
1202 *ret = substring(*ret, offset, length, workspace, workspacelen);
1206 /*! \brief CLI function to show installed custom functions
1207 \addtogroup CLI_functions
1209 static int handle_show_functions(int fd, int argc, char *argv[])
1211 struct ast_custom_function *acf;
1215 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1217 } else if (argc != 2) {
1218 return RESULT_SHOWUSAGE;
1221 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1223 AST_LIST_LOCK(&acf_root);
1224 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1225 if (!like || strstr(acf->name, argv[3])) {
1227 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1230 AST_LIST_UNLOCK(&acf_root);
1232 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1234 return RESULT_SUCCESS;
1237 static int handle_show_function(int fd, int argc, char *argv[])
1239 struct ast_custom_function *acf;
1240 /* Maximum number of characters added by terminal coloring is 22 */
1241 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1242 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1243 char stxtitle[40], *syntax = NULL;
1244 int synopsis_size, description_size, syntax_size;
1247 return RESULT_SHOWUSAGE;
1249 if (!(acf = ast_custom_function_find(argv[2]))) {
1250 ast_cli(fd, "No function by that name registered.\n");
1251 return RESULT_FAILURE;
1256 synopsis_size = strlen(acf->synopsis) + 23;
1258 synopsis_size = strlen("Not available") + 23;
1259 synopsis = alloca(synopsis_size);
1262 description_size = strlen(acf->desc) + 23;
1264 description_size = strlen("Not available") + 23;
1265 description = alloca(description_size);
1268 syntax_size = strlen(acf->syntax) + 23;
1270 syntax_size = strlen("Not available") + 23;
1271 syntax = alloca(syntax_size);
1273 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1274 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1275 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1276 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1277 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1279 acf->syntax ? acf->syntax : "Not available",
1280 COLOR_CYAN, 0, syntax_size);
1281 term_color(synopsis,
1282 acf->synopsis ? acf->synopsis : "Not available",
1283 COLOR_CYAN, 0, synopsis_size);
1284 term_color(description,
1285 acf->desc ? acf->desc : "Not available",
1286 COLOR_CYAN, 0, description_size);
1288 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1290 return RESULT_SUCCESS;
1293 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1295 struct ast_custom_function *acf;
1298 int wordlen = strlen(word);
1300 /* case-insensitive for convenience in this 'complete' function */
1301 AST_LIST_LOCK(&acf_root);
1302 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1303 if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
1304 ret = strdup(acf->name);
1308 AST_LIST_UNLOCK(&acf_root);
1313 struct ast_custom_function *ast_custom_function_find(const char *name)
1315 struct ast_custom_function *acf = NULL;
1317 AST_LIST_LOCK(&acf_root);
1318 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1319 if (!strcmp(name, acf->name))
1322 AST_LIST_UNLOCK(&acf_root);
1327 int ast_custom_function_unregister(struct ast_custom_function *acf)
1329 struct ast_custom_function *cur;
1334 AST_LIST_LOCK(&acf_root);
1335 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1337 AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
1338 if (option_verbose > 1)
1339 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1343 AST_LIST_TRAVERSE_SAFE_END
1344 AST_LIST_UNLOCK(&acf_root);
1346 return acf ? 0 : -1;
1349 int ast_custom_function_register(struct ast_custom_function *acf)
1351 struct ast_custom_function *cur;
1356 AST_LIST_LOCK(&acf_root);
1358 if (ast_custom_function_find(acf->name)) {
1359 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1360 AST_LIST_UNLOCK(&acf_root);
1364 /* Store in alphabetical order */
1365 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1366 if (strcasecmp(acf->name, cur->name) < 0) {
1367 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
1371 AST_LIST_TRAVERSE_SAFE_END
1373 AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
1375 AST_LIST_UNLOCK(&acf_root);
1377 if (option_verbose > 1)
1378 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1383 /*! \brief return a pointer to the arguments of the function,
1384 * and terminates the function name with '\\0'
1386 static char *func_args(char *function)
1388 char *args = strchr(function, '(');
1391 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1395 if ((p = strrchr(args, ')')) )
1398 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1403 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1405 char *args = func_args(function);
1406 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1409 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1410 else if (!acfptr->read)
1411 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1413 return acfptr->read(chan, function, args, workspace, len);
1417 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1419 char *args = func_args(function);
1420 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1423 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1424 else if (!acfptr->write)
1425 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1427 return acfptr->write(chan, function, args, value);
1432 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1434 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1437 const char *tmp, *whereweare;
1438 int length, offset, offset2, isfunction;
1439 char *workspace = NULL;
1440 char *ltmp = NULL, *var = NULL;
1441 char *nextvar, *nextexp, *nextthing;
1443 int pos, brackets, needsub, len;
1446 while (!ast_strlen_zero(whereweare) && count) {
1447 /* Assume we're copying the whole remaining string */
1448 pos = strlen(whereweare);
1451 nextthing = strchr(whereweare, '$');
1453 switch(nextthing[1]) {
1455 nextvar = nextthing;
1456 pos = nextvar - whereweare;
1459 nextexp = nextthing;
1460 pos = nextexp - whereweare;
1466 /* Can't copy more than 'count' bytes */
1470 /* Copy that many bytes */
1471 memcpy(cp2, whereweare, pos);
1479 /* We have a variable. Find the start and end, and determine
1480 if we are going to have to recursively call ourselves on the
1482 vars = vare = nextvar + 2;
1486 /* Find the end of it */
1487 while (brackets && *vare) {
1488 if ((vare[0] == '$') && (vare[1] == '{')) {
1490 } else if (vare[0] == '{') {
1492 } else if (vare[0] == '}') {
1494 } else if ((vare[0] == '$') && (vare[1] == '['))
1499 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1500 len = vare - vars - 1;
1502 /* Skip totally over variable string */
1503 whereweare += (len + 3);
1506 var = alloca(VAR_BUF_SIZE);
1508 /* Store variable name (and truncate) */
1509 ast_copy_string(var, vars, len + 1);
1511 /* Substitute if necessary */
1514 ltmp = alloca(VAR_BUF_SIZE);
1516 memset(ltmp, 0, VAR_BUF_SIZE);
1517 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1524 workspace = alloca(VAR_BUF_SIZE);
1526 workspace[0] = '\0';
1528 parse_variable_name(vars, &offset, &offset2, &isfunction);
1530 /* Evaluate function */
1531 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1533 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1535 /* Retrieve variable value */
1536 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1539 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1541 length = strlen(cp4);
1544 memcpy(cp2, cp4, length);
1548 } else if (nextexp) {
1549 /* We have an expression. Find the start and end, and determine
1550 if we are going to have to recursively call ourselves on the
1552 vars = vare = nextexp + 2;
1556 /* Find the end of it */
1557 while(brackets && *vare) {
1558 if ((vare[0] == '$') && (vare[1] == '[')) {
1562 } else if (vare[0] == '[') {
1564 } else if (vare[0] == ']') {
1566 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1573 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1574 len = vare - vars - 1;
1576 /* Skip totally over expression */
1577 whereweare += (len + 3);
1580 var = alloca(VAR_BUF_SIZE);
1582 /* Store variable name (and truncate) */
1583 ast_copy_string(var, vars, len + 1);
1585 /* Substitute if necessary */
1588 ltmp = alloca(VAR_BUF_SIZE);
1590 memset(ltmp, 0, VAR_BUF_SIZE);
1591 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1597 length = ast_expr(vars, cp2, count);
1600 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1609 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1611 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1614 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1616 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1619 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1621 memset(passdata, 0, datalen);
1623 /* No variables or expressions in e->data, so why scan it? */
1624 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1625 ast_copy_string(passdata, e->data, datalen);
1629 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1632 /*! \brief The return value depends on the action:
1634 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1635 * and return 0 on failure, -1 on match;
1636 * E_FINDLABEL maps the label to a priority, and returns
1637 * the priority on success, ... XXX
1638 * E_SPAWN, spawn an application,
1639 * and return 0 on success, -1 on failure.
1641 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
1642 const char *context, const char *exten, int priority,
1643 const char *label, const char *callerid, enum ext_match_t action)
1645 struct ast_exten *e;
1646 struct ast_app *app;
1648 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
1649 char passdata[EXT_DATA_SIZE];
1651 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
1653 ast_mutex_lock(&conlock);
1654 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
1656 if (matching_action) {
1657 ast_mutex_unlock(&conlock);
1658 return -1; /* success, we found it */
1659 } else if (action == E_FINDLABEL) { /* map the label to a priority */
1661 ast_mutex_unlock(&conlock);
1662 return res; /* the priority we were looking for */
1663 } else { /* spawn */
1664 app = pbx_findapp(e->app);
1665 ast_mutex_unlock(&conlock);
1667 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1670 if (c->context != context)
1671 ast_copy_string(c->context, context, sizeof(c->context));
1672 if (c->exten != exten)
1673 ast_copy_string(c->exten, exten, sizeof(c->exten));
1674 c->priority = priority;
1675 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1678 char atmp2[EXT_DATA_SIZE+100];
1679 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1680 snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
1681 snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
1682 app->name, c->name, passdata, "in new stack");
1683 pbx_builtin_setvar_helper(c, atmp, atmp2);
1685 if (option_verbose > 2) {
1686 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
1687 ast_verbose( VERBOSE_PREFIX_3 "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1688 exten, context, priority,
1689 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1690 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1691 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1694 manager_event(EVENT_FLAG_CALL, "Newexten",
1699 "Application: %s\r\n"
1702 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1703 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
1705 } else if (q.swo) { /* not found here, but in another switch */
1706 ast_mutex_unlock(&conlock);
1707 if (matching_action)
1711 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
1714 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
1716 } else { /* not found anywhere, see what happened */
1717 ast_mutex_unlock(&conlock);
1719 case STATUS_NO_CONTEXT:
1720 if (!matching_action)
1721 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1723 case STATUS_NO_EXTENSION:
1724 if (!matching_action)
1725 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1727 case STATUS_NO_PRIORITY:
1728 if (!matching_action)
1729 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1731 case STATUS_NO_LABEL:
1733 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1736 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1739 return (matching_action) ? 0 : -1;
1743 /*! \brief ast_hint_extension: Find hint for given extension in context */
1744 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1746 struct ast_exten *e;
1747 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
1749 ast_mutex_lock(&conlock);
1750 e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
1751 ast_mutex_unlock(&conlock);
1756 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1757 static int ast_extension_state2(struct ast_exten *e)
1759 char hint[AST_MAX_EXTENSION];
1761 int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
1762 int busy = 0, inuse = 0, ring = 0;
1767 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1769 rest = hint; /* One or more devices separated with a & character */
1770 while ( (cur = strsep(&rest, "&")) ) {
1771 int res = ast_device_state(cur);
1773 case AST_DEVICE_NOT_INUSE:
1778 case AST_DEVICE_INUSE:
1784 case AST_DEVICE_RINGING:
1790 case AST_DEVICE_RINGINUSE:
1797 case AST_DEVICE_ONHOLD:
1801 case AST_DEVICE_BUSY:
1807 case AST_DEVICE_UNAVAILABLE:
1808 case AST_DEVICE_INVALID:
1822 return AST_EXTENSION_RINGING;
1824 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1826 return AST_EXTENSION_INUSE;
1828 return AST_EXTENSION_NOT_INUSE;
1830 return AST_EXTENSION_ONHOLD;
1832 return AST_EXTENSION_BUSY;
1834 return AST_EXTENSION_UNAVAILABLE;
1836 return AST_EXTENSION_INUSE;
1838 return AST_EXTENSION_NOT_INUSE;
1841 /*! \brief ast_extension_state2str: Return extension_state as string */
1842 const char *ast_extension_state2str(int extension_state)
1846 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1847 if (extension_states[i].extension_state == extension_state)
1848 return extension_states[i].text;
1853 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1854 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1856 struct ast_exten *e;
1858 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1860 return -1; /* No hint, return -1 */
1862 return ast_extension_state2(e); /* Check all devices in the hint */
1865 void ast_hint_state_changed(const char *device)
1867 struct ast_hint *hint;
1869 AST_LIST_LOCK(&hints);
1871 AST_LIST_TRAVERSE(&hints, hint, list) {
1872 struct ast_state_cb *cblist;
1873 char buf[AST_MAX_EXTENSION];
1878 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1879 while ( (cur = strsep(&parse, "&")) ) {
1880 if (!strcasecmp(cur, device))
1886 /* Get device state for this hint */
1887 state = ast_extension_state2(hint->exten);
1889 if ((state == -1) || (state == hint->laststate))
1892 /* Device state changed since last check - notify the watchers */
1894 /* For general callbacks */
1895 for (cblist = statecbs; cblist; cblist = cblist->next)
1896 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1898 /* For extension callbacks */
1899 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1900 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1902 hint->laststate = state; /* record we saw the change */
1905 AST_LIST_UNLOCK(&hints);
1908 /*! \brief ast_extension_state_add: Add watcher for extension states */
1909 int ast_extension_state_add(const char *context, const char *exten,
1910 ast_state_cb_type callback, void *data)
1912 struct ast_hint *hint;
1913 struct ast_state_cb *cblist;
1914 struct ast_exten *e;
1916 /* If there's no context and extension: add callback to statecbs list */
1917 if (!context && !exten) {
1918 AST_LIST_LOCK(&hints);
1920 for (cblist = statecbs; cblist; cblist = cblist->next) {
1921 if (cblist->callback == callback) {
1922 cblist->data = data;
1923 AST_LIST_UNLOCK(&hints);
1928 /* Now insert the callback */
1929 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1930 AST_LIST_UNLOCK(&hints);
1934 cblist->callback = callback;
1935 cblist->data = data;
1937 cblist->next = statecbs;
1940 AST_LIST_UNLOCK(&hints);
1944 if (!context || !exten)
1947 /* This callback type is for only one hint, so get the hint */
1948 e = ast_hint_extension(NULL, context, exten);
1953 /* Find the hint in the list of hints */
1954 AST_LIST_LOCK(&hints);
1956 AST_LIST_TRAVERSE(&hints, hint, list) {
1957 if (hint->exten == e)
1962 /* We have no hint, sorry */
1963 AST_LIST_UNLOCK(&hints);
1967 /* Now insert the callback in the callback list */
1968 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1969 AST_LIST_UNLOCK(&hints);
1972 cblist->id = stateid++; /* Unique ID for this callback */
1973 cblist->callback = callback; /* Pointer to callback routine */
1974 cblist->data = data; /* Data for the callback */
1976 cblist->next = hint->callbacks;
1977 hint->callbacks = cblist;
1979 AST_LIST_UNLOCK(&hints);
1983 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1984 int ast_extension_state_del(int id, ast_state_cb_type callback)
1986 struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
1989 if (!id && !callback)
1992 AST_LIST_LOCK(&hints);
1994 if (!id) { /* id == 0 is a callback without extension */
1995 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
1996 if ((*p_cur)->callback == callback)
1999 } else { /* callback with extension, find the callback based on ID */
2000 struct ast_hint *hint;
2001 AST_LIST_TRAVERSE(&hints, hint, list) {
2002 for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
2003 if ((*p_cur)->id == id)
2006 if (*p_cur) /* found in the inner loop */
2010 if (p_cur && *p_cur) {
2011 struct ast_state_cb *cur = *p_cur;
2016 AST_LIST_UNLOCK(&hints);
2020 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2021 static int ast_add_hint(struct ast_exten *e)
2023 struct ast_hint *hint;
2028 AST_LIST_LOCK(&hints);
2030 /* Search if hint exists, do nothing */
2031 AST_LIST_TRAVERSE(&hints, hint, list) {
2032 if (hint->exten == e) {
2033 AST_LIST_UNLOCK(&hints);
2034 if (option_debug > 1)
2035 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2040 if (option_debug > 1)
2041 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2043 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
2044 AST_LIST_UNLOCK(&hints);
2047 /* Initialize and insert new item at the top */
2049 hint->laststate = ast_extension_state2(e);
2050 AST_LIST_INSERT_HEAD(&hints, hint, list);
2052 AST_LIST_UNLOCK(&hints);
2056 /*! \brief ast_change_hint: Change hint for an extension */
2057 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2059 struct ast_hint *hint;
2062 AST_LIST_LOCK(&hints);
2063 AST_LIST_TRAVERSE(&hints, hint, list) {
2064 if (hint->exten == oe) {
2070 AST_LIST_UNLOCK(&hints);
2075 /*! \brief ast_remove_hint: Remove hint from extension */
2076 static int ast_remove_hint(struct ast_exten *e)
2078 /* Cleanup the Notifys if hint is removed */
2079 struct ast_hint *hint;
2080 struct ast_state_cb *cblist, *cbprev;
2086 AST_LIST_LOCK(&hints);
2087 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
2088 if (hint->exten == e) {
2090 cblist = hint->callbacks;
2092 /* Notify with -1 and remove all callbacks */
2094 cblist = cblist->next;
2095 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2098 hint->callbacks = NULL;
2099 AST_LIST_REMOVE_CURRENT(&hints, list);
2105 AST_LIST_TRAVERSE_SAFE_END
2106 AST_LIST_UNLOCK(&hints);
2112 /*! \brief ast_get_hint: Get hint for channel */
2113 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2115 struct ast_exten *e = ast_hint_extension(c, context, exten);
2119 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2121 const char *tmp = ast_get_extension_app_data(e);
2123 ast_copy_string(name, tmp, namesize);
2130 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2132 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
2135 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2137 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
2140 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2142 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
2145 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2147 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
2150 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2152 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
2155 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2157 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
2160 /* helper function to set extension and priority */
2161 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
2163 ast_copy_string(c->exten, exten, sizeof(c->exten));
2168 * \brief collect digits from the channel into the buffer,
2169 * return -1 on error, 0 on timeout or done.
2171 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
2175 buf[pos] = '\0'; /* make sure it is properly terminated */
2176 while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
2177 /* As long as we're willing to wait, and as long as it's not defined,
2178 keep reading digits until we can't possibly get a right answer anymore. */
2179 digit = ast_waitfordigit(c, waittime * 1000);
2180 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2183 if (!digit) /* No entry */
2185 if (digit < 0) /* Error, maybe a hangup */
2187 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
2191 waittime = c->pbx->dtimeout;
2197 static int __ast_pbx_run(struct ast_channel *c)
2199 int found = 0; /* set if we find at least one match */
2202 int error = 0; /* set an error conditions */
2204 /* A little initial setup here */
2206 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2207 /* XXX and now what ? */
2210 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2214 c->cdr = ast_cdr_alloc();
2216 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2220 ast_cdr_init(c->cdr, c);
2223 /* Set reasonable defaults */
2224 c->pbx->rtimeout = 10;
2225 c->pbx->dtimeout = 5;
2227 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
2228 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2230 /* Start by trying whatever the channel is set to */
2231 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2232 /* If not successful fall back to 's' */
2233 if (option_verbose > 1)
2234 ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
2235 /* XXX the original code used the existing priority in the call to
2236 * ast_exists_extension(), and reset it to 1 afterwards.
2237 * I believe the correct thing is to set it to 1 immediately.
2239 set_ext_pri(c, "s", 1);
2240 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2241 /* JK02: And finally back to default if everything else failed */
2242 if (option_verbose > 1)
2243 ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
2244 ast_copy_string(c->context, "default", sizeof(c->context));
2247 if (c->cdr && ast_tvzero(c->cdr->start))
2248 ast_cdr_start(c->cdr);
2250 char dst_exten[256]; /* buffer to accumulate digits */
2251 int pos = 0; /* XXX should check bounds */
2254 /* loop on priorities in this context/exten */
2255 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2257 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2258 /* Something bad happened, or a hangup has been requested. */
2259 if (strchr("0123456789ABCDEF*#", res)) {
2260 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2262 dst_exten[pos++] = digit = res;
2263 dst_exten[pos] = '\0';
2266 if (res == AST_PBX_KEEPALIVE) {
2268 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2269 else if (option_verbose > 1)
2270 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2275 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2276 else if (option_verbose > 1)
2277 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2278 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2280 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2281 /* atimeout, nothing bad */
2289 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
2290 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2291 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2292 c->whentohangup = 0;
2293 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2294 } else if (c->_softhangup) {
2295 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2296 c->exten, c->priority);
2301 } /* end while - from here on we can use 'break' to go out */
2305 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2307 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2308 /* If there is no match at priority 1, it is not a valid extension anymore.
2309 * Try to continue at "i", 1 or exit if the latter does not exist.
2311 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2312 if (option_verbose > 2)
2313 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2314 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2315 set_ext_pri(c, "i", 1);
2317 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2318 c->name, c->exten, c->context);
2319 error = 1; /* we know what to do with it */
2322 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2323 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2325 } else { /* keypress received, get more digits for a full extension */
2328 waittime = c->pbx->dtimeout;
2329 else if (!autofallthrough)
2330 waittime = c->pbx->rtimeout;
2332 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2335 if (option_verbose > 2)
2336 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2337 if (!strcasecmp(status, "CONGESTION"))
2338 res = pbx_builtin_congestion(c, "10");
2339 else if (!strcasecmp(status, "CHANUNAVAIL"))
2340 res = pbx_builtin_congestion(c, "10");
2341 else if (!strcasecmp(status, "BUSY"))
2342 res = pbx_builtin_busy(c, "10");
2343 error = 1; /* XXX disable message */
2344 break; /* exit from the 'for' loop */
2347 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
2349 if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
2350 set_ext_pri(c, dst_exten, 1);
2352 /* No such extension */
2353 if (!ast_strlen_zero(dst_exten)) {
2354 /* An invalid extension */
2355 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2356 if (option_verbose > 2)
2357 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
2358 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
2359 set_ext_pri(c, "i", 1);
2361 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
2362 found = 1; /* XXX disable message */
2366 /* A simple timeout */
2367 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2368 if (option_verbose > 2)
2369 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2370 set_ext_pri(c, "t", 1);
2372 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2373 found = 1; /* XXX disable message */
2379 if (option_verbose > 2)
2380 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2385 if (!found && !error)
2386 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2387 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2388 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2389 ast_cdr_end(c->cdr);
2390 set_ext_pri(c, "h", 1);
2391 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2392 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2393 /* Something bad happened, or a hangup has been requested. */
2395 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2396 else if (option_verbose > 1)
2397 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2403 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2405 pbx_destroy(c->pbx);
2407 if (res != AST_PBX_KEEPALIVE)
2412 /* Returns 0 on success, non-zero if call limit was reached */
2413 static int increase_call_count(const struct ast_channel *c)
2417 ast_mutex_lock(&maxcalllock);
2418 if (option_maxcalls) {
2419 if (countcalls >= option_maxcalls) {
2420 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2424 if (option_maxload) {
2425 getloadavg(&curloadavg, 1);
2426 if (curloadavg >= option_maxload) {
2427 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2433 ast_mutex_unlock(&maxcalllock);
2438 static void decrease_call_count(void)
2440 ast_mutex_lock(&maxcalllock);
2443 ast_mutex_unlock(&maxcalllock);
2446 static void destroy_exten(struct ast_exten *e)
2448 if (e->priority == PRIORITY_HINT)
2456 static void *pbx_thread(void *data)
2458 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2459 answer this channel and get it going.
2462 The launcher of this function _MUST_ increment 'countcalls'
2463 before invoking the function; it will be decremented when the
2464 PBX has finished running on the channel
2466 struct ast_channel *c = data;
2469 decrease_call_count();
2476 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2479 pthread_attr_t attr;
2482 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2483 return AST_PBX_FAILED;
2486 if (increase_call_count(c))
2487 return AST_PBX_CALL_LIMIT;
2489 /* Start a new thread, and get something handling this channel. */
2490 pthread_attr_init(&attr);
2491 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2492 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2493 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2494 return AST_PBX_FAILED;
2497 return AST_PBX_SUCCESS;
2500 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2502 enum ast_pbx_result res = AST_PBX_SUCCESS;
2504 if (increase_call_count(c))
2505 return AST_PBX_CALL_LIMIT;
2507 res = __ast_pbx_run(c);
2508 decrease_call_count();
2513 int ast_active_calls(void)
2518 int pbx_set_autofallthrough(int newval)
2520 int oldval = autofallthrough;
2521 autofallthrough = newval;
2525 /* lookup for a context with a given name,
2526 * return with conlock held if found, NULL if not found
2528 static struct ast_context *find_context_locked(const char *context)
2530 struct ast_context *c = NULL;
2532 ast_lock_contexts();
2533 while ( (c = ast_walk_contexts(c)) ) {
2534 if (!strcmp(ast_get_context_name(c), context))
2537 ast_unlock_contexts();
2543 * This function locks contexts list by &conlist, search for the right context
2544 * structure, leave context list locked and call ast_context_remove_include2
2545 * which removes include, unlock contexts list and return ...
2547 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2550 struct ast_context *c = find_context_locked(context);
2553 /* found, remove include from this context ... */
2554 ret = ast_context_remove_include2(c, include, registrar);
2555 ast_unlock_contexts();
2561 * When we call this function, &conlock lock must be locked, because when
2562 * we giving *con argument, some process can remove/change this context
2563 * and after that there can be segfault.
2565 * This function locks given context, removes include, unlock context and
2568 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2570 struct ast_include *i, *pi = NULL;
2573 ast_mutex_lock(&con->lock);
2575 /* find our include */
2576 for (i = con->includes; i; pi = i, i = i->next) {
2577 if (!strcmp(i->name, include) &&
2578 (!registrar || !strcmp(i->registrar, registrar))) {
2579 /* remove from list */
2583 con->includes = i->next;
2584 /* free include and return */
2591 ast_mutex_unlock(&con->lock);
2596 * \note This function locks contexts list by &conlist, search for the rigt context
2597 * structure, leave context list locked and call ast_context_remove_switch2
2598 * which removes switch, unlock contexts list and return ...
2600 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2602 int ret = -1; /* default error return */
2603 struct ast_context *c = find_context_locked(context);
2606 /* remove switch from this context ... */
2607 ret = ast_context_remove_switch2(c, sw, data, registrar);
2608 ast_unlock_contexts();
2614 * \brief This function locks given context, removes switch, unlock context and
2616 * \note When we call this function, &conlock lock must be locked, because when
2617 * we giving *con argument, some process can remove/change this context
2618 * and after that there can be segfault.
2621 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2626 ast_mutex_lock(&con->lock);
2629 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
2630 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2631 (!registrar || !strcmp(i->registrar, registrar))) {
2632 /* found, remove from list */
2633 AST_LIST_REMOVE_CURRENT(&con->alts, list);
2634 free(i); /* free switch and return */
2639 AST_LIST_TRAVERSE_SAFE_END
2641 ast_mutex_unlock(&con->lock);
2647 * \note This functions lock contexts list, search for the right context,
2648 * call ast_context_remove_extension2, unlock contexts list and return.
2649 * In this function we are using
2651 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2653 int ret = -1; /* default error return */
2654 struct ast_context *c = find_context_locked(context);
2656 if (c) { /* ... remove extension ... */
2657 ret = ast_context_remove_extension2(c, extension, priority, registrar);
2658 ast_unlock_contexts();
2664 * \brief This functionc locks given context, search for the right extension and
2665 * fires out all peer in this extensions with given priority. If priority
2666 * is set to 0, all peers are removed. After that, unlock context and
2668 * \note When do you want to call this function, make sure that &conlock is locked,
2669 * because some process can handle with your *con context before you lock
2673 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2675 struct ast_exten *exten, *prev_exten = NULL;
2676 struct ast_exten *peer;
2678 ast_mutex_lock(&con->lock);
2680 /* scan the extension list to find matching extension-registrar */
2681 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
2682 if (!strcmp(exten->exten, extension) &&
2683 (!registrar || !strcmp(exten->registrar, registrar)))
2687 /* we can't find right extension */
2688 ast_mutex_unlock(&con->lock);
2692 /* should we free all peers in this extension? (priority == 0)? */
2693 if (priority == 0) {
2694 /* remove this extension from context list */
2696 prev_exten->next = exten->next;
2698 con->root = exten->next;
2700 /* fire out all peers */
2701 while ( (peer = exten) ) {
2702 exten = peer->peer; /* prepare for next entry */
2703 destroy_exten(peer);
2706 /* scan the priority list to remove extension with exten->priority == priority */
2707 struct ast_exten *previous_peer = NULL;
2709 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
2710 if (peer->priority == priority &&
2711 (!registrar || !strcmp(peer->registrar, registrar) ))
2712 break; /* found our priority */
2714 if (!peer) { /* not found */
2715 ast_mutex_unlock(&con->lock);
2718 /* we are first priority extension? */
2719 if (!previous_peer) {
2721 * We are first in the priority chain, so must update the extension chain.
2722 * The next node is either the next priority or the next extension
2724 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
2726 if (!prev_exten) /* change the root... */
2727 con->root = next_node;
2729 prev_exten->next = next_node; /* unlink */
2730 if (peer->peer) /* XXX update the new head of the pri list */
2731 peer->peer->next = peer->next;
2732 } else { /* easy, we are not first priority in extension */
2733 previous_peer->peer = peer->peer;
2736 /* now, free whole priority extension */
2737 destroy_exten(peer);
2738 /* XXX should we return -1 ? */
2740 ast_mutex_unlock(&con->lock);
2745 /*! \brief Dynamically register a new dial plan application */
2746 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2748 struct ast_app *tmp, *cur = NULL;
2752 AST_LIST_LOCK(&apps);
2753 AST_LIST_TRAVERSE(&apps, tmp, list) {
2754 if (!strcasecmp(app, tmp->name)) {
2755 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2756 AST_LIST_UNLOCK(&apps);
2761 length = sizeof(*tmp) + strlen(app) + 1;
2763 if (!(tmp = ast_calloc(1, length))) {
2764 AST_LIST_UNLOCK(&apps);
2768 strcpy(tmp->name, app);
2769 tmp->execute = execute;
2770 tmp->synopsis = synopsis;
2771 tmp->description = description;
2773 /* Store in alphabetical order */
2774 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
2775 if (strcasecmp(tmp->name, cur->name) < 0) {
2776 AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
2780 AST_LIST_TRAVERSE_SAFE_END
2782 AST_LIST_INSERT_TAIL(&apps, tmp, list);
2784 if (option_verbose > 1)
2785 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2787 AST_LIST_UNLOCK(&apps);
2793 * Append to the list. We don't have a tail pointer because we need
2794 * to scan the list anyways to check for duplicates during insertion.
2796 int ast_register_switch(struct ast_switch *sw)
2798 struct ast_switch *tmp;
2800 AST_LIST_LOCK(&switches);
2801 AST_LIST_TRAVERSE(&switches, tmp, list) {
2802 if (!strcasecmp(tmp->name, sw->name)) {
2803 AST_LIST_UNLOCK(&switches);
2804 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2808 AST_LIST_INSERT_TAIL(&switches, sw, list);
2809 AST_LIST_UNLOCK(&switches);
2814 void ast_unregister_switch(struct ast_switch *sw)
2816 AST_LIST_LOCK(&switches);
2817 AST_LIST_REMOVE(&switches, sw, list);
2818 AST_LIST_UNLOCK(&switches);
2822 * Help for CLI commands ...
2824 static char show_application_help[] =
2825 "Usage: show application <application> [<application> [<application> [...]]]\n"
2826 " Describes a particular application.\n";
2828 static char show_functions_help[] =
2829 "Usage: show functions [like <text>]\n"
2830 " List builtin functions, optionally only those matching a given string\n";
2832 static char show_function_help[] =
2833 "Usage: show function <function>\n"
2834 " Describe a particular dialplan function.\n";
2836 static char show_applications_help[] =
2837 "Usage: show applications [{like|describing} <text>]\n"
2838 " List applications which are currently available.\n"
2839 " If 'like', <text> will be a substring of the app name\n"
2840 " If 'describing', <text> will be a substring of the description\n";
2842 static char show_dialplan_help[] =
2843 "Usage: show dialplan [exten@][context]\n"
2846 static char show_switches_help[] =
2847 "Usage: show switches\n"
2848 " Show registered switches\n";
2850 static char show_hints_help[] =
2851 "Usage: show hints\n"
2852 " Show registered hints\n";
2854 static char show_globals_help[] =
2855 "Usage: show globals\n"
2856 " Show current global dialplan variables and their values\n";
2858 static char set_global_help[] =
2859 "Usage: set global <name> <value>\n"
2860 " Set global dialplan variable <name> to <value>\n";
2864 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2869 * \brief 'show application' CLI command implementation functions ...
2873 * There is a possibility to show informations about more than one
2874 * application at one time. You can type 'show application Dial Echo' and
2875 * you will see informations about these two applications ...
2877 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2882 int wordlen = strlen(word);
2884 /* return the n-th [partial] matching entry */
2885 AST_LIST_LOCK(&apps);
2886 AST_LIST_TRAVERSE(&apps, a, list) {
2887 if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
2888 ret = strdup(a->name);
2892 AST_LIST_UNLOCK(&apps);
2897 static int handle_show_application(int fd, int argc, char *argv[])
2900 int app, no_registered_app = 1;
2903 return RESULT_SHOWUSAGE;
2905 /* ... go through all applications ... */
2906 AST_LIST_LOCK(&apps);
2907 AST_LIST_TRAVERSE(&apps, a, list) {
2908 /* ... compare this application name with all arguments given
2909 * to 'show application' command ... */
2910 for (app = 2; app < argc; app++) {
2911 if (!strcasecmp(a->name, argv[app])) {
2912 /* Maximum number of characters added by terminal coloring is 22 */
2913 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2914 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2915 int synopsis_size, description_size;
2917 no_registered_app = 0;
2920 synopsis_size = strlen(a->synopsis) + 23;
2922 synopsis_size = strlen("Not available") + 23;
2923 synopsis = alloca(synopsis_size);
2926 description_size = strlen(a->description) + 23;
2928 description_size = strlen("Not available") + 23;
2929 description = alloca(description_size);
2931 if (synopsis && description) {
2932 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2933 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2934 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2935 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2936 term_color(synopsis,
2937 a->synopsis ? a->synopsis : "Not available",
2938 COLOR_CYAN, 0, synopsis_size);
2939 term_color(description,
2940 a->description ? a->description : "Not available",
2941 COLOR_CYAN, 0, description_size);
2943 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2945 /* ... one of our applications, show info ...*/
2946 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2947 "[Synopsis]\n %s\n\n"
2948 "[Description]\n%s\n",
2950 a->synopsis ? a->synopsis : "Not available",
2951 a->description ? a->description : "Not available");
2956 AST_LIST_UNLOCK(&apps);
2958 /* we found at least one app? no? */
2959 if (no_registered_app) {
2960 ast_cli(fd, "Your application(s) is (are) not registered\n");
2961 return RESULT_FAILURE;
2964 return RESULT_SUCCESS;
2967 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2968 static int handle_show_hints(int fd, int argc, char *argv[])
2970 struct ast_hint *hint;
2973 struct ast_state_cb *watcher;
2975 if (AST_LIST_EMPTY(&hints)) {
2976 ast_cli(fd, "There are no registered dialplan hints\n");
2977 return RESULT_SUCCESS;
2979 /* ... we have hints ... */
2980 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2981 AST_LIST_LOCK(&hints);
2982 AST_LIST_TRAVERSE(&hints, hint, list) {
2984 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2986 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2987 ast_get_extension_name(hint->exten),
2988 ast_get_context_name(ast_get_extension_context(hint->exten)),
2989 ast_get_extension_app(hint->exten),
2990 ast_extension_state2str(hint->laststate), watchers);
2993 ast_cli(fd, "----------------\n");
2994 ast_cli(fd, "- %d hints registered\n", num);
2995 AST_LIST_UNLOCK(&hints);
2996 return RESULT_SUCCESS;
2999 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
3000 static int handle_show_switches(int fd, int argc, char *argv[])
3002 struct ast_switch *sw;
3004 AST_LIST_LOCK(&switches);
3006 if (AST_LIST_EMPTY(&switches)) {
3007 AST_LIST_UNLOCK(&switches);
3008 ast_cli(fd, "There are no registered alternative switches\n");
3009 return RESULT_SUCCESS;
3012 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
3013 AST_LIST_TRAVERSE(&switches, sw, list)
3014 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3016 AST_LIST_UNLOCK(&switches);
3018 return RESULT_SUCCESS;
3022 * 'show applications' CLI command implementation functions ...
3024 static int handle_show_applications(int fd, int argc, char *argv[])
3027 int like = 0, describing = 0;
3028 int total_match = 0; /* Number of matches in like clause */
3029 int total_apps = 0; /* Number of apps registered */
3031 AST_LIST_LOCK(&apps);
3033 if (AST_LIST_EMPTY(&apps)) {
3034 ast_cli(fd, "There are no registered applications\n");
3035 AST_LIST_UNLOCK(&apps);
3039 /* show applications like <keyword> */
3040 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3042 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3046 /* show applications describing <keyword1> [<keyword2>] [...] */
3047 if ((!like) && (!describing)) {
3048 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3050 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3053 AST_LIST_TRAVERSE(&apps, a, list) {
3057 if (strcasestr(a->name, argv[3])) {
3061 } else if (describing) {
3062 if (a->description) {
3063 /* Match all words on command line */
3066 for (i = 3; i < argc; i++) {
3067 if (!strcasestr(a->description, argv[i])) {
3079 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3082 if ((!like) && (!describing)) {
3083 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3085 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3088 AST_LIST_UNLOCK(&apps);
3090 return RESULT_SUCCESS;
3093 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3095 static char* choices[] = { "like", "describing", NULL };
3097 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
3101 * 'show dialplan' CLI command implementation functions ...
3103 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3106 struct ast_context *c = NULL;
3111 /* we are do completion of [exten@]context on second position only */
3115 ast_lock_contexts();
3117 wordlen = strlen(word);
3119 /* walk through all contexts and return the n-th match */
3120 while ( (c = ast_walk_contexts(c)) ) {
3121 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
3122 ret = ast_strdup(ast_get_context_name(c));
3127 ast_unlock_contexts();
3132 struct dialplan_counters {
3136 int context_existence;
3137 int extension_existence;
3140 /*! \brief helper function to print an extension */
3141 static void print_ext(struct ast_exten *e, char * buf, int buflen)
3143 int prio = ast_get_extension_priority(e);
3144 if (prio == PRIORITY_HINT) {
3145 snprintf(buf, buflen, "hint: %s",
3146 ast_get_extension_app(e));
3148 snprintf(buf, buflen, "%d. %s(%s)",
3149 prio, ast_get_extension_app(e),
3150 (char *)ast_get_extension_app_data(e));
3154 /* XXX not verified */
3155 static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
3157 struct ast_context *c = NULL;
3158 int res = 0, old_total_exten = dpc->total_exten;
3160 ast_lock_contexts();
3162 /* walk all contexts ... */
3163 while ( (c = ast_walk_contexts(c)) ) {
3164 struct ast_exten *e;
3165 struct ast_include *i;
3166 struct ast_ignorepat *ip;
3167 char buf[256], buf2[256];
3168 int context_info_printed = 0;
3170 if (context && strcmp(ast_get_context_name(c), context))
3171 continue; /* skip this one, name doesn't match */
3173 dpc->context_existence = 1;
3175 ast_lock_context(c);
3177 /* are we looking for exten too? if yes, we print context
3178 * only if we find our extension.
3179 * Otherwise print context even if empty ?
3180 * XXX i am not sure how the rinclude is handled.
3181 * I think it ought to go inside.
3184 dpc->total_context++;
3185 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3186 ast_get_context_name(c), ast_get_context_registrar(c));
3187 context_info_printed = 1;
3190 /* walk extensions ... */
3192 while ( (e = ast_walk_context_extensions(c, e)) ) {
3193 struct ast_exten *p;
3195 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
3196 continue; /* skip, extension match failed */
3198 dpc->extension_existence = 1;
3200 /* may we print context info? */
3201 if (!context_info_printed) {
3202 dpc->total_context++;
3203 if (rinclude) { /* TODO Print more info about rinclude */
3204 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3205 ast_get_context_name(c), ast_get_context_registrar(c));
3207 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3208 ast_get_context_name(c), ast_get_context_registrar(c));
3210 context_info_printed = 1;
3214 /* write extension name and first peer */
3215 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
3217 print_ext(e, buf2, sizeof(buf2));
3219 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3220 ast_get_extension_registrar(e));
3223 /* walk next extension peers */
3224 p = e; /* skip the first one, we already got it */
3225 while ( (p = ast_walk_extension_priorities(e, p)) ) {
3226 const char *el = ast_get_extension_label(p);
3229 snprintf(buf, sizeof(buf), " [%s]", el);
3232 print_ext(p, buf2, sizeof(buf2));
3234 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
3235 ast_get_extension_registrar(p));
3239 /* walk included and write info ... */
3241 while ( (i = ast_walk_context_includes(c, i)) ) {
3242 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
3244 /* Check all includes for the requested extension */
3245 if (includecount >= AST_PBX_MAX_STACK) {
3246 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
3250 for (x=0;x<includecount;x++) {
3251 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3257 includes[includecount] = ast_get_include_name(i);
3258 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3260 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3264 ast_cli(fd, " Include => %-45s [%s]\n",
3265 buf, ast_get_include_registrar(i));
3269 /* walk ignore patterns and write info ... */
3271 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
3272 const char *ipname = ast_get_ignorepat_name(ip);
3273 char ignorepat[AST_MAX_EXTENSION];
3274 snprintf(buf, sizeof(buf), "'%s'", ipname);
3275 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3276 if (!exten || ast_extension_match(ignorepat, exten)) {
3277 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3278 buf, ast_get_ignorepat_registrar(ip));
3282 struct ast_sw *sw = NULL;
3283 while ( (sw = ast_walk_context_switches(c, sw)) ) {
3284 snprintf(buf, sizeof(buf), "'%s/%s'",
3285 ast_get_switch_name(sw),
3286 ast_get_switch_data(sw));
3287 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3288 buf, ast_get_switch_registrar(sw));
3292 ast_unlock_context(c);
3294 /* if we print something in context, make an empty line */
3295 if (context_info_printed)
3296 ast_cli(fd, "\r\n");
3298 ast_unlock_contexts();
3300 return (dpc->total_exten == old_total_exten) ? -1 : res;
3303 static int handle_show_dialplan(int fd, int argc, char *argv[])
3305 char *exten = NULL, *context = NULL;
3306 /* Variables used for different counters */
3307 struct dialplan_counters counters;
3309 const char *incstack[AST_PBX_MAX_STACK];
3310 memset(&counters, 0, sizeof(counters));
3312 if (argc != 2 && argc != 3)
3313 return RESULT_SHOWUSAGE;
3315 /* we obtain [exten@]context? if yes, split them ... */
3317 if (strchr(argv[2], '@')) { /* split into exten & context */
3318 context = ast_strdupa(argv[2]);
3319 exten = strsep(&context, "@");
3320 /* change empty strings to NULL */
3321 if (ast_strlen_zero(exten))
3323 } else { /* no '@' char, only context given */
3326 if (ast_strlen_zero(context))
3329 /* else Show complete dial plan, context and exten are NULL */
3330 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3332 /* check for input failure and throw some error messages */
3333 if (context && !counters.context_existence) {
3334 ast_cli(fd, "There is no existence of '%s' context\n", context);
3335 return RESULT_FAILURE;
3338 if (exten && !counters.extension_existence) {
3340 ast_cli(fd, "There is no existence of %s@%s extension\n",
3344 "There is no existence of '%s' extension in all contexts\n",
3346 return RESULT_FAILURE;
3349 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
3350 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
3351 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
3352 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
3355 return RESULT_SUCCESS;
3358 /*! \brief CLI support for listing global variables in a parseable way */
3359 static int handle_show_globals(int fd, int argc, char *argv[])
3362 struct ast_var_t *newvariable;
3364 ast_mutex_lock(&globalslock);
3365 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
3367 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
3369 ast_mutex_unlock(&globalslock);
3370 ast_cli(fd, "\n -- %d variables\n", i);
3372 return RESULT_SUCCESS;
3375 /*! \brief CLI support for setting global variables */
3376 static int handle_set_global(int fd, int argc, char *argv[])
3379 return RESULT_SHOWUSAGE;
3381 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
3382 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
3384 return RESULT_SUCCESS;
3390 * CLI entries for upper commands ...
3392 static struct ast_cli_entry pbx_cli[] = {
3393 { { "show", "applications", NULL }, handle_show_applications,
3394 "Shows registered dialplan applications", show_applications_help, complete_show_applications },
3395 { { "show", "functions", NULL }, handle_show_functions,
3396 "Shows registered dialplan functions", show_functions_help },
3397 { { "show" , "function", NULL }, handle_show_function,
3398 "Describe a specific dialplan function", show_function_help, complete_show_function },
3399 { { "show", "application", NULL }, handle_show_application,
3400 "Describe a specific dialplan application", show_application_help, complete_show_application },
3401 { { "show", "dialplan", NULL }, handle_show_dialplan,
3402 "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
3403 { { "show", "switches", NULL }, handle_show_switches,
3404 "Show alternative switches", show_switches_help },
3405 { { "show", "hints", NULL }, handle_show_hints,
3406 "Show dialplan hints", show_hints_help },
3407 { { "show", "globals", NULL }, handle_show_globals,
3408 "Show global dialplan variables", show_globals_help },
3409 { { "set", "global", NULL }, handle_set_global,
3410 "Set global dialplan variable", set_global_help },
3413 int ast_unregister_application(const char *app)
3415 struct ast_app *tmp;
3417 AST_LIST_LOCK(&apps);
3418 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
3419 if (!strcasecmp(app, tmp->name)) {
3420 AST_LIST_REMOVE_CURRENT(&apps, list);
3421 if (option_verbose > 1)
3422 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3427 AST_LIST_TRAVERSE_SAFE_END
3428 AST_LIST_UNLOCK(&apps);
3430 return tmp ? 0 : -1;
3433 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3435 struct ast_context *tmp, **local_contexts;
3436 int length = sizeof(struct ast_context) + strlen(name) + 1;
3439 ast_mutex_lock(&conlock);
3440 local_contexts = &contexts;
3442 local_contexts = extcontexts;
3444 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
3445 if (!strcasecmp(tmp->name, name)) {
3446 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3448 ast_mutex_unlock(&conlock);
3452 if ((tmp = ast_calloc(1, length))) {
3453 ast_mutex_init(&tmp->lock);
3454 strcpy(tmp->name, name);
3456 tmp->registrar = registrar;
3457 tmp->next = *local_contexts;
3458 tmp->includes = NULL;
3459 tmp->ignorepats = NULL;
3460 *local_contexts = tmp;
3462 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3463 else if (option_verbose > 2)
3464 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3468 ast_mutex_unlock(&conlock);
3472 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3477 struct ast_state_cb *callbacks;
3479 AST_LIST_ENTRY(store_hint) list;
3483 AST_LIST_HEAD(store_hints, store_hint);
3485 /* XXX this does not check that multiple contexts are merged */
3486 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
3488 struct ast_context *tmp, *lasttmp = NULL;
3489 struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
3490 struct store_hint *this;
3491 struct ast_hint *hint;
3492 struct ast_exten *exten;
3494 struct ast_state_cb *thiscb, *prevcb;
3496 /* it is very important that this function hold the hint list lock _and_ the conlock
3497 during its operation; not only do we need to ensure that the list of contexts
3498 and extensions does not change, but also that no hint callbacks (watchers) are
3499 added or removed during the merge/delete process
3501 in addition, the locks _must_ be taken in this order, because there are already
3502 other code paths that use this order
3504 ast_mutex_lock(&conlock);
3505 AST_LIST_LOCK(&hints);
3507 /* preserve all watchers for hints associated with this registrar */
3508 AST_LIST_TRAVERSE(&hints, hint, list) {
3509 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
3510 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
3511 if (!(this = ast_calloc(1, length)))
3513 this->callbacks = hint->callbacks;
3514 hint->callbacks = NULL;
3515 this->laststate = hint->laststate;
3516 this->context = this->data;
3517 strcpy(this->data, hint->exten->parent->name);
3518 this->exten = this->data + strlen(this->context) + 1;
3519 strcpy(this->exten, hint->exten->exten);
3520 AST_LIST_INSERT_HEAD(&store, this, list);
3526 /* XXX remove previous contexts from same registrar */
3527 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
3528 __ast_context_destroy(NULL,registrar);
3534 /* XXX remove contexts with the same name */
3536 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
3537 __ast_context_destroy(tmp,tmp->registrar);
3543 lasttmp->next = contexts;
3544 contexts = *extcontexts;
3545 *extcontexts = NULL;
3547 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3549 /* restore the watchers for hints that can be found; notify those that
3552 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
3553 exten = ast_hint_extension(NULL, this->context, this->exten);
3554 /* Find the hint in the list of hints */
3555 AST_LIST_TRAVERSE(&hints, hint, list) {
3556 if (hint->exten == exten)
3559 if (!exten || !hint) {
3560 /* this hint has been removed, notify the watchers */
3562 thiscb = this->callbacks;
3565 thiscb = thiscb->next;
3566 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
3570 thiscb = this->callbacks;
3571 while (thiscb->next)
3572 thiscb = thiscb->next;
3573 thiscb->next = hint->callbacks;
3574 hint->callbacks = this->callbacks;
3575 hint->laststate = this->laststate;
3580 AST_LIST_UNLOCK(&hints);
3581 ast_mutex_unlock(&conlock);
3588 * EBUSY - can't lock
3589 * ENOENT - no existence of context
3591 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3594 struct ast_context *c = find_context_locked(context);
3597 ret = ast_context_add_include2(c, include, registrar);
3598 ast_unlock_contexts();
3603 /*! \brief Helper for get_range.
3604 * return the index of the matching entry, starting from 1.
3605 * If names is not supplied, try numeric values.
3607 static int lookup_name(const char *s, char *const names[], int max)
3612 for (i = 0; names[i]; i++) {
3613 if (!strcasecmp(s, names[i]))
3616 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
3619 return 0; /* error return */
3622 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3623 * names, if supplied, is an array of names that should be mapped to numbers.
3625 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
3627 int s, e; /* start and ending position */
3628 unsigned int mask = 0;
3630 /* Check for whole range */
3631 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
3635 /* Get start and ending position */
3636 char *c = strchr(src, '-');
3639 /* Find the start */
3640 s = lookup_name(src, names, max);
3642 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
3646 if (c) { /* find end of range */
3647 e = lookup_name(c, names, max);
3649 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
3656 /* Fill the mask. Remember that ranges are cyclic */
3657 mask = 1 << e; /* initialize with last element */