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>
26 #include <sys/types.h>
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40 #include "asterisk/lock.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/options.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/file.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/cdr.h"
49 #include "asterisk/config.h"
50 #include "asterisk/term.h"
51 #include "asterisk/manager.h"
52 #include "asterisk/ast_expr.h"
53 #include "asterisk/linkedlists.h"
54 #define SAY_STUBS /* generate declarations and stubs for say methods */
55 #include "asterisk/say.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/causes.h"
58 #include "asterisk/musiconhold.h"
59 #include "asterisk/app.h"
60 #include "asterisk/devicestate.h"
61 #include "asterisk/compat.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 struct ast_sw *next; /*!< Link them together */
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 struct 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 struct ast_app *next; /*!< Next app in list */
178 char name[0]; /*!< Name of the application */
181 /*! \brief ast_state_cb: An extension state notify register item */
182 struct ast_state_cb {
185 ast_state_cb_type callback;
186 struct ast_state_cb *next;
189 /*! \brief Structure for dial plan hints
191 Hints are pointers from an extension in the dialplan to one or
192 more devices (tech/name) */
194 struct ast_exten *exten; /*!< Extension */
195 int laststate; /*!< Last known state */
196 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
197 AST_LIST_ENTRY(ast_hint) list; /*!< Pointer to next hint in list */
200 static const struct cfextension_states {
202 const char * const text;
203 } extension_states[] = {
204 { AST_EXTENSION_NOT_INUSE, "Idle" },
205 { AST_EXTENSION_INUSE, "InUse" },
206 { AST_EXTENSION_BUSY, "Busy" },
207 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
208 { AST_EXTENSION_RINGING, "Ringing" },
209 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" }
212 int ast_pbx_outgoing_cdr_failed(void);
214 static int pbx_builtin_answer(struct ast_channel *, void *);
215 static int pbx_builtin_goto(struct ast_channel *, void *);
216 static int pbx_builtin_hangup(struct ast_channel *, void *);
217 static int pbx_builtin_background(struct ast_channel *, void *);
218 static int pbx_builtin_wait(struct ast_channel *, void *);
219 static int pbx_builtin_waitexten(struct ast_channel *, void *);
220 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
221 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
222 static int pbx_builtin_ringing(struct ast_channel *, void *);
223 static int pbx_builtin_progress(struct ast_channel *, void *);
224 static int pbx_builtin_congestion(struct ast_channel *, void *);
225 static int pbx_builtin_busy(struct ast_channel *, void *);
226 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
227 static int pbx_builtin_noop(struct ast_channel *, void *);
228 static int pbx_builtin_gotoif(struct ast_channel *, void *);
229 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
230 static int pbx_builtin_execiftime(struct ast_channel *, void *);
231 static int pbx_builtin_saynumber(struct ast_channel *, void *);
232 static int pbx_builtin_saydigits(struct ast_channel *, void *);
233 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
234 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
235 int pbx_builtin_setvar(struct ast_channel *, void *);
236 static int pbx_builtin_importvar(struct ast_channel *, void *);
238 AST_MUTEX_DEFINE_STATIC(globalslock);
239 static struct varshead globals;
241 static int autofallthrough = 0;
243 AST_MUTEX_DEFINE_STATIC(maxcalllock);
244 static int countcalls = 0;
246 AST_MUTEX_DEFINE_STATIC(acflock); /*!< Lock for the custom function list */
247 static struct ast_custom_function *acf_root = NULL;
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 a file while awaiting extension",
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 explicity 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 congenstion\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?[label1]:[label2]): This application will cause the calling\n"
318 "channel to jump to the speicifed location in the dialplan based on the\n"
319 "evaluation of the given condition. The channel will continue at 'label1' if the\n"
320 "condition is true, or 'label2' if the condition is false. The labels are\n"
321 "specified in the same syntax that is used with the Goto application.\n"
324 { "GotoIfTime", pbx_builtin_gotoiftime,
325 "Conditional Goto based on the current time",
326 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
327 "This application will have the calling channel jump to the speicified location\n"
328 "int the dialplan if the current time matches the given time specification.\n"
329 "Further information on the time specification can be found in examples\n"
330 "illustrating how to do time-based context includes in the dialplan.\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. Further\n"
338 "information on the time speicification can be found in examples illustrating\n"
339 "how to do time-based context includes in the dialplan.\n"
342 { "Hangup", pbx_builtin_hangup,
343 "Hang up the calling channel",
344 " Hangup(): This application will hang up the calling channel.\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 channel will set the channel's AMA Flags for billing\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 */
464 static struct ast_app *apps = NULL;
465 AST_MUTEX_DEFINE_STATIC(applock); /*!< Lock for the application list */
467 struct ast_switch *switches = NULL;
468 AST_MUTEX_DEFINE_STATIC(switchlock); /*!< Lock for switches */
470 static int stateid = 1;
471 static AST_LIST_HEAD_STATIC(hints, ast_hint);
472 struct ast_state_cb *statecbs = NULL;
475 \note This function is special. It saves the stack so that no matter
476 how many times it is called, it returns to the same place */
477 int pbx_exec(struct ast_channel *c, /*!< Channel */
478 struct ast_app *app, /*!< Application */
479 void *data, /*!< Data for execution */
480 int newstack) /*!< Force stack increment */
487 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
491 ast_cdr_setapp(c->cdr, app->name, data);
493 /* save channel values */
494 saved_c_appl= c->appl;
495 saved_c_data= c->data;
499 res = execute(c, data);
500 /* restore channel values */
501 c->appl= saved_c_appl;
502 c->data= saved_c_data;
505 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
510 /*! Go no deeper than this through includes (not counting loops) */
511 #define AST_PBX_MAX_STACK 128
513 #define HELPER_EXISTS 0
514 #define HELPER_SPAWN 1
515 #define HELPER_EXEC 2
516 #define HELPER_CANMATCH 3
517 #define HELPER_MATCHMORE 4
518 #define HELPER_FINDLABEL 5
520 /*! \brief Find application handle in linked list
522 struct ast_app *pbx_findapp(const char *app)
526 if (ast_mutex_lock(&applock)) {
527 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
530 for (tmp = apps; tmp; tmp = tmp->next) {
531 if (!strcasecmp(tmp->name, app))
534 ast_mutex_unlock(&applock);
538 static struct ast_switch *pbx_findswitch(const char *sw)
540 struct ast_switch *asw;
542 if (ast_mutex_lock(&switchlock)) {
543 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
546 for (asw = switches; asw; asw = asw->next) {
547 if (!strcasecmp(asw->name, sw))
550 ast_mutex_unlock(&switchlock);
554 static inline int include_valid(struct ast_include *i)
559 return ast_check_timing(&(i->timing));
562 static void pbx_destroy(struct ast_pbx *p)
567 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
568 /* All patterns begin with _ */\
569 if (pattern[0] != '_') \
571 /* Start optimistic */\
574 while(match && *data && *pattern && (*pattern != '/')) {\
575 while (*data == '-' && (*(data+1) != '\0')) data++;\
576 switch(toupper(*pattern)) {\
583 where=strchr(pattern,']');\
585 border=(int)(where-pattern);\
586 if (!where || border > strlen(pattern)) {\
587 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
590 for (i=0; i<border; i++) {\
593 if (pattern[i+1]=='-') {\
594 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
601 if (res==1 || *data==pattern[i]) {\
610 if ((*data < '2') || (*data > '9'))\
614 if ((*data < '0') || (*data > '9'))\
618 if ((*data < '1') || (*data > '9'))\
629 /* Ignore these characters */\
633 if (*data != *pattern)\
639 /* If we ran off the end of the data and the pattern ends in '!', match */\
640 if (match && !*data && (*pattern == '!'))\
644 int ast_extension_match(const char *pattern, const char *data)
647 /* If they're the same return */
648 if (!strcmp(pattern, data))
650 EXTENSION_MATCH_CORE(data,pattern,match);
651 /* Must be at the end of both */
652 if (*data || (*pattern && (*pattern != '/')))
657 int ast_extension_close(const char *pattern, const char *data, int needmore)
660 /* If "data" is longer, it can'be a subset of pattern unless
661 pattern is a pattern match */
662 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
665 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
666 (!needmore || (strlen(pattern) > strlen(data)))) {
669 EXTENSION_MATCH_CORE(data,pattern,match);
670 /* If there's more or we don't care about more, or if it's a possible early match,
671 return non-zero; otherwise it's a miss */
672 if (!needmore || *pattern || match == 2) {
678 struct ast_context *ast_context_find(const char *name)
680 struct ast_context *tmp;
681 ast_mutex_lock(&conlock);
683 for (tmp = contexts; tmp; tmp = tmp->next) {
684 if (!strcasecmp(name, tmp->name))
689 ast_mutex_unlock(&conlock);
693 #define STATUS_NO_CONTEXT 1
694 #define STATUS_NO_EXTENSION 2
695 #define STATUS_NO_PRIORITY 3
696 #define STATUS_NO_LABEL 4
697 #define STATUS_SUCCESS 5
699 static int matchcid(const char *cidpattern, const char *callerid)
703 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
704 failing to get a number should count as a match, otherwise not */
706 if (!ast_strlen_zero(cidpattern))
714 return ast_extension_match(cidpattern, callerid);
717 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data, const char **foundcontext)
720 struct ast_context *tmp;
721 struct ast_exten *e, *eroot;
722 struct ast_include *i;
724 struct ast_switch *asw;
726 /* Initialize status if appropriate */
728 *status = STATUS_NO_CONTEXT;
732 /* Check for stack overflow */
733 if (*stacklen >= AST_PBX_MAX_STACK) {
734 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
737 /* Check first to see if we've already been checked */
738 for (x = 0; x < *stacklen; x++) {
739 if (!strcasecmp(incstack[x], context))
746 for (; tmp; tmp = tmp->next) {
748 if (bypass || !strcmp(tmp->name, context)) {
749 struct ast_exten *earlymatch = NULL;
751 if (*status < STATUS_NO_EXTENSION)
752 *status = STATUS_NO_EXTENSION;
753 for (eroot = tmp->root; eroot; eroot = eroot->next) {
755 /* Match extension */
756 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
757 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
758 ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
759 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
761 if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
762 /* It matched an extension ending in a '!' wildcard
763 So ignore it for now, unless there's a better match */
766 if (*status < STATUS_NO_PRIORITY)
767 *status = STATUS_NO_PRIORITY;
768 for (e = eroot; e; e = e->peer) {
770 if (action == HELPER_FINDLABEL) {
771 if (*status < STATUS_NO_LABEL)
772 *status = STATUS_NO_LABEL;
773 if (label && e->label && !strcmp(label, e->label)) {
774 *status = STATUS_SUCCESS;
775 *foundcontext = context;
778 } else if (e->priority == priority) {
779 *status = STATUS_SUCCESS;
780 *foundcontext = context;
788 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
789 of the loop waiting for more digits, and _then_ match (normally)
790 the extension we ended up with. We got an early-matching wildcard
791 pattern, so return NULL to break out of the loop. */
794 /* Check alternative switches */
795 for (sw = tmp->alts; sw; sw = sw->next) {
796 if ((asw = pbx_findswitch(sw->name))) {
797 /* Substitute variables now */
799 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
800 if (action == HELPER_CANMATCH)
801 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
802 else if (action == HELPER_MATCHMORE)
803 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
805 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
809 *data = sw->eval ? sw->tmpdata : sw->data;
810 *foundcontext = context;
814 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
817 /* Setup the stack */
818 incstack[*stacklen] = tmp->name;
820 /* Now try any includes we have in this context */
821 for (i = tmp->includes; i; i = i->next) {
822 if (include_valid(i)) {
823 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
835 /* Note that it's negative -- that's important later. */
836 #define DONT_HAVE_LENGTH 0x80000000
838 /*! \brief extract offset:length from variable name.
839 * Returns 1 if there is a offset:length part, which is
840 * trimmed off (values go into variables)
842 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
847 *length = DONT_HAVE_LENGTH;
849 for (; *var; var++) {
853 } else if (*var == ')') {
855 } else if (*var == ':' && parens == 0) {
857 sscanf(var, "%d:%d", offset, length);
858 return 1; /* offset:length valid */
864 /*! \brief takes a substring. It is ok to call with value == workspace.
866 * offset < 0 means start from the end of the string and set the beginning
867 * to be that many characters back.
868 * length is the length of the substring, -1 means unlimited
869 * (we take any negative value).
870 * Always return a copy in workspace.
872 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
874 char *ret = workspace;
875 int lr; /* length of the input string after the copy */
877 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
879 if (offset == 0 && length < 0) /* take the whole string */
882 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
884 if (offset < 0) { /* translate negative offset into positive ones */
885 offset = lr + offset;
886 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
890 /* too large offset result in empty string so we know what to return */
892 return ret + lr; /* the final '\0' */
894 ret += offset; /* move to the start position */
895 if (length >= 0 && length < lr - offset) /* truncate if necessary */
901 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
902 functions in the dialplan
904 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
906 const char not_found = '\0';
908 const char *s; /* the result */
910 int i, need_substring;
911 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
914 places[0] = &c->varshead;
917 * Make a copy of var because parse_variable_name() modifies the string.
918 * Then if called directly, we might need to run substring() on the result;
919 * remember this for later in 'need_substring', 'offset' and 'length'
921 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
922 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
925 * Look first into predefined variables, then into variable lists.
926 * Variable 's' points to the result, according to the following rules:
927 * s == ¬_found (set at the beginning) means that we did not find a
928 * matching variable and need to look into more places.
929 * If s != ¬_found, s is a valid result string as follows:
930 * s = NULL if the variable does not have a value;
931 * you typically do this when looking for an unset predefined variable.
932 * s = workspace if the result has been assembled there;
933 * typically done when the result is built e.g. with an snprintf(),
934 * so we don't need to do an additional copy.
935 * s != workspace in case we have a string, that needs to be copied
936 * (the ast_copy_string is done once for all at the end).
937 * Typically done when the result is already available in some string.
939 s = ¬_found; /* default value */
940 if (c) { /* This group requires a valid channel */
941 /* Names with common parts are looked up a piece at a time using strncmp. */
942 if (!strncmp(var, "CALL", 4)) {
943 if (!strncmp(var + 4, "ING", 3)) {
944 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
945 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
947 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
948 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
950 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
951 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
953 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
954 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
958 } else if (!strcmp(var, "HINT")) {
959 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
960 } else if (!strcmp(var, "HINTNAME")) {
961 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
962 } else if (!strcmp(var, "EXTEN")) {
964 } else if (!strcmp(var, "CONTEXT")) {
966 } else if (!strcmp(var, "PRIORITY")) {
967 snprintf(workspace, workspacelen, "%d", c->priority);
969 } else if (!strcmp(var, "CHANNEL")) {
971 } else if (!strcmp(var, "UNIQUEID")) {
973 } else if (!strcmp(var, "HANGUPCAUSE")) {
974 snprintf(workspace, workspacelen, "%d", c->hangupcause);
978 if (s == ¬_found) { /* look for more */
979 if (!strcmp(var, "EPOCH")) {
980 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
982 } else if (!strcmp(var, "SYSTEMNAME")) {
983 s = ast_config_AST_SYSTEM_NAME;
986 /* if not found, look into chanvars or global vars */
987 for (i = 0; s == ¬_found && i < (sizeof(places) / sizeof(places[0])); i++) {
988 struct ast_var_t *variables;
991 if (places[i] == &globals)
992 ast_mutex_lock(&globalslock);
993 AST_LIST_TRAVERSE(places[i], variables, entries) {
994 if (strcasecmp(ast_var_name(variables), var)==0) {
995 s = ast_var_value(variables);
999 if (places[i] == &globals)
1000 ast_mutex_unlock(&globalslock);
1002 if (s == ¬_found || s == NULL)
1006 ast_copy_string(workspace, s, workspacelen);
1009 *ret = substring(*ret, offset, length, workspace, workspacelen);
1013 /*! \brief CLI function to show installed custom functions
1014 \addtogroup CLI_functions
1016 static int handle_show_functions(int fd, int argc, char *argv[])
1018 struct ast_custom_function *acf;
1023 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1025 } else if (argc != 2) {
1026 return RESULT_SHOWUSAGE;
1029 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1031 for (acf = acf_root ; acf; acf = acf->next) {
1034 if (strstr(acf->name, argv[3])) {
1044 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1048 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1053 static int handle_show_function(int fd, int argc, char *argv[])
1055 struct ast_custom_function *acf;
1056 /* Maximum number of characters added by terminal coloring is 22 */
1057 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1058 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1059 char stxtitle[40], *syntax = NULL;
1060 int synopsis_size, description_size, syntax_size;
1062 if (argc < 3) return RESULT_SHOWUSAGE;
1064 if (!(acf = ast_custom_function_find(argv[2]))) {
1065 ast_cli(fd, "No function by that name registered.\n");
1066 return RESULT_FAILURE;
1071 synopsis_size = strlen(acf->synopsis) + 23;
1073 synopsis_size = strlen("Not available") + 23;
1074 synopsis = alloca(synopsis_size);
1077 description_size = strlen(acf->desc) + 23;
1079 description_size = strlen("Not available") + 23;
1080 description = alloca(description_size);
1083 syntax_size = strlen(acf->syntax) + 23;
1085 syntax_size = strlen("Not available") + 23;
1086 syntax = alloca(syntax_size);
1088 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1089 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1090 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1091 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1092 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1094 acf->syntax ? acf->syntax : "Not available",
1095 COLOR_CYAN, 0, syntax_size);
1096 term_color(synopsis,
1097 acf->synopsis ? acf->synopsis : "Not available",
1098 COLOR_CYAN, 0, synopsis_size);
1099 term_color(description,
1100 acf->desc ? acf->desc : "Not available",
1101 COLOR_CYAN, 0, description_size);
1103 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1105 return RESULT_SUCCESS;
1108 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1110 struct ast_custom_function *acf;
1113 int wordlen = strlen(word);
1115 /* try to lock functions list ... */
1116 if (ast_mutex_lock(&acflock)) {
1117 ast_log(LOG_ERROR, "Unable to lock function list\n");
1121 /* case-insensitive for convenience in this 'complete' function */
1122 for (acf = acf_root; acf && !ret; acf = acf->next) {
1123 if (!strncasecmp(word, acf->name, wordlen) && ++which > state)
1124 ret = strdup(acf->name);
1127 ast_mutex_unlock(&acflock);
1132 struct ast_custom_function* ast_custom_function_find(const char *name)
1134 struct ast_custom_function *acfptr;
1136 /* try to lock functions list ... */
1137 if (ast_mutex_lock(&acflock)) {
1138 ast_log(LOG_ERROR, "Unable to lock function list\n");
1142 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1143 if (!strcmp(name, acfptr->name))
1147 ast_mutex_unlock(&acflock);
1152 int ast_custom_function_unregister(struct ast_custom_function *acf)
1154 struct ast_custom_function *acfptr, *lastacf = NULL;
1160 /* try to lock functions list ... */
1161 if (ast_mutex_lock(&acflock)) {
1162 ast_log(LOG_ERROR, "Unable to lock function list\n");
1166 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1167 if (acfptr == acf) {
1169 lastacf->next = acf->next;
1171 acf_root = acf->next;
1179 ast_mutex_unlock(&acflock);
1181 if (!res && (option_verbose > 1))
1182 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1187 int ast_custom_function_register(struct ast_custom_function *acf)
1189 struct ast_custom_function *cur, *last = NULL;
1195 /* try to lock functions list ... */
1196 if (ast_mutex_lock(&acflock)) {
1197 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
1201 if (ast_custom_function_find(acf->name)) {
1202 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1203 ast_mutex_unlock(&acflock);
1207 for (cur = acf_root; cur; cur = cur->next) {
1208 if (strcmp(acf->name, cur->name) < 0) {
1214 acf->next = acf_root;
1222 /* Wasn't before anything else, put it at the end */
1231 ast_mutex_unlock(&acflock);
1233 if (option_verbose > 1)
1234 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1239 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1241 char *args = NULL, *p;
1242 struct ast_custom_function *acfptr;
1244 if ((args = strchr(function, '('))) {
1246 if ((p = strrchr(args, ')')))
1249 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1251 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1254 if ((acfptr = ast_custom_function_find(function))) {
1255 /* run the custom function */
1257 return acfptr->read(chan, function, args, workspace, len);
1259 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1261 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1267 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1269 char *args = NULL, *p;
1270 struct ast_custom_function *acfptr;
1272 if ((args = strchr(function, '('))) {
1274 if ((p = strrchr(args, ')')))
1277 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1279 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1282 if ((acfptr = ast_custom_function_find(function))) {
1283 /* run the custom function */
1285 return acfptr->write(chan, function, args, value);
1287 ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
1289 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1295 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1298 const char *tmp, *whereweare;
1299 int length, offset, offset2, isfunction;
1300 char *workspace = NULL;
1301 char *ltmp = NULL, *var = NULL;
1302 char *nextvar, *nextexp, *nextthing;
1304 int pos, brackets, needsub, len;
1306 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1309 while(!ast_strlen_zero(whereweare) && count) {
1310 /* Assume we're copying the whole remaining string */
1311 pos = strlen(whereweare);
1314 nextthing = strchr(whereweare, '$');
1316 switch(nextthing[1]) {
1318 nextvar = nextthing;
1319 pos = nextvar - whereweare;
1322 nextexp = nextthing;
1323 pos = nextexp - whereweare;
1329 /* Can't copy more than 'count' bytes */
1333 /* Copy that many bytes */
1334 memcpy(cp2, whereweare, pos);
1342 /* We have a variable. Find the start and end, and determine
1343 if we are going to have to recursively call ourselves on the
1345 vars = vare = nextvar + 2;
1349 /* Find the end of it */
1350 while(brackets && *vare) {
1351 if ((vare[0] == '$') && (vare[1] == '{')) {
1354 } else if (vare[0] == '}') {
1356 } else if ((vare[0] == '$') && (vare[1] == '['))
1361 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1362 len = vare - vars - 1;
1364 /* Skip totally over variable string */
1365 whereweare += (len + 3);
1368 var = alloca(VAR_BUF_SIZE);
1370 /* Store variable name (and truncate) */
1371 ast_copy_string(var, vars, len + 1);
1373 /* Substitute if necessary */
1376 ltmp = alloca(VAR_BUF_SIZE);
1378 memset(ltmp, 0, VAR_BUF_SIZE);
1379 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1386 workspace = alloca(VAR_BUF_SIZE);
1388 workspace[0] = '\0';
1390 parse_variable_name(vars, &offset, &offset2, &isfunction);
1392 /* Evaluate function */
1393 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1395 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1397 /* Retrieve variable value */
1398 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1401 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1403 length = strlen(cp4);
1406 memcpy(cp2, cp4, length);
1410 } else if (nextexp) {
1411 /* We have an expression. Find the start and end, and determine
1412 if we are going to have to recursively call ourselves on the
1414 vars = vare = nextexp + 2;
1418 /* Find the end of it */
1419 while(brackets && *vare) {
1420 if ((vare[0] == '$') && (vare[1] == '[')) {
1424 } else if (vare[0] == '[') {
1426 } else if (vare[0] == ']') {
1428 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1435 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1436 len = vare - vars - 1;
1438 /* Skip totally over expression */
1439 whereweare += (len + 3);
1442 var = alloca(VAR_BUF_SIZE);
1444 /* Store variable name (and truncate) */
1445 ast_copy_string(var, vars, len + 1);
1447 /* Substitute if necessary */
1450 ltmp = alloca(VAR_BUF_SIZE);
1452 memset(ltmp, 0, VAR_BUF_SIZE);
1453 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1459 length = ast_expr(vars, cp2, count);
1462 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1471 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1473 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1476 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1478 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1481 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1483 memset(passdata, 0, datalen);
1485 /* No variables or expressions in e->data, so why scan it? */
1486 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1487 ast_copy_string(passdata, e->data, datalen);
1491 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1494 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
1496 struct ast_exten *e;
1497 struct ast_app *app;
1498 struct ast_switch *sw;
1500 const char *foundcontext=NULL;
1504 char *incstack[AST_PBX_MAX_STACK];
1505 char passdata[EXT_DATA_SIZE];
1509 char tmp3[EXT_DATA_SIZE];
1511 char atmp2[EXT_DATA_SIZE+100];
1513 if (ast_mutex_lock(&conlock)) {
1514 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1515 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1520 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1523 case HELPER_CANMATCH:
1524 ast_mutex_unlock(&conlock);
1527 ast_mutex_unlock(&conlock);
1529 case HELPER_FINDLABEL:
1531 ast_mutex_unlock(&conlock);
1533 case HELPER_MATCHMORE:
1534 ast_mutex_unlock(&conlock);
1540 app = pbx_findapp(e->app);
1541 ast_mutex_unlock(&conlock);
1543 if (c->context != context)
1544 ast_copy_string(c->context, context, sizeof(c->context));
1545 if (c->exten != exten)
1546 ast_copy_string(c->exten, exten, sizeof(c->exten));
1547 c->priority = priority;
1548 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1550 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1551 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1552 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, passdata, (newstack ? "in new stack" : "in same stack"));
1553 pbx_builtin_setvar_helper(c, atmp, atmp2);
1555 if (option_verbose > 2)
1556 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1557 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1558 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1559 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1560 (newstack ? "in new stack" : "in same stack"));
1561 manager_event(EVENT_FLAG_CALL, "Newexten",
1566 "Application: %s\r\n"
1569 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1570 res = pbx_exec(c, app, passdata, newstack);
1573 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1577 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1582 case HELPER_CANMATCH:
1583 ast_mutex_unlock(&conlock);
1586 ast_mutex_unlock(&conlock);
1588 case HELPER_MATCHMORE:
1589 ast_mutex_unlock(&conlock);
1591 case HELPER_FINDLABEL:
1592 ast_mutex_unlock(&conlock);
1598 ast_mutex_unlock(&conlock);
1600 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1602 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1607 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1611 ast_mutex_unlock(&conlock);
1613 case STATUS_NO_CONTEXT:
1614 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1615 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1617 case STATUS_NO_EXTENSION:
1618 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1619 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1621 case STATUS_NO_PRIORITY:
1622 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1623 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1625 case STATUS_NO_LABEL:
1627 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1630 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1633 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1641 /*! \brief ast_hint_extension: Find hint for given extension in context */
1642 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1644 struct ast_exten *e;
1645 struct ast_switch *sw;
1647 const char *foundcontext = NULL;
1649 char *incstack[AST_PBX_MAX_STACK];
1652 if (ast_mutex_lock(&conlock)) {
1653 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1656 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1657 ast_mutex_unlock(&conlock);
1661 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1662 static int ast_extension_state2(struct ast_exten *e)
1664 char hint[AST_MAX_EXTENSION] = "";
1667 int allunavailable = 1, allbusy = 1, allfree = 1;
1668 int busy = 0, inuse = 0, ring = 0;
1673 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1675 cur = hint; /* On or more devices separated with a & character */
1677 rest = strchr(cur, '&');
1683 res = ast_device_state(cur);
1685 case AST_DEVICE_NOT_INUSE:
1689 case AST_DEVICE_INUSE:
1694 case AST_DEVICE_RINGING:
1699 case AST_DEVICE_BUSY:
1704 case AST_DEVICE_UNAVAILABLE:
1705 case AST_DEVICE_INVALID:
1718 return AST_EXTENSION_RINGING;
1720 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1722 return AST_EXTENSION_INUSE;
1724 return AST_EXTENSION_NOT_INUSE;
1726 return AST_EXTENSION_BUSY;
1728 return AST_EXTENSION_UNAVAILABLE;
1730 return AST_EXTENSION_INUSE;
1732 return AST_EXTENSION_NOT_INUSE;
1735 /*! \brief ast_extension_state2str: Return extension_state as string */
1736 const char *ast_extension_state2str(int extension_state)
1740 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1741 if (extension_states[i].extension_state == extension_state) {
1742 return extension_states[i].text;
1748 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1749 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1751 struct ast_exten *e;
1753 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1755 return -1; /* No hint, return -1 */
1757 return ast_extension_state2(e); /* Check all devices in the hint */
1760 void ast_hint_state_changed(const char *device)
1762 struct ast_hint *hint;
1763 struct ast_state_cb *cblist;
1764 char buf[AST_MAX_EXTENSION];
1769 AST_LIST_LOCK(&hints);
1771 AST_LIST_TRAVERSE(&hints, hint, list) {
1772 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1774 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1775 if (strcasecmp(cur, device))
1778 /* Get device state for this hint */
1779 state = ast_extension_state2(hint->exten);
1781 if ((state == -1) || (state == hint->laststate))
1784 /* Device state changed since last check - notify the watchers */
1786 /* For general callbacks */
1787 for (cblist = statecbs; cblist; cblist = cblist->next)
1788 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1790 /* For extension callbacks */
1791 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1792 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1794 hint->laststate = state;
1799 AST_LIST_UNLOCK(&hints);
1802 /*! \brief ast_extension_state_add: Add watcher for extension states */
1803 int ast_extension_state_add(const char *context, const char *exten,
1804 ast_state_cb_type callback, void *data)
1806 struct ast_hint *hint;
1807 struct ast_state_cb *cblist;
1808 struct ast_exten *e;
1810 /* If there's no context and extension: add callback to statecbs list */
1811 if (!context && !exten) {
1812 AST_LIST_LOCK(&hints);
1814 for (cblist = statecbs; cblist; cblist = cblist->next) {
1815 if (cblist->callback == callback) {
1816 cblist->data = data;
1817 AST_LIST_UNLOCK(&hints);
1822 /* Now insert the callback */
1823 cblist = calloc(1, sizeof(struct ast_state_cb));
1825 AST_LIST_UNLOCK(&hints);
1829 cblist->callback = callback;
1830 cblist->data = data;
1832 cblist->next = statecbs;
1835 AST_LIST_UNLOCK(&hints);
1839 if (!context || !exten)
1842 /* This callback type is for only one hint, so get the hint */
1843 e = ast_hint_extension(NULL, context, exten);
1848 /* Find the hint in the list of hints */
1849 AST_LIST_LOCK(&hints);
1851 AST_LIST_TRAVERSE(&hints, hint, list) {
1852 if (hint->exten == e)
1857 /* We have no hint, sorry */
1858 AST_LIST_UNLOCK(&hints);
1862 /* Now insert the callback in the callback list */
1863 cblist = calloc(1, sizeof(struct ast_state_cb));
1865 AST_LIST_UNLOCK(&hints);
1868 cblist->id = stateid++; /* Unique ID for this callback */
1869 cblist->callback = callback; /* Pointer to callback routine */
1870 cblist->data = data; /* Data for the callback */
1872 cblist->next = hint->callbacks;
1873 hint->callbacks = cblist;
1875 AST_LIST_UNLOCK(&hints);
1879 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1880 int ast_extension_state_del(int id, ast_state_cb_type callback)
1882 struct ast_hint *hint;
1883 struct ast_state_cb *cblist, *cbprev;
1885 if (!id && !callback)
1888 AST_LIST_LOCK(&hints);
1890 /* id is zero is a callback without extension */
1893 for (cblist = statecbs; cblist; cblist = cblist->next) {
1894 if (cblist->callback == callback) {
1896 statecbs = cblist->next;
1898 cbprev->next = cblist->next;
1902 AST_LIST_UNLOCK(&hints);
1908 AST_LIST_UNLOCK(&hints);
1912 /* id greater than zero is a callback with extension */
1913 /* Find the callback based on ID */
1914 AST_LIST_TRAVERSE(&hints, hint, list) {
1916 for (cblist = hint->callbacks; cblist; cblist = cblist->next) {
1917 if (cblist->id==id) {
1919 hint->callbacks = cblist->next;
1921 cbprev->next = cblist->next;
1925 AST_LIST_UNLOCK(&hints);
1932 AST_LIST_UNLOCK(&hints);
1936 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
1937 static int ast_add_hint(struct ast_exten *e)
1939 struct ast_hint *hint;
1944 AST_LIST_LOCK(&hints);
1946 /* Search if hint exists, do nothing */
1947 AST_LIST_TRAVERSE(&hints, hint, list) {
1948 if (hint->exten == e) {
1949 AST_LIST_UNLOCK(&hints);
1950 if (option_debug > 1)
1951 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1956 if (option_debug > 1)
1957 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1959 hint = calloc(1, sizeof(struct ast_hint));
1961 AST_LIST_UNLOCK(&hints);
1962 if (option_debug > 1)
1963 ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
1966 /* Initialize and insert new item at the top */
1968 hint->laststate = ast_extension_state2(e);
1969 AST_LIST_INSERT_HEAD(&hints, hint, list);
1971 AST_LIST_UNLOCK(&hints);
1975 /*! \brief ast_change_hint: Change hint for an extension */
1976 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1978 struct ast_hint *hint;
1981 AST_LIST_LOCK(&hints);
1982 AST_LIST_TRAVERSE(&hints, hint, list) {
1983 if (hint->exten == oe) {
1989 AST_LIST_UNLOCK(&hints);
1994 /*! \brief ast_remove_hint: Remove hint from extension */
1995 static int ast_remove_hint(struct ast_exten *e)
1997 /* Cleanup the Notifys if hint is removed */
1998 struct ast_hint *hint;
1999 struct ast_state_cb *cblist, *cbprev;
2005 AST_LIST_LOCK(&hints);
2006 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
2007 if (hint->exten == e) {
2009 cblist = hint->callbacks;
2011 /* Notify with -1 and remove all callbacks */
2013 cblist = cblist->next;
2014 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2017 hint->callbacks = NULL;
2018 AST_LIST_REMOVE_CURRENT(&hints, list);
2024 AST_LIST_TRAVERSE_SAFE_END
2025 AST_LIST_UNLOCK(&hints);
2031 /*! \brief ast_get_hint: Get hint for channel */
2032 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2034 struct ast_exten *e;
2037 e = ast_hint_extension(c, context, exten);
2040 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2042 tmp = ast_get_extension_app_data(e);
2044 ast_copy_string(name, (char *) tmp, namesize);
2051 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2053 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2056 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2058 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2061 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2063 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2066 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2068 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2071 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2073 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2076 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2078 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2081 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2083 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2086 static int __ast_pbx_run(struct ast_channel *c)
2096 /* A little initial setup here */
2098 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2099 c->pbx = calloc(1, sizeof(struct ast_pbx));
2101 ast_log(LOG_ERROR, "Out of memory\n");
2106 c->cdr = ast_cdr_alloc();
2108 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2112 ast_cdr_init(c->cdr, c);
2115 /* Set reasonable defaults */
2116 c->pbx->rtimeout = 10;
2117 c->pbx->dtimeout = 5;
2119 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2120 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2122 /* Start by trying whatever the channel is set to */
2123 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2124 /* If not successful fall back to 's' */
2125 if (option_verbose > 1)
2126 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);
2127 ast_copy_string(c->exten, "s", sizeof(c->exten));
2128 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2129 /* JK02: And finally back to default if everything else failed */
2130 if (option_verbose > 1)
2131 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);
2132 ast_copy_string(c->context, "default", sizeof(c->context));
2136 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2137 ast_cdr_start(c->cdr);
2141 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2142 memset(exten, 0, sizeof(exten));
2143 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2144 /* Something bad happened, or a hangup has been requested. */
2145 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2146 (res == '*') || (res == '#')) {
2147 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2148 memset(exten, 0, sizeof(exten));
2150 exten[pos++] = digit = res;
2154 case AST_PBX_KEEPALIVE:
2156 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2157 else if (option_verbose > 1)
2158 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2163 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2164 else if (option_verbose > 1)
2165 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2166 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2171 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2181 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2182 ast_copy_string(c->exten, "T", sizeof(c->exten));
2183 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2184 c->whentohangup = 0;
2186 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2187 } else if (c->_softhangup) {
2188 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2189 c->exten, c->priority);
2195 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2196 /* It's not a valid extension anymore */
2197 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2198 if (option_verbose > 2)
2199 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2200 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2201 ast_copy_string(c->exten, "i", sizeof(c->exten));
2204 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2205 c->name, c->exten, c->context);
2208 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2209 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2212 /* Done, wait for an extension */
2215 waittime = c->pbx->dtimeout;
2216 else if (!autofallthrough)
2217 waittime = c->pbx->rtimeout;
2219 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2220 /* As long as we're willing to wait, and as long as it's not defined,
2221 keep reading digits until we can't possibly get a right answer anymore. */
2222 digit = ast_waitfordigit(c, waittime * 1000);
2223 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2230 /* Error, maybe a hangup */
2232 exten[pos++] = digit;
2233 waittime = c->pbx->dtimeout;
2236 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2237 /* Prepare the next cycle */
2238 ast_copy_string(c->exten, exten, sizeof(c->exten));
2241 /* No such extension */
2242 if (!ast_strlen_zero(exten)) {
2243 /* An invalid extension */
2244 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2245 if (option_verbose > 2)
2246 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2247 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2248 ast_copy_string(c->exten, "i", sizeof(c->exten));
2251 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2255 /* A simple timeout */
2256 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2257 if (option_verbose > 2)
2258 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2259 ast_copy_string(c->exten, "t", sizeof(c->exten));
2262 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2268 if (option_verbose > 2)
2269 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2275 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2278 if (option_verbose > 2)
2279 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2280 if (!strcasecmp(status, "CONGESTION"))
2281 res = pbx_builtin_congestion(c, "10");
2282 else if (!strcasecmp(status, "CHANUNAVAIL"))
2283 res = pbx_builtin_congestion(c, "10");
2284 else if (!strcasecmp(status, "BUSY"))
2285 res = pbx_builtin_busy(c, "10");
2291 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2293 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2294 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2295 ast_cdr_end(c->cdr);
2299 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2300 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2301 /* Something bad happened, or a hangup has been requested. */
2303 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2304 else if (option_verbose > 1)
2305 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2311 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2313 pbx_destroy(c->pbx);
2315 if (res != AST_PBX_KEEPALIVE)
2320 /* Returns 0 on success, non-zero if call limit was reached */
2321 static int increase_call_count(const struct ast_channel *c)
2325 ast_mutex_lock(&maxcalllock);
2326 if (option_maxcalls) {
2327 if (countcalls >= option_maxcalls) {
2328 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2332 if (option_maxload) {
2333 getloadavg(&curloadavg, 1);
2334 if (curloadavg >= option_maxload) {
2335 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2341 ast_mutex_unlock(&maxcalllock);
2346 static void decrease_call_count(void)
2348 ast_mutex_lock(&maxcalllock);
2351 ast_mutex_unlock(&maxcalllock);
2354 static void *pbx_thread(void *data)
2356 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2357 answer this channel and get it going.
2360 The launcher of this function _MUST_ increment 'countcalls'
2361 before invoking the function; it will be decremented when the
2362 PBX has finished running on the channel
2364 struct ast_channel *c = data;
2367 decrease_call_count();
2374 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2377 pthread_attr_t attr;
2380 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2381 return AST_PBX_FAILED;
2384 if (increase_call_count(c))
2385 return AST_PBX_CALL_LIMIT;
2387 /* Start a new thread, and get something handling this channel. */
2388 pthread_attr_init(&attr);
2389 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2390 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2391 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2392 return AST_PBX_FAILED;
2395 return AST_PBX_SUCCESS;
2398 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2400 enum ast_pbx_result res = AST_PBX_SUCCESS;
2402 if (increase_call_count(c))
2403 return AST_PBX_CALL_LIMIT;
2405 res = __ast_pbx_run(c);
2406 decrease_call_count();
2411 int ast_active_calls(void)
2416 int pbx_set_autofallthrough(int newval)
2419 oldval = autofallthrough;
2420 if (oldval != newval)
2421 autofallthrough = newval;
2426 * This function locks contexts list by &conlist, search for the right context
2427 * structure, leave context list locked and call ast_context_remove_include2
2428 * which removes include, unlock contexts list and return ...
2430 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2432 struct ast_context *c = NULL;
2434 if (ast_lock_contexts())
2437 /* walk contexts and search for the right one ...*/
2438 while ( (c = ast_walk_contexts(c)) ) {
2439 /* we found one ... */
2440 if (!strcmp(ast_get_context_name(c), context)) {
2442 /* remove include from this context ... */
2443 ret = ast_context_remove_include2(c, include, registrar);
2445 ast_unlock_contexts();
2447 /* ... return results */
2452 /* we can't find the right one context */
2453 ast_unlock_contexts();
2458 * When we call this function, &conlock lock must be locked, because when
2459 * we giving *con argument, some process can remove/change this context
2460 * and after that there can be segfault.
2462 * This function locks given context, removes include, unlock context and
2465 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2467 struct ast_include *i, *pi = NULL;
2469 if (ast_mutex_lock(&con->lock)) return -1;
2472 for (i = con->includes; i; i = i->next) {
2473 /* find our include */
2474 if (!strcmp(i->name, include) &&
2475 (!registrar || !strcmp(i->registrar, registrar))) {
2476 /* remove from list */
2480 con->includes = i->next;
2481 /* free include and return */
2483 ast_mutex_unlock(&con->lock);
2489 /* we can't find the right include */
2490 ast_mutex_unlock(&con->lock);
2495 * \note This function locks contexts list by &conlist, search for the rigt context
2496 * structure, leave context list locked and call ast_context_remove_switch2
2497 * which removes switch, unlock contexts list and return ...
2499 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2501 struct ast_context *c = NULL;
2502 int ret = -1; /* default error return */
2504 if (ast_lock_contexts())
2507 /* walk contexts and search for the right one ...*/
2508 while ( (c = ast_walk_contexts(c)) ) {
2509 /* we found one ... */
2510 if (!strcmp(ast_get_context_name(c), context)) {
2511 /* remove switch from this context ... */
2512 ret = ast_context_remove_switch2(c, sw, data, registrar);
2517 /* found or error */
2518 ast_unlock_contexts();
2523 * \brief This function locks given context, removes switch, unlock context and
2525 * \note When we call this function, &conlock lock must be locked, because when
2526 * we giving *con argument, some process can remove/change this context
2527 * and after that there can be segfault.
2530 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2532 struct ast_sw *i, *pi = NULL;
2534 if (ast_mutex_lock(&con->lock)) return -1;
2537 for (i = con->alts; i; i = i->next) {
2538 /* find our switch */
2539 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2540 (!registrar || !strcmp(i->registrar, registrar))) {
2541 /* remove from list */
2545 con->alts = i->next;
2546 /* free switch and return */
2548 ast_mutex_unlock(&con->lock);
2554 /* we can't find the right switch */
2555 ast_mutex_unlock(&con->lock);
2560 * \note This functions lock contexts list, search for the right context,
2561 * call ast_context_remove_extension2, unlock contexts list and return.
2562 * In this function we are using
2564 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2566 struct ast_context *c = NULL;
2567 int ret = -1; /* default error return */
2569 if (ast_lock_contexts())
2572 /* walk contexts ... */
2573 while ( (c = ast_walk_contexts(c)) ) {
2574 /* ... search for the right one ... */
2575 if (!strcmp(ast_get_context_name(c), context)) {
2576 /* ... remove extension ... */
2577 ret = ast_context_remove_extension2(c, extension, priority,
2582 /* found or error */
2583 ast_unlock_contexts();
2588 * \brief This functionc locks given context, search for the right extension and
2589 * fires out all peer in this extensions with given priority. If priority
2590 * is set to 0, all peers are removed. After that, unlock context and
2592 * \note When do you want to call this function, make sure that &conlock is locked,
2593 * because some process can handle with your *con context before you lock
2597 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2599 struct ast_exten *exten, *prev_exten = NULL;
2601 if (ast_mutex_lock(&con->lock)) return -1;
2603 /* go through all extensions in context and search the right one ... */
2607 /* look for right extension */
2608 if (!strcmp(exten->exten, extension) &&
2609 (!registrar || !strcmp(exten->registrar, registrar))) {
2610 struct ast_exten *peer;
2612 /* should we free all peers in this extension? (priority == 0)? */
2613 if (priority == 0) {
2614 /* remove this extension from context list */
2616 prev_exten->next = exten->next;
2618 con->root = exten->next;
2620 /* fire out all peers */
2625 if (!peer->priority==PRIORITY_HINT)
2626 ast_remove_hint(peer);
2628 peer->datad(peer->data);
2634 ast_mutex_unlock(&con->lock);
2637 /* remove only extension with exten->priority == priority */
2638 struct ast_exten *previous_peer = NULL;
2642 /* is this our extension? */
2643 if (peer->priority == priority &&
2644 (!registrar || !strcmp(peer->registrar, registrar) )) {
2645 /* we are first priority extension? */
2646 if (!previous_peer) {
2647 /* exists previous extension here? */
2649 /* yes, so we must change next pointer in
2650 * previous connection to next peer
2653 prev_exten->next = peer->peer;
2654 peer->peer->next = exten->next;
2656 prev_exten->next = exten->next;
2658 /* no previous extension, we are first
2659 * extension, so change con->root ...
2662 con->root = peer->peer;
2664 con->root = exten->next;
2667 /* we are not first priority in extension */
2668 previous_peer->peer = peer->peer;
2671 /* now, free whole priority extension */
2672 if (peer->priority==PRIORITY_HINT)
2673 ast_remove_hint(peer);
2674 peer->datad(peer->data);
2677 ast_mutex_unlock(&con->lock);
2680 /* this is not right extension, skip to next peer */
2681 previous_peer = peer;
2686 ast_mutex_unlock(&con->lock);
2692 exten = exten->next;
2695 /* we can't find right extension */
2696 ast_mutex_unlock(&con->lock);
2701 /*! \brief Dynamically register a new dial plan application */
2702 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2704 struct ast_app *tmp, *prev, *cur;
2707 length = sizeof(struct ast_app);
2708 length += strlen(app) + 1;
2709 if (ast_mutex_lock(&applock)) {
2710 ast_log(LOG_ERROR, "Unable to lock application list\n");
2713 for (tmp = apps; tmp; tmp = tmp->next) {
2714 if (!strcasecmp(app, tmp->name)) {
2715 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2716 ast_mutex_unlock(&applock);
2721 tmp = calloc(1, length);
2723 ast_log(LOG_ERROR, "Out of memory\n");
2724 ast_mutex_unlock(&applock);
2728 strcpy(tmp->name, app);
2729 tmp->execute = execute;
2730 tmp->synopsis = synopsis;
2731 tmp->description = description;
2732 /* Store in alphabetical order */
2734 for (cur = apps; cur; cur = cur->next) {
2735 if (strcasecmp(tmp->name, cur->name) < 0)
2740 tmp->next = prev->next;
2747 if (option_verbose > 1)
2748 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2749 ast_mutex_unlock(&applock);
2753 int ast_register_switch(struct ast_switch *sw)
2755 struct ast_switch *tmp, *prev=NULL;
2756 if (ast_mutex_lock(&switchlock)) {
2757 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2760 for (tmp = switches; tmp; tmp = tmp->next) {
2761 if (!strcasecmp(tmp->name, sw->name))
2766 ast_mutex_unlock(&switchlock);
2767 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2775 ast_mutex_unlock(&switchlock);
2779 void ast_unregister_switch(struct ast_switch *sw)
2781 struct ast_switch *tmp, *prev=NULL;
2782 if (ast_mutex_lock(&switchlock)) {
2783 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2786 for (tmp = switches; tmp; tmp = tmp->next) {
2789 prev->next = tmp->next;
2791 switches = tmp->next;
2797 ast_mutex_unlock(&switchlock);
2801 * Help for CLI commands ...
2803 static char show_application_help[] =
2804 "Usage: show application <application> [<application> [<application> [...]]]\n"
2805 " Describes a particular application.\n";
2807 static char show_functions_help[] =
2808 "Usage: show functions [like <text>]\n"
2809 " List builtin functions, optionally only those matching a given string\n";
2811 static char show_function_help[] =
2812 "Usage: show function <function>\n"
2813 " Describe a particular dialplan function.\n";
2815 static char show_applications_help[] =
2816 "Usage: show applications [{like|describing} <text>]\n"
2817 " List applications which are currently available.\n"
2818 " If 'like', <text> will be a substring of the app name\n"
2819 " If 'describing', <text> will be a substring of the description\n";
2821 static char show_dialplan_help[] =
2822 "Usage: show dialplan [exten@][context]\n"
2825 static char show_switches_help[] =
2826 "Usage: show switches\n"
2827 " Show registered switches\n";
2829 static char show_hints_help[] =
2830 "Usage: show hints\n"
2831 " Show registered hints\n";
2833 static char show_globals_help[] =
2834 "Usage: show globals\n"
2835 " Show current global dialplan variables and their values\n";
2837 static char set_global_help[] =
2838 "Usage: set global <name> <value>\n"
2839 " Set global dialplan variable <name> to <value>\n";
2843 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2848 * \brief 'show application' CLI command implementation functions ...
2852 * There is a possibility to show informations about more than one
2853 * application at one time. You can type 'show application Dial Echo' and
2854 * you will see informations about these two applications ...
2856 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2861 int wordlen = strlen(word);
2863 /* try to lock applications list ... */
2864 if (ast_mutex_lock(&applock)) {
2865 ast_log(LOG_ERROR, "Unable to lock application list\n");
2869 /* return the n-th [partial] matching entry */
2870 for (a = apps; a && !ret; a = a->next) {
2871 if (!strncasecmp(word, a->name, wordlen) && ++which > state)
2872 ret = strdup(a->name);
2875 ast_mutex_unlock(&applock);
2880 static int handle_show_application(int fd, int argc, char *argv[])
2883 int app, no_registered_app = 1;
2885 if (argc < 3) return RESULT_SHOWUSAGE;
2887 /* try to lock applications list ... */
2888 if (ast_mutex_lock(&applock)) {
2889 ast_log(LOG_ERROR, "Unable to lock application list\n");
2893 /* ... go through all applications ... */
2894 for (a = apps; a; a = a->next) {
2895 /* ... compare this application name with all arguments given
2896 * to 'show application' command ... */
2897 for (app = 2; app < argc; app++) {
2898 if (!strcasecmp(a->name, argv[app])) {
2899 /* Maximum number of characters added by terminal coloring is 22 */
2900 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2901 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2902 int synopsis_size, description_size;
2904 no_registered_app = 0;
2907 synopsis_size = strlen(a->synopsis) + 23;
2909 synopsis_size = strlen("Not available") + 23;
2910 synopsis = alloca(synopsis_size);
2913 description_size = strlen(a->description) + 23;
2915 description_size = strlen("Not available") + 23;
2916 description = alloca(description_size);
2918 if (synopsis && description) {
2919 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2920 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2921 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2922 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2923 term_color(synopsis,
2924 a->synopsis ? a->synopsis : "Not available",
2925 COLOR_CYAN, 0, synopsis_size);
2926 term_color(description,
2927 a->description ? a->description : "Not available",
2928 COLOR_CYAN, 0, description_size);
2930 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2932 /* ... one of our applications, show info ...*/
2933 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2934 "[Synopsis]\n %s\n\n"
2935 "[Description]\n%s\n",
2937 a->synopsis ? a->synopsis : "Not available",
2938 a->description ? a->description : "Not available");
2944 ast_mutex_unlock(&applock);
2946 /* we found at least one app? no? */
2947 if (no_registered_app) {
2948 ast_cli(fd, "Your application(s) is (are) not registered\n");
2949 return RESULT_FAILURE;
2952 return RESULT_SUCCESS;
2955 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2956 static int handle_show_hints(int fd, int argc, char *argv[])
2958 struct ast_hint *hint;
2961 struct ast_state_cb *watcher;
2963 if (AST_LIST_EMPTY(&hints)) {
2964 ast_cli(fd, "There are no registered dialplan hints\n");
2965 return RESULT_SUCCESS;
2967 /* ... we have hints ... */
2968 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2969 if (AST_LIST_LOCK(&hints)) {
2970 ast_log(LOG_ERROR, "Unable to lock hints\n");
2973 AST_LIST_TRAVERSE(&hints, hint, list) {
2975 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2977 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2978 ast_get_extension_name(hint->exten),
2979 ast_get_context_name(ast_get_extension_context(hint->exten)),
2980 ast_get_extension_app(hint->exten),
2981 ast_extension_state2str(hint->laststate), watchers);
2984 ast_cli(fd, "----------------\n");
2985 ast_cli(fd, "- %d hints registered\n", num);
2986 AST_LIST_UNLOCK(&hints);
2987 return RESULT_SUCCESS;
2990 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2991 static int handle_show_switches(int fd, int argc, char *argv[])
2993 struct ast_switch *sw;
2995 ast_cli(fd, "There are no registered alternative switches\n");
2996 return RESULT_SUCCESS;
2998 /* ... we have applications ... */
2999 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
3000 if (ast_mutex_lock(&switchlock)) {
3001 ast_log(LOG_ERROR, "Unable to lock switches\n");
3004 for (sw = switches; sw; sw = sw->next) {
3005 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3007 ast_mutex_unlock(&switchlock);
3008 return RESULT_SUCCESS;
3012 * 'show applications' CLI command implementation functions ...
3014 static int handle_show_applications(int fd, int argc, char *argv[])
3017 int like = 0, describing = 0;
3018 int total_match = 0; /* Number of matches in like clause */
3019 int total_apps = 0; /* Number of apps registered */
3021 /* try to lock applications list ... */
3022 if (ast_mutex_lock(&applock)) {
3023 ast_log(LOG_ERROR, "Unable to lock application list\n");
3027 /* ... have we got at least one application (first)? no? */
3029 ast_cli(fd, "There are no registered applications\n");
3030 ast_mutex_unlock(&applock);
3034 /* show applications like <keyword> */
3035 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3037 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3041 /* show applications describing <keyword1> [<keyword2>] [...] */
3042 if ((!like) && (!describing)) {
3043 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3045 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3048 /* ... go through all applications ... */
3049 for (a = apps; a; a = a->next) {
3050 /* ... show informations about applications ... */
3054 if (strcasestr(a->name, argv[3])) {
3058 } else if (describing) {
3059 if (a->description) {
3060 /* Match all words on command line */
3063 for (i = 3; i < argc; i++) {
3064 if (!strcasestr(a->description, argv[i])) {
3076 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3079 if ((!like) && (!describing)) {
3080 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3082 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3085 /* ... unlock and return */
3086 ast_mutex_unlock(&applock);
3088 return RESULT_SUCCESS;
3091 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3093 int wordlen = strlen(word);
3096 if (ast_strlen_zero(word)) {
3099 return strdup("like");
3101 return strdup("describing");
3105 } else if (! strncasecmp(word, "like", wordlen)) {
3107 return strdup("like");
3111 } else if (! strncasecmp(word, "describing", wordlen)) {
3113 return strdup("describing");
3123 * 'show dialplan' CLI command implementation functions ...
3125 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3128 struct ast_context *c = NULL;
3133 /* we are do completion of [exten@]context on second position only */
3137 /* try to lock contexts list ... */
3138 if (ast_lock_contexts()) {
3139 ast_log(LOG_ERROR, "Unable to lock context list\n");
3143 wordlen = strlen(word);
3145 /* ... walk through all contexts ... */
3146 while ( (c = ast_walk_contexts(c)) ) {
3147 /* ... word matches context name? yes? ... */
3148 if (!strncasecmp(word, ast_get_context_name(c), wordlen)) {
3149 /* ... for serve? ... */
3150 if (++which > state) {
3151 /* ... yes, serve this context name ... */
3152 ret = strdup(ast_get_context_name(c));
3158 /* ... unlock and return */
3159 ast_unlock_contexts();
3163 struct dialplan_counters {
3167 int context_existence;
3168 int extension_existence;
3171 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, char *includes[])
3173 struct ast_context *c = NULL;
3174 int res = 0, old_total_exten = dpc->total_exten;
3176 /* try to lock contexts */
3177 if (ast_lock_contexts()) {
3178 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3182 /* walk all contexts ... */
3183 while ( (c = ast_walk_contexts(c)) ) {
3184 /* show this context? */
3186 !strcmp(ast_get_context_name(c), context)) {
3187 dpc->context_existence = 1;
3189 /* try to lock context before walking in ... */
3190 if (!ast_lock_context(c)) {
3191 struct ast_exten *e;
3192 struct ast_include *i;
3193 struct ast_ignorepat *ip;
3195 char buf[256], buf2[256];
3196 int context_info_printed = 0;
3198 /* are we looking for exten too? if yes, we print context
3199 * if we our extension only
3202 dpc->total_context++;
3203 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3204 ast_get_context_name(c), ast_get_context_registrar(c));
3205 context_info_printed = 1;
3208 /* walk extensions ... */
3209 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3210 struct ast_exten *p;
3213 /* looking for extension? is this our extension? */
3215 !ast_extension_match(ast_get_extension_name(e), exten))
3217 /* we are looking for extension and it's not our
3218 * extension, so skip to next extension */
3222 dpc->extension_existence = 1;
3224 /* may we print context info? */
3225 if (!context_info_printed) {
3226 dpc->total_context++;
3228 /* TODO Print more info about rinclude */
3229 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3230 ast_get_context_name(c),
3231 ast_get_context_registrar(c));
3233 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3234 ast_get_context_name(c),
3235 ast_get_context_registrar(c));
3237 context_info_printed = 1;
3241 /* write extension name and first peer */
3242 bzero(buf, sizeof(buf));
3243 snprintf(buf, sizeof(buf), "'%s' =>",
3244 ast_get_extension_name(e));
3246 prio = ast_get_extension_priority(e);
3247 if (prio == PRIORITY_HINT) {
3248 snprintf(buf2, sizeof(buf2),
3250 ast_get_extension_app(e));
3252 snprintf(buf2, sizeof(buf2),
3255 ast_get_extension_app(e),
3256 (char *)ast_get_extension_app_data(e));
3259 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3260 ast_get_extension_registrar(e));
3263 /* walk next extension peers */
3264 for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3266 bzero((void *)buf2, sizeof(buf2));
3267 bzero((void *)buf, sizeof(buf));
3268 if (ast_get_extension_label(p))
3269 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
3270 prio = ast_get_extension_priority(p);
3271 if (prio == PRIORITY_HINT) {
3272 snprintf(buf2, sizeof(buf2),
3274 ast_get_extension_app(p));
3276 snprintf(buf2, sizeof(buf2),
3279 ast_get_extension_app(p),
3280 (char *)ast_get_extension_app_data(p));
3283 ast_cli(fd," %-17s %-45s [%s]\n",
3285 ast_get_extension_registrar(p));
3289 /* walk included and write info ... */
3290 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3291 bzero(buf, sizeof(buf));
3292 snprintf(buf, sizeof(buf), "'%s'",
3293 ast_get_include_name(i));
3295 /* Check all includes for the requested extension */
3296 if (includecount >= AST_PBX_MAX_STACK) {
3297 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
3301 for (x=0;x<includecount;x++) {
3302 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3308 includes[includecount] = (char *)ast_get_include_name(i);
3309 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3311 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3315 ast_cli(fd, " Include => %-45s [%s]\n",
3316 buf, ast_get_include_registrar(i));
3320 /* walk ignore patterns and write info ... */
3321 for (ip = ast_walk_context_ignorepats(c, NULL); ip; ip = ast_walk_context_ignorepats(c, ip)) {
3322 const char *ipname = ast_get_ignorepat_name(ip);
3323 char ignorepat[AST_MAX_EXTENSION];
3324 snprintf(buf, sizeof(buf), "'%s'", ipname);
3325 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3326 if ((!exten) || ast_extension_match(ignorepat, exten)) {
3327 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3328 buf, ast_get_ignorepat_registrar(ip));
3332 for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
3333 snprintf(buf, sizeof(buf), "'%s/%s'",
3334 ast_get_switch_name(sw),
3335 ast_get_switch_data(sw));
3336 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3337 buf, ast_get_switch_registrar(sw));
3341 ast_unlock_context(c);
3343 /* if we print something in context, make an empty line */
3344 if (context_info_printed) ast_cli(fd, "\r\n");
3348 ast_unlock_contexts();
3350 if (dpc->total_exten == old_total_exten) {
3351 /* Nothing new under the sun */
3358 static int handle_show_dialplan(int fd, int argc, char *argv[])
3360 char *exten = NULL, *context = NULL;
3361 /* Variables used for different counters */
3362 struct dialplan_counters counters;
3363 char *incstack[AST_PBX_MAX_STACK];
3364 memset(&counters, 0, sizeof(counters));
3366 if (argc != 2 && argc != 3)
3367 return RESULT_SHOWUSAGE;
3369 /* we obtain [exten@]context? if yes, split them ... */
3371 char *splitter = ast_strdupa(argv[2]);
3372 /* is there a '@' character? */
3373 if (splitter && strchr(argv[2], '@')) {
3374 /* yes, split into exten & context ... */
3375 exten = strsep(&splitter, "@");
3378 /* check for length and change to NULL if ast_strlen_zero() */
3379 if (ast_strlen_zero(exten))
3381 if (ast_strlen_zero(context))
3383 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3385 /* no '@' char, only context given */
3387 if (ast_strlen_zero(context))
3389 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3392 /* Show complete dial plan */
3393 show_dialplan_helper(fd, NULL, NULL, &counters, NULL, 0, incstack);
3396 /* check for input failure and throw some error messages */
3397 if (context && !counters.context_existence) {
3398 ast_cli(fd, "There is no existence of '%s' context\n", context);
3399 return RESULT_FAILURE;
3402 if (exten && !counters.extension_existence) {
3404 ast_cli(fd, "There is no existence of %s@%s extension\n",
3408 "There is no existence of '%s' extension in all contexts\n",
3410 return RESULT_FAILURE;
3413 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
3414 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
3415 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
3416 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
3419 return RESULT_SUCCESS;
3422 /*! \brief CLI support for listing global variables in a parseable way */
3423 static int handle_show_globals(int fd, int argc, char *argv[])
3426 struct ast_var_t *newvariable;
3428 ast_mutex_lock(&globalslock);
3429 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
3431 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
3433 ast_mutex_unlock(&globalslock);
3434 ast_cli(fd, "\n -- %d variables\n", i);
3436 return RESULT_SUCCESS;
3439 /*! \brief CLI support for setting global variables */
3440 static int handle_set_global(int fd, int argc, char *argv[])
3443 return RESULT_SHOWUSAGE;
3445 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
3446 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
3448 return RESULT_SUCCESS;
3454 * CLI entries for upper commands ...
3456 static struct ast_cli_entry pbx_cli[] = {
3457 { { "show", "applications", NULL }, handle_show_applications,