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 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 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" }
213 int ast_pbx_outgoing_cdr_failed(void);
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 AST_MUTEX_DEFINE_STATIC(acflock); /*!< Lock for the custom function list */
248 static struct ast_custom_function *acf_root = NULL;
250 /*! \brief Declaration of builtin applications */
251 static struct pbx_builtin {
252 char name[AST_MAX_APP];
253 int (*execute)(struct ast_channel *chan, void *data);
258 /* These applications are built into the PBX core and do not
259 need separate modules */
261 { "Answer", pbx_builtin_answer,
262 "Answer a channel if ringing",
263 " Answer([delay]): If the call has not been answered, this application will\n"
264 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
265 "Asterisk will wait this number of milliseconds before answering the call.\n"
268 { "BackGround", pbx_builtin_background,
269 "Play a file while awaiting extension",
270 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
271 "This application will play the given list of files while waiting for an\n"
272 "extension to be dialed by the calling channel. To continue waiting for digits\n"
273 "after this application has finished playing files, the WaitExten application\n"
274 "should be used. The 'langoverride' option explicity specifies which language\n"
275 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
276 "this is the dialplan context that this application will use when exiting to a\n"
278 " If one of the requested sound files does not exist, call processing will be\n"
281 " s - causes the playback of the message to be skipped\n"
282 " if the channel is not in the 'up' state (i.e. it\n"
283 " hasn't been answered yet.) If this happens, the\n"
284 " application will return immediately.\n"
285 " n - don't answer the channel before playing the files\n"
286 " m - only break if a digit hit matches a one digit\n"
287 " extension in the destination context\n"
290 { "Busy", pbx_builtin_busy,
291 "Indicate the Busy condition",
292 " Busy([timeout]): This application will indicate the busy condition to\n"
293 "the calling channel. If the optional timeout is specified, the calling channel\n"
294 "will be hung up after the specified number of seconds. Otherwise, this\n"
295 "application will wait until the calling channel hangs up.\n"
298 { "Congestion", pbx_builtin_congestion,
299 "Indicate the Congestion condition",
300 " Congestion([timeout]): This application will indicate the congenstion\n"
301 "condition to the calling channel. If the optional timeout is specified, the\n"
302 "calling channel will be hung up after the specified number of seconds.\n"
303 "Otherwise, this application will wait until the calling channel hangs up.\n"
306 { "Goto", pbx_builtin_goto,
307 "Jump to a particular priority, extension, or context",
308 " Goto([[context|]extension|]priority): This application will cause the\n"
309 "calling channel to continue dialplan execution at the specified priority.\n"
310 "If no specific extension, or extension and context, are specified, then this\n"
311 "application will jump to the specified priority of the current extension.\n"
312 " If the attempt to jump to another location in the dialplan is not successful,\n"
313 "then the channel will continue at the next priority of the current extension.\n"
316 { "GotoIf", pbx_builtin_gotoif,
318 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
319 "the calling channel to jump to the specified location in the dialplan based on\n"
320 "the evaluation of the given condition. The channel will continue at\n"
321 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
322 "false. The labels are specified with the same syntax as used within the Goto\n"
323 "application. If the label chosen by the condition is omitted, no jump is\n"
324 "performed, but execution continues with the next priority in the dialplan.\n"
327 { "GotoIfTime", pbx_builtin_gotoiftime,
328 "Conditional Goto based on the current time",
329 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
330 "This application will have the calling channel jump to the speicified location\n"
331 "int the dialplan if the current time matches the given time specification.\n"
332 "Further information on the time specification can be found in examples\n"
333 "illustrating how to do time-based context includes in the dialplan.\n"
336 { "ExecIfTime", pbx_builtin_execiftime,
337 "Conditional application execution based on the current time",
338 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
339 "This application will execute the specified dialplan application, with optional\n"
340 "arguments, if the current time matches the given time specification. Further\n"
341 "information on the time speicification can be found in examples illustrating\n"
342 "how to do time-based context includes in the dialplan.\n"
345 { "Hangup", pbx_builtin_hangup,
346 "Hang up the calling channel",
347 " Hangup(): This application will hang up the calling channel.\n"
350 { "NoOp", pbx_builtin_noop,
352 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
353 "purposes. Any text that is provided as arguments to this application can be\n"
354 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
355 "variables or functions without having any effect."
358 { "Progress", pbx_builtin_progress,
360 " Progress(): This application will request that in-band progress information\n"
361 "be provided to the calling channel.\n"
364 { "ResetCDR", pbx_builtin_resetcdr,
365 "Resets the Call Data Record",
366 " ResetCDR([options]): This application causes the Call Data Record to be\n"
369 " w -- Store the current CDR record before resetting it.\n"
370 " a -- Store any stacked records.\n"
371 " v -- Save CDR variables.\n"
374 { "Ringing", pbx_builtin_ringing,
375 "Indicate ringing tone",
376 " Ringing(): This application will request that the channel indicate a ringing\n"
377 "tone to the user.\n"
380 { "SayNumber", pbx_builtin_saynumber,
382 " SayNumber(digits[,gender]): This application will play the sounds that\n"
383 "correspond to the given number. Optionally, a gender may be specified.\n"
384 "This will use the language that is currently set for the channel. See the\n"
385 "LANGUAGE function for more information on setting the language for the channel.\n"
388 { "SayDigits", pbx_builtin_saydigits,
390 " SayDigits(digits): This application will play the sounds that correspond\n"
391 "to the digits of the given number. This will use the language that is currently\n"
392 "set for the channel. See the LANGUAGE function for more information on setting\n"
393 "the language for the channel.\n"
396 { "SayAlpha", pbx_builtin_saycharacters,
398 " SayAlpha(string): This application will play the sounds that correspond to\n"
399 "the letters of the given string.\n"
402 { "SayPhonetic", pbx_builtin_sayphonetic,
404 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
405 "alphabet that correspond to the letters in the given string.\n"
408 { "SetAMAFlags", pbx_builtin_setamaflags,
410 " SetAMAFlags([flag]): This channel will set the channel's AMA Flags for billing\n"
414 { "SetGlobalVar", pbx_builtin_setglobalvar,
415 "Set a global variable to a given value",
416 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
417 "the specified value.\n"
420 { "Set", pbx_builtin_setvar,
421 "Set channel variable(s) or function value(s)",
422 " Set(name1=value1|name2=value2|..[|options])\n"
423 "This function can be used to set the value of channel variables or dialplan\n"
424 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
425 "if the variable name is prefixed with _, the variable will be inherited into\n"
426 "channels created from the current channel. If the variable name is prefixed\n"
427 "with __, the variable will be inherited into channels created from the current\n"
428 "channel and all children channels.\n"
430 " g - Set variable globally instead of on the channel\n"
431 " (applies only to variables, not functions)\n"
434 { "ImportVar", pbx_builtin_importvar,
435 "Import a variable from a channel into a new variable",
436 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
437 "from the specified channel (as opposed to the current one) and stores it as\n"
438 "a variable in the current channel (the channel that is calling this\n"
439 "application). Variables created by this application have the same inheritance\n"
440 "properties as those created with the Set application. See the documentation for\n"
441 "Set for more information.\n"
444 { "Wait", pbx_builtin_wait,
445 "Waits for some time",
446 " Wait(seconds): This application waits for a specified number of seconds.\n"
447 "Then, dialplan execution will continue at the next priority.\n"
448 " Note that the seconds can be passed with fractions of a second. For example,\n"
449 "'1.5' will ask the application to wait for 1.5 seconds.\n"
452 { "WaitExten", pbx_builtin_waitexten,
453 "Waits for an extension to be entered",
454 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
455 "a new extension for a specified number of seconds.\n"
456 " Note that the seconds can be passed with fractions of a second. For example,\n"
457 "'1.5' will ask the application to wait for 1.5 seconds.\n"
459 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
460 " Optionally, specify the class for music on hold within parenthesis.\n"
465 static struct ast_context *contexts = NULL;
466 AST_MUTEX_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
467 static struct ast_app *apps = NULL;
468 AST_MUTEX_DEFINE_STATIC(applock); /*!< Lock for the application list */
470 struct ast_switch *switches = NULL;
471 AST_MUTEX_DEFINE_STATIC(switchlock); /*!< Lock for switches */
473 static int stateid = 1;
475 When holding this list's lock, do _not_ do anything that will cause conlock
476 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
477 function will take the locks in conlock/hints order, so any other
478 paths that require both locks must also take them in that order.
480 static AST_LIST_HEAD_STATIC(hints, ast_hint);
481 struct ast_state_cb *statecbs = NULL;
484 \note This function is special. It saves the stack so that no matter
485 how many times it is called, it returns to the same place */
486 int pbx_exec(struct ast_channel *c, /*!< Channel */
487 struct ast_app *app, /*!< Application */
488 void *data) /*!< Data for execution */
492 const char *saved_c_appl;
493 const char *saved_c_data;
496 ast_cdr_setapp(c->cdr, app->name, data);
498 /* save channel values */
499 saved_c_appl= c->appl;
500 saved_c_data= c->data;
504 /* XXX remember what to to when we have linked apps to modules */
506 /* XXX LOCAL_USER_ADD(app->module) */
508 res = app->execute(c, data);
510 /* XXX LOCAL_USER_REMOVE(app->module) */
512 /* restore channel values */
513 c->appl = saved_c_appl;
514 c->data = saved_c_data;
519 /*! Go no deeper than this through includes (not counting loops) */
520 #define AST_PBX_MAX_STACK 128
522 #define HELPER_EXISTS 0
523 #define HELPER_SPAWN 1
524 #define HELPER_CANMATCH 3
525 #define HELPER_MATCHMORE 4
526 #define HELPER_FINDLABEL 5
528 /*! \brief Find application handle in linked list
530 struct ast_app *pbx_findapp(const char *app)
534 if (ast_mutex_lock(&applock)) {
535 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
538 for (tmp = apps; tmp; tmp = tmp->next) {
539 if (!strcasecmp(tmp->name, app))
542 ast_mutex_unlock(&applock);
546 static struct ast_switch *pbx_findswitch(const char *sw)
548 struct ast_switch *asw;
550 if (ast_mutex_lock(&switchlock)) {
551 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
554 for (asw = switches; asw; asw = asw->next) {
555 if (!strcasecmp(asw->name, sw))
558 ast_mutex_unlock(&switchlock);
562 static inline int include_valid(struct ast_include *i)
567 return ast_check_timing(&(i->timing));
570 static void pbx_destroy(struct ast_pbx *p)
575 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
576 /* All patterns begin with _ */\
577 if (pattern[0] != '_') \
579 /* Start optimistic */\
582 while(match && *data && *pattern && (*pattern != '/')) {\
583 while (*data == '-' && (*(data+1) != '\0')) data++;\
584 switch(toupper(*pattern)) {\
591 where=strchr(pattern,']');\
593 border=(int)(where-pattern);\
594 if (!where || border > strlen(pattern)) {\
595 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
598 for (i=0; i<border; i++) {\
601 if (pattern[i+1]=='-') {\
602 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
609 if (res==1 || *data==pattern[i]) {\
618 if ((*data < '2') || (*data > '9'))\
622 if ((*data < '0') || (*data > '9'))\
626 if ((*data < '1') || (*data > '9'))\
637 /* Ignore these characters */\
641 if (*data != *pattern)\
647 /* If we ran off the end of the data and the pattern ends in '!', match */\
648 if (match && !*data && (*pattern == '!'))\
652 int ast_extension_match(const char *pattern, const char *data)
655 /* If they're the same return */
656 if (!strcmp(pattern, data))
658 EXTENSION_MATCH_CORE(data,pattern,match);
659 /* Must be at the end of both */
660 if (*data || (*pattern && (*pattern != '/')))
665 int ast_extension_close(const char *pattern, const char *data, int needmore)
668 /* If "data" is longer, it can'be a subset of pattern unless
669 pattern is a pattern match */
670 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
673 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
674 (!needmore || (strlen(pattern) > strlen(data)))) {
677 EXTENSION_MATCH_CORE(data,pattern,match);
678 /* If there's more or we don't care about more, or if it's a possible early match,
679 return non-zero; otherwise it's a miss */
680 if (!needmore || *pattern || match == 2) {
686 struct ast_context *ast_context_find(const char *name)
688 struct ast_context *tmp;
689 ast_mutex_lock(&conlock);
691 for (tmp = contexts; tmp; tmp = tmp->next) {
692 if (!strcasecmp(name, tmp->name))
697 ast_mutex_unlock(&conlock);
701 #define STATUS_NO_CONTEXT 1
702 #define STATUS_NO_EXTENSION 2
703 #define STATUS_NO_PRIORITY 3
704 #define STATUS_NO_LABEL 4
705 #define STATUS_SUCCESS 5
707 static int matchcid(const char *cidpattern, const char *callerid)
711 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
712 failing to get a number should count as a match, otherwise not */
714 if (!ast_strlen_zero(cidpattern))
722 return ast_extension_match(cidpattern, callerid);
725 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)
728 struct ast_context *tmp;
729 struct ast_exten *e, *eroot;
730 struct ast_include *i;
732 struct ast_switch *asw;
734 /* Initialize status if appropriate */
736 *status = STATUS_NO_CONTEXT;
740 /* Check for stack overflow */
741 if (*stacklen >= AST_PBX_MAX_STACK) {
742 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
745 /* Check first to see if we've already been checked */
746 for (x = 0; x < *stacklen; x++) {
747 if (!strcasecmp(incstack[x], context))
754 for (; tmp; tmp = tmp->next) {
756 if (bypass || !strcmp(tmp->name, context)) {
757 struct ast_exten *earlymatch = NULL;
759 if (*status < STATUS_NO_EXTENSION)
760 *status = STATUS_NO_EXTENSION;
761 for (eroot = tmp->root; eroot; eroot = eroot->next) {
763 /* Match extension */
764 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
765 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
766 ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
767 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
769 if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
770 /* It matched an extension ending in a '!' wildcard
771 So ignore it for now, unless there's a better match */
774 if (*status < STATUS_NO_PRIORITY)
775 *status = STATUS_NO_PRIORITY;
776 for (e = eroot; e; e = e->peer) {
778 if (action == HELPER_FINDLABEL) {
779 if (*status < STATUS_NO_LABEL)
780 *status = STATUS_NO_LABEL;
781 if (label && e->label && !strcmp(label, e->label)) {
782 *status = STATUS_SUCCESS;
783 *foundcontext = context;
786 } else if (e->priority == priority) {
787 *status = STATUS_SUCCESS;
788 *foundcontext = context;
796 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
797 of the loop waiting for more digits, and _then_ match (normally)
798 the extension we ended up with. We got an early-matching wildcard
799 pattern, so return NULL to break out of the loop. */
802 /* Check alternative switches */
803 for (sw = tmp->alts; sw; sw = sw->next) {
804 if ((asw = pbx_findswitch(sw->name))) {
805 /* Substitute variables now */
807 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
808 if (action == HELPER_CANMATCH)
809 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
810 else if (action == HELPER_MATCHMORE)
811 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
813 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
817 *data = sw->eval ? sw->tmpdata : sw->data;
818 *foundcontext = context;
822 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
825 /* Setup the stack */
826 incstack[*stacklen] = tmp->name;
828 /* Now try any includes we have in this context */
829 for (i = tmp->includes; i; i = i->next) {
830 if (include_valid(i)) {
831 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
843 /* Note that it's negative -- that's important later. */
844 #define DONT_HAVE_LENGTH 0x80000000
846 /*! \brief extract offset:length from variable name.
847 * Returns 1 if there is a offset:length part, which is
848 * trimmed off (values go into variables)
850 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
855 *length = DONT_HAVE_LENGTH;
857 for (; *var; var++) {
861 } else if (*var == ')') {
863 } else if (*var == ':' && parens == 0) {
865 sscanf(var, "%d:%d", offset, length);
866 return 1; /* offset:length valid */
872 /*! \brief takes a substring. It is ok to call with value == workspace.
874 * offset < 0 means start from the end of the string and set the beginning
875 * to be that many characters back.
876 * length is the length of the substring, -1 means unlimited
877 * (we take any negative value).
878 * Always return a copy in workspace.
880 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
882 char *ret = workspace;
883 int lr; /* length of the input string after the copy */
885 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
887 if (offset == 0 && length < 0) /* take the whole string */
890 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
892 if (offset < 0) { /* translate negative offset into positive ones */
893 offset = lr + offset;
894 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
898 /* too large offset result in empty string so we know what to return */
900 return ret + lr; /* the final '\0' */
902 ret += offset; /* move to the start position */
903 if (length >= 0 && length < lr - offset) /* truncate if necessary */
909 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
910 functions in the dialplan
912 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
914 const char not_found = '\0';
916 const char *s; /* the result */
918 int i, need_substring;
919 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
922 places[0] = &c->varshead;
925 * Make a copy of var because parse_variable_name() modifies the string.
926 * Then if called directly, we might need to run substring() on the result;
927 * remember this for later in 'need_substring', 'offset' and 'length'
929 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
930 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
933 * Look first into predefined variables, then into variable lists.
934 * Variable 's' points to the result, according to the following rules:
935 * s == ¬_found (set at the beginning) means that we did not find a
936 * matching variable and need to look into more places.
937 * If s != ¬_found, s is a valid result string as follows:
938 * s = NULL if the variable does not have a value;
939 * you typically do this when looking for an unset predefined variable.
940 * s = workspace if the result has been assembled there;
941 * typically done when the result is built e.g. with an snprintf(),
942 * so we don't need to do an additional copy.
943 * s != workspace in case we have a string, that needs to be copied
944 * (the ast_copy_string is done once for all at the end).
945 * Typically done when the result is already available in some string.
947 s = ¬_found; /* default value */
948 if (c) { /* This group requires a valid channel */
949 /* Names with common parts are looked up a piece at a time using strncmp. */
950 if (!strncmp(var, "CALL", 4)) {
951 if (!strncmp(var + 4, "ING", 3)) {
952 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
953 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
955 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
956 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
958 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
959 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
961 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
962 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
966 } else if (!strcmp(var, "HINT")) {
967 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
968 } else if (!strcmp(var, "HINTNAME")) {
969 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
970 } else if (!strcmp(var, "EXTEN")) {
972 } else if (!strcmp(var, "CONTEXT")) {
974 } else if (!strcmp(var, "PRIORITY")) {
975 snprintf(workspace, workspacelen, "%d", c->priority);
977 } else if (!strcmp(var, "CHANNEL")) {
979 } else if (!strcmp(var, "UNIQUEID")) {
981 } else if (!strcmp(var, "HANGUPCAUSE")) {
982 snprintf(workspace, workspacelen, "%d", c->hangupcause);
986 if (s == ¬_found) { /* look for more */
987 if (!strcmp(var, "EPOCH")) {
988 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
990 } else if (!strcmp(var, "SYSTEMNAME")) {
991 s = ast_config_AST_SYSTEM_NAME;
994 /* if not found, look into chanvars or global vars */
995 for (i = 0; s == ¬_found && i < (sizeof(places) / sizeof(places[0])); i++) {
996 struct ast_var_t *variables;
999 if (places[i] == &globals)
1000 ast_mutex_lock(&globalslock);
1001 AST_LIST_TRAVERSE(places[i], variables, entries) {
1002 if (strcasecmp(ast_var_name(variables), var)==0) {
1003 s = ast_var_value(variables);
1007 if (places[i] == &globals)
1008 ast_mutex_unlock(&globalslock);
1010 if (s == ¬_found || s == NULL)
1014 ast_copy_string(workspace, s, workspacelen);
1017 *ret = substring(*ret, offset, length, workspace, workspacelen);
1021 /*! \brief CLI function to show installed custom functions
1022 \addtogroup CLI_functions
1024 static int handle_show_functions(int fd, int argc, char *argv[])
1026 struct ast_custom_function *acf;
1031 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1033 } else if (argc != 2) {
1034 return RESULT_SHOWUSAGE;
1037 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1039 for (acf = acf_root ; acf; acf = acf->next) {
1042 if (strstr(acf->name, argv[3])) {
1052 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1056 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1061 static int handle_show_function(int fd, int argc, char *argv[])
1063 struct ast_custom_function *acf;
1064 /* Maximum number of characters added by terminal coloring is 22 */
1065 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1066 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1067 char stxtitle[40], *syntax = NULL;
1068 int synopsis_size, description_size, syntax_size;
1070 if (argc < 3) return RESULT_SHOWUSAGE;
1072 if (!(acf = ast_custom_function_find(argv[2]))) {
1073 ast_cli(fd, "No function by that name registered.\n");
1074 return RESULT_FAILURE;
1079 synopsis_size = strlen(acf->synopsis) + 23;
1081 synopsis_size = strlen("Not available") + 23;
1082 synopsis = alloca(synopsis_size);
1085 description_size = strlen(acf->desc) + 23;
1087 description_size = strlen("Not available") + 23;
1088 description = alloca(description_size);
1091 syntax_size = strlen(acf->syntax) + 23;
1093 syntax_size = strlen("Not available") + 23;
1094 syntax = alloca(syntax_size);
1096 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1097 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1098 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1099 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1100 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1102 acf->syntax ? acf->syntax : "Not available",
1103 COLOR_CYAN, 0, syntax_size);
1104 term_color(synopsis,
1105 acf->synopsis ? acf->synopsis : "Not available",
1106 COLOR_CYAN, 0, synopsis_size);
1107 term_color(description,
1108 acf->desc ? acf->desc : "Not available",
1109 COLOR_CYAN, 0, description_size);
1111 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1113 return RESULT_SUCCESS;
1116 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1118 struct ast_custom_function *acf;
1121 int wordlen = strlen(word);
1123 /* try to lock functions list ... */
1124 if (ast_mutex_lock(&acflock)) {
1125 ast_log(LOG_ERROR, "Unable to lock function list\n");
1129 /* case-insensitive for convenience in this 'complete' function */
1130 for (acf = acf_root; acf && !ret; acf = acf->next) {
1131 if (!strncasecmp(word, acf->name, wordlen) && ++which > state)
1132 ret = strdup(acf->name);
1135 ast_mutex_unlock(&acflock);
1140 struct ast_custom_function* ast_custom_function_find(const char *name)
1142 struct ast_custom_function *acfptr;
1144 /* try to lock functions list ... */
1145 if (ast_mutex_lock(&acflock)) {
1146 ast_log(LOG_ERROR, "Unable to lock function list\n");
1150 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1151 if (!strcmp(name, acfptr->name))
1155 ast_mutex_unlock(&acflock);
1160 int ast_custom_function_unregister(struct ast_custom_function *acf)
1162 struct ast_custom_function *acfptr, *lastacf = NULL;
1168 /* try to lock functions list ... */
1169 if (ast_mutex_lock(&acflock)) {
1170 ast_log(LOG_ERROR, "Unable to lock function list\n");
1174 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1175 if (acfptr == acf) {
1177 lastacf->next = acf->next;
1179 acf_root = acf->next;
1187 ast_mutex_unlock(&acflock);
1189 if (!res && (option_verbose > 1))
1190 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1195 int ast_custom_function_register(struct ast_custom_function *acf)
1197 struct ast_custom_function *cur, *last = NULL;
1203 /* try to lock functions list ... */
1204 if (ast_mutex_lock(&acflock)) {
1205 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
1209 if (ast_custom_function_find(acf->name)) {
1210 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1211 ast_mutex_unlock(&acflock);
1215 for (cur = acf_root; cur; cur = cur->next) {
1216 if (strcmp(acf->name, cur->name) < 0) {
1222 acf->next = acf_root;
1230 /* Wasn't before anything else, put it at the end */
1239 ast_mutex_unlock(&acflock);
1241 if (option_verbose > 1)
1242 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1247 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1249 char *args = NULL, *p;
1250 struct ast_custom_function *acfptr;
1252 if ((args = strchr(function, '('))) {
1254 if ((p = strrchr(args, ')')))
1257 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1259 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1262 if ((acfptr = ast_custom_function_find(function))) {
1263 /* run the custom function */
1265 return acfptr->read(chan, function, args, workspace, len);
1267 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1269 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1275 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1277 char *args = NULL, *p;
1278 struct ast_custom_function *acfptr;
1280 if ((args = strchr(function, '('))) {
1282 if ((p = strrchr(args, ')')))
1285 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1287 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1290 if ((acfptr = ast_custom_function_find(function))) {
1291 /* run the custom function */
1293 return acfptr->write(chan, function, args, value);
1295 ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
1297 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1303 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1306 const char *tmp, *whereweare;
1307 int length, offset, offset2, isfunction;
1308 char *workspace = NULL;
1309 char *ltmp = NULL, *var = NULL;
1310 char *nextvar, *nextexp, *nextthing;
1312 int pos, brackets, needsub, len;
1314 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1317 while(!ast_strlen_zero(whereweare) && count) {
1318 /* Assume we're copying the whole remaining string */
1319 pos = strlen(whereweare);
1322 nextthing = strchr(whereweare, '$');
1324 switch(nextthing[1]) {
1326 nextvar = nextthing;
1327 pos = nextvar - whereweare;
1330 nextexp = nextthing;
1331 pos = nextexp - whereweare;
1337 /* Can't copy more than 'count' bytes */
1341 /* Copy that many bytes */
1342 memcpy(cp2, whereweare, pos);
1350 /* We have a variable. Find the start and end, and determine
1351 if we are going to have to recursively call ourselves on the
1353 vars = vare = nextvar + 2;
1357 /* Find the end of it */
1358 while(brackets && *vare) {
1359 if ((vare[0] == '$') && (vare[1] == '{')) {
1362 } else if (vare[0] == '}') {
1364 } else if ((vare[0] == '$') && (vare[1] == '['))
1369 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1370 len = vare - vars - 1;
1372 /* Skip totally over variable string */
1373 whereweare += (len + 3);
1376 var = alloca(VAR_BUF_SIZE);
1378 /* Store variable name (and truncate) */
1379 ast_copy_string(var, vars, len + 1);
1381 /* Substitute if necessary */
1384 ltmp = alloca(VAR_BUF_SIZE);
1386 memset(ltmp, 0, VAR_BUF_SIZE);
1387 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1394 workspace = alloca(VAR_BUF_SIZE);
1396 workspace[0] = '\0';
1398 parse_variable_name(vars, &offset, &offset2, &isfunction);
1400 /* Evaluate function */
1401 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1403 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1405 /* Retrieve variable value */
1406 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1409 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1411 length = strlen(cp4);
1414 memcpy(cp2, cp4, length);
1418 } else if (nextexp) {
1419 /* We have an expression. Find the start and end, and determine
1420 if we are going to have to recursively call ourselves on the
1422 vars = vare = nextexp + 2;
1426 /* Find the end of it */
1427 while(brackets && *vare) {
1428 if ((vare[0] == '$') && (vare[1] == '[')) {
1432 } else if (vare[0] == '[') {
1434 } else if (vare[0] == ']') {
1436 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1443 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1444 len = vare - vars - 1;
1446 /* Skip totally over expression */
1447 whereweare += (len + 3);
1450 var = alloca(VAR_BUF_SIZE);
1452 /* Store variable name (and truncate) */
1453 ast_copy_string(var, vars, len + 1);
1455 /* Substitute if necessary */
1458 ltmp = alloca(VAR_BUF_SIZE);
1460 memset(ltmp, 0, VAR_BUF_SIZE);
1461 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1467 length = ast_expr(vars, cp2, count);
1470 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1479 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1481 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1484 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1486 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1489 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1491 memset(passdata, 0, datalen);
1493 /* No variables or expressions in e->data, so why scan it? */
1494 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1495 ast_copy_string(passdata, e->data, datalen);
1499 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1502 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)
1504 struct ast_exten *e;
1505 struct ast_app *app;
1506 struct ast_switch *sw;
1508 const char *foundcontext=NULL;
1511 char *incstack[AST_PBX_MAX_STACK];
1512 char passdata[EXT_DATA_SIZE];
1516 char tmp3[EXT_DATA_SIZE];
1518 char atmp2[EXT_DATA_SIZE+100];
1520 if (ast_mutex_lock(&conlock)) {
1521 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1522 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1527 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1530 case HELPER_CANMATCH:
1531 ast_mutex_unlock(&conlock);
1534 ast_mutex_unlock(&conlock);
1536 case HELPER_FINDLABEL:
1538 ast_mutex_unlock(&conlock);
1540 case HELPER_MATCHMORE:
1541 ast_mutex_unlock(&conlock);
1544 app = pbx_findapp(e->app);
1545 ast_mutex_unlock(&conlock);
1547 if (c->context != context)
1548 ast_copy_string(c->context, context, sizeof(c->context));
1549 if (c->exten != exten)
1550 ast_copy_string(c->exten, exten, sizeof(c->exten));
1551 c->priority = priority;
1552 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1554 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1555 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1556 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, passdata, "in new stack");
1557 pbx_builtin_setvar_helper(c, atmp, atmp2);
1559 if (option_verbose > 2)
1560 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1561 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1562 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1563 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1565 manager_event(EVENT_FLAG_CALL, "Newexten",
1570 "Application: %s\r\n"
1573 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1574 res = pbx_exec(c, app, passdata);
1577 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1581 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1586 case HELPER_CANMATCH:
1587 ast_mutex_unlock(&conlock);
1590 ast_mutex_unlock(&conlock);
1592 case HELPER_MATCHMORE:
1593 ast_mutex_unlock(&conlock);
1595 case HELPER_FINDLABEL:
1596 ast_mutex_unlock(&conlock);
1599 ast_mutex_unlock(&conlock);
1601 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, data);
1603 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1608 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1612 ast_mutex_unlock(&conlock);
1614 case STATUS_NO_CONTEXT:
1615 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1616 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1618 case STATUS_NO_EXTENSION:
1619 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1620 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1622 case STATUS_NO_PRIORITY:
1623 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1624 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1626 case STATUS_NO_LABEL:
1628 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1631 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1634 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1642 /*! \brief ast_hint_extension: Find hint for given extension in context */
1643 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1645 struct ast_exten *e;
1646 struct ast_switch *sw;
1648 const char *foundcontext = NULL;
1650 char *incstack[AST_PBX_MAX_STACK];
1653 if (ast_mutex_lock(&conlock)) {
1654 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1657 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1658 ast_mutex_unlock(&conlock);
1662 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1663 static int ast_extension_state2(struct ast_exten *e)
1665 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 rest = hint; /* One or more devices separated with a & character */
1676 while ( (cur = strsep(&rest, "&")) ) {
1677 int res = ast_device_state(cur);
1679 case AST_DEVICE_NOT_INUSE:
1683 case AST_DEVICE_INUSE:
1688 case AST_DEVICE_RINGING:
1693 case AST_DEVICE_BUSY:
1698 case AST_DEVICE_UNAVAILABLE:
1699 case AST_DEVICE_INVALID:
1711 return AST_EXTENSION_RINGING;
1713 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1715 return AST_EXTENSION_INUSE;
1717 return AST_EXTENSION_NOT_INUSE;
1719 return AST_EXTENSION_BUSY;
1721 return AST_EXTENSION_UNAVAILABLE;
1723 return AST_EXTENSION_INUSE;
1725 return AST_EXTENSION_NOT_INUSE;
1728 /*! \brief ast_extension_state2str: Return extension_state as string */
1729 const char *ast_extension_state2str(int extension_state)
1733 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1734 if (extension_states[i].extension_state == extension_state)
1735 return extension_states[i].text;
1740 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1741 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1743 struct ast_exten *e;
1745 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1747 return -1; /* No hint, return -1 */
1749 return ast_extension_state2(e); /* Check all devices in the hint */
1752 void ast_hint_state_changed(const char *device)
1754 struct ast_hint *hint;
1755 struct ast_state_cb *cblist;
1756 char buf[AST_MAX_EXTENSION];
1761 AST_LIST_LOCK(&hints);
1763 AST_LIST_TRAVERSE(&hints, hint, list) {
1764 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1766 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1767 if (strcasecmp(cur, device))
1770 /* Get device state for this hint */
1771 state = ast_extension_state2(hint->exten);
1773 if ((state == -1) || (state == hint->laststate))
1776 /* Device state changed since last check - notify the watchers */
1778 /* For general callbacks */
1779 for (cblist = statecbs; cblist; cblist = cblist->next)
1780 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1782 /* For extension callbacks */
1783 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1784 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1786 hint->laststate = state;
1791 AST_LIST_UNLOCK(&hints);
1794 /*! \brief ast_extension_state_add: Add watcher for extension states */
1795 int ast_extension_state_add(const char *context, const char *exten,
1796 ast_state_cb_type callback, void *data)
1798 struct ast_hint *hint;
1799 struct ast_state_cb *cblist;
1800 struct ast_exten *e;
1802 /* If there's no context and extension: add callback to statecbs list */
1803 if (!context && !exten) {
1804 AST_LIST_LOCK(&hints);
1806 for (cblist = statecbs; cblist; cblist = cblist->next) {
1807 if (cblist->callback == callback) {
1808 cblist->data = data;
1809 AST_LIST_UNLOCK(&hints);
1814 /* Now insert the callback */
1815 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1816 AST_LIST_UNLOCK(&hints);
1820 cblist->callback = callback;
1821 cblist->data = data;
1823 cblist->next = statecbs;
1826 AST_LIST_UNLOCK(&hints);
1830 if (!context || !exten)
1833 /* This callback type is for only one hint, so get the hint */
1834 e = ast_hint_extension(NULL, context, exten);
1839 /* Find the hint in the list of hints */
1840 AST_LIST_LOCK(&hints);
1842 AST_LIST_TRAVERSE(&hints, hint, list) {
1843 if (hint->exten == e)
1848 /* We have no hint, sorry */
1849 AST_LIST_UNLOCK(&hints);
1853 /* Now insert the callback in the callback list */
1854 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1855 AST_LIST_UNLOCK(&hints);
1858 cblist->id = stateid++; /* Unique ID for this callback */
1859 cblist->callback = callback; /* Pointer to callback routine */
1860 cblist->data = data; /* Data for the callback */
1862 cblist->next = hint->callbacks;
1863 hint->callbacks = cblist;
1865 AST_LIST_UNLOCK(&hints);
1869 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1870 int ast_extension_state_del(int id, ast_state_cb_type callback)
1872 struct ast_hint *hint;
1873 struct ast_state_cb *cblist, *cbprev;
1875 if (!id && !callback)
1878 AST_LIST_LOCK(&hints);
1880 /* id is zero is a callback without extension */
1883 for (cblist = statecbs; cblist; cblist = cblist->next) {
1884 if (cblist->callback == callback) {
1886 statecbs = cblist->next;
1888 cbprev->next = cblist->next;
1892 AST_LIST_UNLOCK(&hints);
1898 AST_LIST_UNLOCK(&hints);
1902 /* id greater than zero is a callback with extension */
1903 /* Find the callback based on ID */
1904 AST_LIST_TRAVERSE(&hints, hint, list) {
1906 for (cblist = hint->callbacks; cblist; cblist = cblist->next) {
1907 if (cblist->id==id) {
1909 hint->callbacks = cblist->next;
1911 cbprev->next = cblist->next;
1915 AST_LIST_UNLOCK(&hints);
1922 AST_LIST_UNLOCK(&hints);
1926 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
1927 static int ast_add_hint(struct ast_exten *e)
1929 struct ast_hint *hint;
1934 AST_LIST_LOCK(&hints);
1936 /* Search if hint exists, do nothing */
1937 AST_LIST_TRAVERSE(&hints, hint, list) {
1938 if (hint->exten == e) {
1939 AST_LIST_UNLOCK(&hints);
1940 if (option_debug > 1)
1941 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1946 if (option_debug > 1)
1947 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1949 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
1950 AST_LIST_UNLOCK(&hints);
1953 /* Initialize and insert new item at the top */
1955 hint->laststate = ast_extension_state2(e);
1956 AST_LIST_INSERT_HEAD(&hints, hint, list);
1958 AST_LIST_UNLOCK(&hints);
1962 /*! \brief ast_change_hint: Change hint for an extension */
1963 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1965 struct ast_hint *hint;
1968 AST_LIST_LOCK(&hints);
1969 AST_LIST_TRAVERSE(&hints, hint, list) {
1970 if (hint->exten == oe) {
1976 AST_LIST_UNLOCK(&hints);
1981 /*! \brief ast_remove_hint: Remove hint from extension */
1982 static int ast_remove_hint(struct ast_exten *e)
1984 /* Cleanup the Notifys if hint is removed */
1985 struct ast_hint *hint;
1986 struct ast_state_cb *cblist, *cbprev;
1992 AST_LIST_LOCK(&hints);
1993 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
1994 if (hint->exten == e) {
1996 cblist = hint->callbacks;
1998 /* Notify with -1 and remove all callbacks */
2000 cblist = cblist->next;
2001 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2004 hint->callbacks = NULL;
2005 AST_LIST_REMOVE_CURRENT(&hints, list);
2011 AST_LIST_TRAVERSE_SAFE_END
2012 AST_LIST_UNLOCK(&hints);
2018 /*! \brief ast_get_hint: Get hint for channel */
2019 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2021 struct ast_exten *e = ast_hint_extension(c, context, exten);
2025 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2027 const char *tmp = ast_get_extension_app_data(e);
2029 ast_copy_string(name, tmp, namesize);
2036 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2038 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2041 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2043 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2046 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2048 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2051 int ast_canmatch_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_CANMATCH);
2056 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2058 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2061 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2063 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2066 static int __ast_pbx_run(struct ast_channel *c)
2076 /* A little initial setup here */
2078 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2079 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2083 c->cdr = ast_cdr_alloc();
2085 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2089 ast_cdr_init(c->cdr, c);
2092 /* Set reasonable defaults */
2093 c->pbx->rtimeout = 10;
2094 c->pbx->dtimeout = 5;
2096 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2097 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2099 /* Start by trying whatever the channel is set to */
2100 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2101 /* If not successful fall back to 's' */
2102 if (option_verbose > 1)
2103 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);
2104 ast_copy_string(c->exten, "s", sizeof(c->exten));
2105 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2106 /* JK02: And finally back to default if everything else failed */
2107 if (option_verbose > 1)
2108 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);
2109 ast_copy_string(c->context, "default", sizeof(c->context));
2113 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2114 ast_cdr_start(c->cdr);
2118 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2119 memset(exten, 0, sizeof(exten));
2120 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2121 /* Something bad happened, or a hangup has been requested. */
2122 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2123 (res == '*') || (res == '#')) {
2124 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2125 memset(exten, 0, sizeof(exten));
2127 exten[pos++] = digit = res;
2131 case AST_PBX_KEEPALIVE:
2133 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2134 else if (option_verbose > 1)
2135 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2140 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2141 else if (option_verbose > 1)
2142 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2143 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2148 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2158 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2159 ast_copy_string(c->exten, "T", sizeof(c->exten));
2160 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2161 c->whentohangup = 0;
2163 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2164 } else if (c->_softhangup) {
2165 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2166 c->exten, c->priority);
2172 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2173 /* It's not a valid extension anymore */
2174 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2175 if (option_verbose > 2)
2176 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2177 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2178 ast_copy_string(c->exten, "i", sizeof(c->exten));
2181 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2182 c->name, c->exten, c->context);
2185 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2186 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2189 /* Done, wait for an extension */
2192 waittime = c->pbx->dtimeout;
2193 else if (!autofallthrough)
2194 waittime = c->pbx->rtimeout;
2196 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2197 /* As long as we're willing to wait, and as long as it's not defined,
2198 keep reading digits until we can't possibly get a right answer anymore. */
2199 digit = ast_waitfordigit(c, waittime * 1000);
2200 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2207 /* Error, maybe a hangup */
2209 exten[pos++] = digit;
2210 waittime = c->pbx->dtimeout;
2213 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2214 /* Prepare the next cycle */
2215 ast_copy_string(c->exten, exten, sizeof(c->exten));
2218 /* No such extension */
2219 if (!ast_strlen_zero(exten)) {
2220 /* An invalid extension */
2221 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2222 if (option_verbose > 2)
2223 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2224 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2225 ast_copy_string(c->exten, "i", sizeof(c->exten));
2228 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2232 /* A simple timeout */
2233 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2234 if (option_verbose > 2)
2235 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2236 ast_copy_string(c->exten, "t", sizeof(c->exten));
2239 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2245 if (option_verbose > 2)
2246 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2252 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2255 if (option_verbose > 2)
2256 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2257 if (!strcasecmp(status, "CONGESTION"))
2258 res = pbx_builtin_congestion(c, "10");
2259 else if (!strcasecmp(status, "CHANUNAVAIL"))
2260 res = pbx_builtin_congestion(c, "10");
2261 else if (!strcasecmp(status, "BUSY"))
2262 res = pbx_builtin_busy(c, "10");
2268 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2270 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2271 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2272 ast_cdr_end(c->cdr);
2276 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2277 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2278 /* Something bad happened, or a hangup has been requested. */
2280 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2281 else if (option_verbose > 1)
2282 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2288 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2290 pbx_destroy(c->pbx);
2292 if (res != AST_PBX_KEEPALIVE)
2297 /* Returns 0 on success, non-zero if call limit was reached */
2298 static int increase_call_count(const struct ast_channel *c)
2302 ast_mutex_lock(&maxcalllock);
2303 if (option_maxcalls) {
2304 if (countcalls >= option_maxcalls) {
2305 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2309 if (option_maxload) {
2310 getloadavg(&curloadavg, 1);
2311 if (curloadavg >= option_maxload) {
2312 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2318 ast_mutex_unlock(&maxcalllock);
2323 static void decrease_call_count(void)
2325 ast_mutex_lock(&maxcalllock);
2328 ast_mutex_unlock(&maxcalllock);
2331 static void *pbx_thread(void *data)
2333 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2334 answer this channel and get it going.
2337 The launcher of this function _MUST_ increment 'countcalls'
2338 before invoking the function; it will be decremented when the
2339 PBX has finished running on the channel
2341 struct ast_channel *c = data;
2344 decrease_call_count();
2351 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2354 pthread_attr_t attr;
2357 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2358 return AST_PBX_FAILED;
2361 if (increase_call_count(c))
2362 return AST_PBX_CALL_LIMIT;
2364 /* Start a new thread, and get something handling this channel. */
2365 pthread_attr_init(&attr);
2366 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2367 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2368 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2369 return AST_PBX_FAILED;
2372 return AST_PBX_SUCCESS;
2375 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2377 enum ast_pbx_result res = AST_PBX_SUCCESS;
2379 if (increase_call_count(c))
2380 return AST_PBX_CALL_LIMIT;
2382 res = __ast_pbx_run(c);
2383 decrease_call_count();
2388 int ast_active_calls(void)
2393 int pbx_set_autofallthrough(int newval)
2395 int oldval = autofallthrough;
2396 autofallthrough = newval;
2401 * This function locks contexts list by &conlist, search for the right context
2402 * structure, leave context list locked and call ast_context_remove_include2
2403 * which removes include, unlock contexts list and return ...
2405 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2407 struct ast_context *c = NULL;
2409 if (ast_lock_contexts())
2412 /* walk contexts and search for the right one ...*/
2413 while ( (c = ast_walk_contexts(c)) ) {
2414 /* we found one ... */
2415 if (!strcmp(ast_get_context_name(c), context)) {
2417 /* remove include from this context ... */
2418 ret = ast_context_remove_include2(c, include, registrar);
2420 ast_unlock_contexts();
2422 /* ... return results */
2427 /* we can't find the right one context */
2428 ast_unlock_contexts();
2433 * When we call this function, &conlock lock must be locked, because when
2434 * we giving *con argument, some process can remove/change this context
2435 * and after that there can be segfault.
2437 * This function locks given context, removes include, unlock context and
2440 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2442 struct ast_include *i, *pi = NULL;
2444 if (ast_mutex_lock(&con->lock))
2448 for (i = con->includes; i; pi = i, i = i->next) {
2449 /* find our include */
2450 if (!strcmp(i->name, include) &&
2451 (!registrar || !strcmp(i->registrar, registrar))) {
2452 /* remove from list */
2456 con->includes = i->next;
2457 /* free include and return */
2459 ast_mutex_unlock(&con->lock);
2464 /* we can't find the right include */
2465 ast_mutex_unlock(&con->lock);
2470 * \note This function locks contexts list by &conlist, search for the rigt context
2471 * structure, leave context list locked and call ast_context_remove_switch2
2472 * which removes switch, unlock contexts list and return ...
2474 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2476 struct ast_context *c = NULL;
2477 int ret = -1; /* default error return */
2479 if (ast_lock_contexts())
2482 /* walk contexts and search for the right one ...*/
2483 while ( (c = ast_walk_contexts(c)) ) {
2484 /* we found one ... */
2485 if (!strcmp(ast_get_context_name(c), context)) {
2486 /* remove switch from this context ... */
2487 ret = ast_context_remove_switch2(c, sw, data, registrar);
2492 /* found or error */
2493 ast_unlock_contexts();
2498 * \brief This function locks given context, removes switch, unlock context and
2500 * \note When we call this function, &conlock lock must be locked, because when
2501 * we giving *con argument, some process can remove/change this context
2502 * and after that there can be segfault.
2505 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2507 struct ast_sw *i, *pi = NULL;
2509 if (ast_mutex_lock(&con->lock)) return -1;
2512 for (i = con->alts; i; pi = i, i = i->next) {
2513 /* find our switch */
2514 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2515 (!registrar || !strcmp(i->registrar, registrar))) {
2516 /* remove from list */
2520 con->alts = i->next;
2521 /* free switch and return */
2523 ast_mutex_unlock(&con->lock);
2528 /* we can't find the right switch */
2529 ast_mutex_unlock(&con->lock);
2534 * \note This functions lock contexts list, search for the right context,
2535 * call ast_context_remove_extension2, unlock contexts list and return.
2536 * In this function we are using
2538 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2540 struct ast_context *c = NULL;
2541 int ret = -1; /* default error return */
2543 if (ast_lock_contexts())
2546 /* walk contexts ... */
2547 while ( (c = ast_walk_contexts(c)) ) {
2548 /* ... search for the right one ... */
2549 if (!strcmp(ast_get_context_name(c), context)) {
2550 /* ... remove extension ... */
2551 ret = ast_context_remove_extension2(c, extension, priority,
2556 /* found or error */
2557 ast_unlock_contexts();
2562 * \brief This functionc locks given context, search for the right extension and
2563 * fires out all peer in this extensions with given priority. If priority
2564 * is set to 0, all peers are removed. After that, unlock context and
2566 * \note When do you want to call this function, make sure that &conlock is locked,
2567 * because some process can handle with your *con context before you lock
2571 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2573 struct ast_exten *exten, *prev_exten = NULL;
2575 if (ast_mutex_lock(&con->lock))
2578 /* go through all extensions in context and search the right one ... */
2582 /* look for right extension */
2583 if (!strcmp(exten->exten, extension) &&
2584 (!registrar || !strcmp(exten->registrar, registrar))) {
2585 struct ast_exten *peer;
2587 /* should we free all peers in this extension? (priority == 0)? */
2588 if (priority == 0) {
2589 /* remove this extension from context list */
2591 prev_exten->next = exten->next;
2593 con->root = exten->next;
2595 /* fire out all peers */
2600 if (!peer->priority==PRIORITY_HINT)
2601 ast_remove_hint(peer);
2603 peer->datad(peer->data);
2609 ast_mutex_unlock(&con->lock);
2612 /* remove only extension with exten->priority == priority */
2613 struct ast_exten *previous_peer = NULL;
2617 /* is this our extension? */
2618 if (peer->priority == priority &&
2619 (!registrar || !strcmp(peer->registrar, registrar) )) {
2620 /* we are first priority extension? */
2621 if (!previous_peer) {
2622 /* exists previous extension here? */
2624 /* yes, so we must change next pointer in
2625 * previous connection to next peer
2628 prev_exten->next = peer->peer;
2629 peer->peer->next = exten->next;
2631 prev_exten->next = exten->next;
2633 /* no previous extension, we are first
2634 * extension, so change con->root ...
2637 con->root = peer->peer;
2639 con->root = exten->next;
2642 /* we are not first priority in extension */
2643 previous_peer->peer = peer->peer;
2646 /* now, free whole priority extension */
2647 if (peer->priority==PRIORITY_HINT)
2648 ast_remove_hint(peer);
2649 peer->datad(peer->data);
2652 ast_mutex_unlock(&con->lock);
2655 /* this is not right extension, skip to next peer */
2656 previous_peer = peer;
2661 ast_mutex_unlock(&con->lock);
2667 exten = exten->next;
2670 /* we can't find right extension */
2671 ast_mutex_unlock(&con->lock);
2676 /*! \brief Dynamically register a new dial plan application */
2677 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2679 struct ast_app *tmp, *prev, *cur;
2682 length = sizeof(struct ast_app);
2683 length += strlen(app) + 1;
2684 if (ast_mutex_lock(&applock)) {
2685 ast_log(LOG_ERROR, "Unable to lock application list\n");
2688 for (tmp = apps; tmp; tmp = tmp->next) {
2689 if (!strcasecmp(app, tmp->name)) {
2690 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2691 ast_mutex_unlock(&applock);
2696 if (!(tmp = ast_calloc(1, length))) {
2697 ast_mutex_unlock(&applock);
2701 strcpy(tmp->name, app);
2702 tmp->execute = execute;
2703 tmp->synopsis = synopsis;
2704 tmp->description = description;
2705 /* Store in alphabetical order */
2707 for (cur = apps; cur; cur = cur->next) {
2708 if (strcasecmp(tmp->name, cur->name) < 0)
2713 tmp->next = prev->next;
2720 if (option_verbose > 1)
2721 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2722 ast_mutex_unlock(&applock);
2726 int ast_register_switch(struct ast_switch *sw)
2728 struct ast_switch *tmp, *prev=NULL;
2729 if (ast_mutex_lock(&switchlock)) {
2730 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2733 for (tmp = switches; tmp; prev = tmp, tmp = tmp->next) {
2734 if (!strcasecmp(tmp->name, sw->name))
2738 ast_mutex_unlock(&switchlock);
2739 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2747 ast_mutex_unlock(&switchlock);
2751 void ast_unregister_switch(struct ast_switch *sw)
2753 struct ast_switch *tmp, *prev=NULL;
2754 if (ast_mutex_lock(&switchlock)) {
2755 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2758 for (tmp = switches; tmp; prev = tmp, tmp = tmp->next) {
2761 prev->next = tmp->next;
2763 switches = tmp->next;
2768 ast_mutex_unlock(&switchlock);
2772 * Help for CLI commands ...
2774 static char show_application_help[] =
2775 "Usage: show application <application> [<application> [<application> [...]]]\n"
2776 " Describes a particular application.\n";
2778 static char show_functions_help[] =
2779 "Usage: show functions [like <text>]\n"
2780 " List builtin functions, optionally only those matching a given string\n";
2782 static char show_function_help[] =
2783 "Usage: show function <function>\n"
2784 " Describe a particular dialplan function.\n";
2786 static char show_applications_help[] =
2787 "Usage: show applications [{like|describing} <text>]\n"
2788 " List applications which are currently available.\n"
2789 " If 'like', <text> will be a substring of the app name\n"
2790 " If 'describing', <text> will be a substring of the description\n";
2792 static char show_dialplan_help[] =
2793 "Usage: show dialplan [exten@][context]\n"
2796 static char show_switches_help[] =
2797 "Usage: show switches\n"
2798 " Show registered switches\n";
2800 static char show_hints_help[] =
2801 "Usage: show hints\n"
2802 " Show registered hints\n";
2804 static char show_globals_help[] =
2805 "Usage: show globals\n"
2806 " Show current global dialplan variables and their values\n";
2808 static char set_global_help[] =
2809 "Usage: set global <name> <value>\n"
2810 " Set global dialplan variable <name> to <value>\n";
2814 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2819 * \brief 'show application' CLI command implementation functions ...
2823 * There is a possibility to show informations about more than one
2824 * application at one time. You can type 'show application Dial Echo' and
2825 * you will see informations about these two applications ...
2827 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2832 int wordlen = strlen(word);
2834 /* try to lock applications list ... */
2835 if (ast_mutex_lock(&applock)) {
2836 ast_log(LOG_ERROR, "Unable to lock application list\n");
2840 /* return the n-th [partial] matching entry */
2841 for (a = apps; a && !ret; a = a->next) {
2842 if (!strncasecmp(word, a->name, wordlen) && ++which > state)
2843 ret = strdup(a->name);
2846 ast_mutex_unlock(&applock);
2851 static int handle_show_application(int fd, int argc, char *argv[])
2854 int app, no_registered_app = 1;
2856 if (argc < 3) return RESULT_SHOWUSAGE;
2858 /* try to lock applications list ... */
2859 if (ast_mutex_lock(&applock)) {
2860 ast_log(LOG_ERROR, "Unable to lock application list\n");
2864 /* ... go through all applications ... */
2865 for (a = apps; a; a = a->next) {
2866 /* ... compare this application name with all arguments given
2867 * to 'show application' command ... */
2868 for (app = 2; app < argc; app++) {
2869 if (!strcasecmp(a->name, argv[app])) {
2870 /* Maximum number of characters added by terminal coloring is 22 */
2871 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2872 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2873 int synopsis_size, description_size;
2875 no_registered_app = 0;
2878 synopsis_size = strlen(a->synopsis) + 23;
2880 synopsis_size = strlen("Not available") + 23;
2881 synopsis = alloca(synopsis_size);
2884 description_size = strlen(a->description) + 23;
2886 description_size = strlen("Not available") + 23;
2887 description = alloca(description_size);
2889 if (synopsis && description) {
2890 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2891 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2892 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2893 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2894 term_color(synopsis,
2895 a->synopsis ? a->synopsis : "Not available",
2896 COLOR_CYAN, 0, synopsis_size);
2897 term_color(description,
2898 a->description ? a->description : "Not available",
2899 COLOR_CYAN, 0, description_size);
2901 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2903 /* ... one of our applications, show info ...*/
2904 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2905 "[Synopsis]\n %s\n\n"
2906 "[Description]\n%s\n",
2908 a->synopsis ? a->synopsis : "Not available",
2909 a->description ? a->description : "Not available");
2915 ast_mutex_unlock(&applock);
2917 /* we found at least one app? no? */
2918 if (no_registered_app) {
2919 ast_cli(fd, "Your application(s) is (are) not registered\n");
2920 return RESULT_FAILURE;
2923 return RESULT_SUCCESS;
2926 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2927 static int handle_show_hints(int fd, int argc, char *argv[])
2929 struct ast_hint *hint;
2932 struct ast_state_cb *watcher;
2934 if (AST_LIST_EMPTY(&hints)) {
2935 ast_cli(fd, "There are no registered dialplan hints\n");
2936 return RESULT_SUCCESS;
2938 /* ... we have hints ... */
2939 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2940 if (AST_LIST_LOCK(&hints)) {
2941 ast_log(LOG_ERROR, "Unable to lock hints\n");
2944 AST_LIST_TRAVERSE(&hints, hint, list) {
2946 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2948 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2949 ast_get_extension_name(hint->exten),
2950 ast_get_context_name(ast_get_extension_context(hint->exten)),
2951 ast_get_extension_app(hint->exten),
2952 ast_extension_state2str(hint->laststate), watchers);
2955 ast_cli(fd, "----------------\n");
2956 ast_cli(fd, "- %d hints registered\n", num);
2957 AST_LIST_UNLOCK(&hints);
2958 return RESULT_SUCCESS;
2961 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2962 static int handle_show_switches(int fd, int argc, char *argv[])
2964 struct ast_switch *sw;
2966 ast_cli(fd, "There are no registered alternative switches\n");
2967 return RESULT_SUCCESS;
2969 /* ... we have applications ... */
2970 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2971 if (ast_mutex_lock(&switchlock)) {
2972 ast_log(LOG_ERROR, "Unable to lock switches\n");
2975 for (sw = switches; sw; sw = sw->next)
2976 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2977 ast_mutex_unlock(&switchlock);
2978 return RESULT_SUCCESS;
2982 * 'show applications' CLI command implementation functions ...
2984 static int handle_show_applications(int fd, int argc, char *argv[])
2987 int like = 0, describing = 0;
2988 int total_match = 0; /* Number of matches in like clause */
2989 int total_apps = 0; /* Number of apps registered */
2991 /* try to lock applications list ... */
2992 if (ast_mutex_lock(&applock)) {
2993 ast_log(LOG_ERROR, "Unable to lock application list\n");
2997 /* ... have we got at least one application (first)? no? */
2999 ast_cli(fd, "There are no registered applications\n");
3000 ast_mutex_unlock(&applock);
3004 /* show applications like <keyword> */
3005 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3007 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3011 /* show applications describing <keyword1> [<keyword2>] [...] */
3012 if ((!like) && (!describing)) {
3013 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3015 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3018 /* ... go through all applications ... */
3019 for (a = apps; a; a = a->next) {
3020 /* ... show informations about applications ... */
3024 if (strcasestr(a->name, argv[3])) {
3028 } else if (describing) {
3029 if (a->description) {
3030 /* Match all words on command line */
3033 for (i = 3; i < argc; i++) {
3034 if (!strcasestr(a->description, argv[i])) {
3046 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3049 if ((!like) && (!describing)) {
3050 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3052 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3055 /* ... unlock and return */
3056 ast_mutex_unlock(&applock);
3058 return RESULT_SUCCESS;
3061 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3063 static char* choices[] = { "like", "describing", NULL };
3065 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);