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;
1030 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1032 } else if (argc != 2) {
1033 return RESULT_SHOWUSAGE;
1036 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1038 for (acf = acf_root ; acf; acf = acf->next) {
1039 if (!like || strstr(acf->name, argv[3])) {
1041 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1045 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1050 static int handle_show_function(int fd, int argc, char *argv[])
1052 struct ast_custom_function *acf;
1053 /* Maximum number of characters added by terminal coloring is 22 */
1054 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1055 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1056 char stxtitle[40], *syntax = NULL;
1057 int synopsis_size, description_size, syntax_size;
1060 return RESULT_SHOWUSAGE;
1062 if (!(acf = ast_custom_function_find(argv[2]))) {
1063 ast_cli(fd, "No function by that name registered.\n");
1064 return RESULT_FAILURE;
1069 synopsis_size = strlen(acf->synopsis) + 23;
1071 synopsis_size = strlen("Not available") + 23;
1072 synopsis = alloca(synopsis_size);
1075 description_size = strlen(acf->desc) + 23;
1077 description_size = strlen("Not available") + 23;
1078 description = alloca(description_size);
1081 syntax_size = strlen(acf->syntax) + 23;
1083 syntax_size = strlen("Not available") + 23;
1084 syntax = alloca(syntax_size);
1086 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1087 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1088 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1089 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1090 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1092 acf->syntax ? acf->syntax : "Not available",
1093 COLOR_CYAN, 0, syntax_size);
1094 term_color(synopsis,
1095 acf->synopsis ? acf->synopsis : "Not available",
1096 COLOR_CYAN, 0, synopsis_size);
1097 term_color(description,
1098 acf->desc ? acf->desc : "Not available",
1099 COLOR_CYAN, 0, description_size);
1101 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1103 return RESULT_SUCCESS;
1106 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1108 struct ast_custom_function *acf;
1111 int wordlen = strlen(word);
1113 /* try to lock functions list ... */
1114 if (ast_mutex_lock(&acflock)) {
1115 ast_log(LOG_ERROR, "Unable to lock function list\n");
1119 /* case-insensitive for convenience in this 'complete' function */
1120 for (acf = acf_root; acf && !ret; acf = acf->next) {
1121 if (!strncasecmp(word, acf->name, wordlen) && ++which > state)
1122 ret = strdup(acf->name);
1125 ast_mutex_unlock(&acflock);
1130 struct ast_custom_function* ast_custom_function_find(const char *name)
1132 struct ast_custom_function *acfptr;
1134 /* try to lock functions list ... */
1135 if (ast_mutex_lock(&acflock)) {
1136 ast_log(LOG_ERROR, "Unable to lock function list\n");
1140 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1141 if (!strcmp(name, acfptr->name))
1145 ast_mutex_unlock(&acflock);
1150 int ast_custom_function_unregister(struct ast_custom_function *acf)
1152 struct ast_custom_function *cur, *prev = NULL;
1158 /* try to lock functions list ... */
1159 if (ast_mutex_lock(&acflock)) {
1160 ast_log(LOG_ERROR, "Unable to lock function list\n");
1164 for (cur = acf_root; cur; prev = cur, cur = cur->next) {
1167 prev->next = acf->next;
1169 acf_root = acf->next;
1175 ast_mutex_unlock(&acflock);
1177 if (!res && option_verbose > 1)
1178 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1183 int ast_custom_function_register(struct ast_custom_function *acf)
1185 struct ast_custom_function *cur, *last = NULL;
1191 /* try to lock functions list ... */
1192 if (ast_mutex_lock(&acflock)) {
1193 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
1197 if (ast_custom_function_find(acf->name)) {
1198 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1199 ast_mutex_unlock(&acflock);
1203 for (cur = acf_root; cur; cur = cur->next) {
1204 if (strcmp(acf->name, cur->name) < 0) {
1210 acf->next = acf_root;
1218 /* Wasn't before anything else, put it at the end */
1227 ast_mutex_unlock(&acflock);
1229 if (option_verbose > 1)
1230 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1235 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1237 char *args = NULL, *p;
1238 struct ast_custom_function *acfptr;
1240 if ((args = strchr(function, '('))) {
1242 if ((p = strrchr(args, ')')))
1245 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1247 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1250 if ((acfptr = ast_custom_function_find(function))) {
1251 /* run the custom function */
1253 return acfptr->read(chan, function, args, workspace, len);
1255 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1257 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1263 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1265 char *args = NULL, *p;
1266 struct ast_custom_function *acfptr;
1268 if ((args = strchr(function, '('))) {
1270 if ((p = strrchr(args, ')')))
1273 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1275 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1278 if ((acfptr = ast_custom_function_find(function))) {
1279 /* run the custom function */
1281 return acfptr->write(chan, function, args, value);
1283 ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
1285 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1291 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1294 const char *tmp, *whereweare;
1295 int length, offset, offset2, isfunction;
1296 char *workspace = NULL;
1297 char *ltmp = NULL, *var = NULL;
1298 char *nextvar, *nextexp, *nextthing;
1300 int pos, brackets, needsub, len;
1302 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1305 while(!ast_strlen_zero(whereweare) && count) {
1306 /* Assume we're copying the whole remaining string */
1307 pos = strlen(whereweare);
1310 nextthing = strchr(whereweare, '$');
1312 switch(nextthing[1]) {
1314 nextvar = nextthing;
1315 pos = nextvar - whereweare;
1318 nextexp = nextthing;
1319 pos = nextexp - whereweare;
1325 /* Can't copy more than 'count' bytes */
1329 /* Copy that many bytes */
1330 memcpy(cp2, whereweare, pos);
1338 /* We have a variable. Find the start and end, and determine
1339 if we are going to have to recursively call ourselves on the
1341 vars = vare = nextvar + 2;
1345 /* Find the end of it */
1346 while (brackets && *vare) {
1347 if ((vare[0] == '$') && (vare[1] == '{')) {
1349 } else if (vare[0] == '{') {
1351 } else if (vare[0] == '}') {
1353 } else if ((vare[0] == '$') && (vare[1] == '['))
1358 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1359 len = vare - vars - 1;
1361 /* Skip totally over variable string */
1362 whereweare += (len + 3);
1365 var = alloca(VAR_BUF_SIZE);
1367 /* Store variable name (and truncate) */
1368 ast_copy_string(var, vars, len + 1);
1370 /* Substitute if necessary */
1373 ltmp = alloca(VAR_BUF_SIZE);
1375 memset(ltmp, 0, VAR_BUF_SIZE);
1376 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1383 workspace = alloca(VAR_BUF_SIZE);
1385 workspace[0] = '\0';
1387 parse_variable_name(vars, &offset, &offset2, &isfunction);
1389 /* Evaluate function */
1390 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1392 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1394 /* Retrieve variable value */
1395 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1398 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1400 length = strlen(cp4);
1403 memcpy(cp2, cp4, length);
1407 } else if (nextexp) {
1408 /* We have an expression. Find the start and end, and determine
1409 if we are going to have to recursively call ourselves on the
1411 vars = vare = nextexp + 2;
1415 /* Find the end of it */
1416 while(brackets && *vare) {
1417 if ((vare[0] == '$') && (vare[1] == '[')) {
1421 } else if (vare[0] == '[') {
1423 } else if (vare[0] == ']') {
1425 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1432 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1433 len = vare - vars - 1;
1435 /* Skip totally over expression */
1436 whereweare += (len + 3);
1439 var = alloca(VAR_BUF_SIZE);
1441 /* Store variable name (and truncate) */
1442 ast_copy_string(var, vars, len + 1);
1444 /* Substitute if necessary */
1447 ltmp = alloca(VAR_BUF_SIZE);
1449 memset(ltmp, 0, VAR_BUF_SIZE);
1450 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1456 length = ast_expr(vars, cp2, count);
1459 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1468 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1470 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1473 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1475 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1478 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1480 memset(passdata, 0, datalen);
1482 /* No variables or expressions in e->data, so why scan it? */
1483 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1484 ast_copy_string(passdata, e->data, datalen);
1488 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1491 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)
1493 struct ast_exten *e;
1494 struct ast_app *app;
1495 struct ast_switch *sw;
1497 const char *foundcontext=NULL;
1500 char *incstack[AST_PBX_MAX_STACK];
1501 char passdata[EXT_DATA_SIZE];
1505 char tmp3[EXT_DATA_SIZE];
1507 char atmp2[EXT_DATA_SIZE+100];
1509 if (ast_mutex_lock(&conlock)) {
1510 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1511 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1516 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1519 case HELPER_CANMATCH:
1520 ast_mutex_unlock(&conlock);
1523 ast_mutex_unlock(&conlock);
1525 case HELPER_FINDLABEL:
1527 ast_mutex_unlock(&conlock);
1529 case HELPER_MATCHMORE:
1530 ast_mutex_unlock(&conlock);
1533 app = pbx_findapp(e->app);
1534 ast_mutex_unlock(&conlock);
1536 if (c->context != context)
1537 ast_copy_string(c->context, context, sizeof(c->context));
1538 if (c->exten != exten)
1539 ast_copy_string(c->exten, exten, sizeof(c->exten));
1540 c->priority = priority;
1541 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1543 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1544 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1545 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, passdata, "in new stack");
1546 pbx_builtin_setvar_helper(c, atmp, atmp2);
1548 if (option_verbose > 2)
1549 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1550 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1551 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1552 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1554 manager_event(EVENT_FLAG_CALL, "Newexten",
1559 "Application: %s\r\n"
1562 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1563 res = pbx_exec(c, app, passdata);
1566 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1570 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1575 case HELPER_CANMATCH:
1576 ast_mutex_unlock(&conlock);
1579 ast_mutex_unlock(&conlock);
1581 case HELPER_MATCHMORE:
1582 ast_mutex_unlock(&conlock);
1584 case HELPER_FINDLABEL:
1585 ast_mutex_unlock(&conlock);
1588 ast_mutex_unlock(&conlock);
1590 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, data);
1592 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1597 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1601 ast_mutex_unlock(&conlock);
1603 case STATUS_NO_CONTEXT:
1604 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1605 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1607 case STATUS_NO_EXTENSION:
1608 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1609 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1611 case STATUS_NO_PRIORITY:
1612 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1613 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1615 case STATUS_NO_LABEL:
1617 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1620 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1623 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1631 /*! \brief ast_hint_extension: Find hint for given extension in context */
1632 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1634 struct ast_exten *e;
1635 struct ast_switch *sw;
1637 const char *foundcontext = NULL;
1639 char *incstack[AST_PBX_MAX_STACK];
1642 if (ast_mutex_lock(&conlock)) {
1643 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1646 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1647 ast_mutex_unlock(&conlock);
1651 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1652 static int ast_extension_state2(struct ast_exten *e)
1654 char hint[AST_MAX_EXTENSION];
1656 int allunavailable = 1, allbusy = 1, allfree = 1;
1657 int busy = 0, inuse = 0, ring = 0;
1662 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1664 rest = hint; /* One or more devices separated with a & character */
1665 while ( (cur = strsep(&rest, "&")) ) {
1666 int res = ast_device_state(cur);
1668 case AST_DEVICE_NOT_INUSE:
1672 case AST_DEVICE_INUSE:
1677 case AST_DEVICE_RINGING:
1682 case AST_DEVICE_BUSY:
1687 case AST_DEVICE_UNAVAILABLE:
1688 case AST_DEVICE_INVALID:
1700 return AST_EXTENSION_RINGING;
1702 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1704 return AST_EXTENSION_INUSE;
1706 return AST_EXTENSION_NOT_INUSE;
1708 return AST_EXTENSION_BUSY;
1710 return AST_EXTENSION_UNAVAILABLE;
1712 return AST_EXTENSION_INUSE;
1714 return AST_EXTENSION_NOT_INUSE;
1717 /*! \brief ast_extension_state2str: Return extension_state as string */
1718 const char *ast_extension_state2str(int extension_state)
1722 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1723 if (extension_states[i].extension_state == extension_state)
1724 return extension_states[i].text;
1729 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1730 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1732 struct ast_exten *e;
1734 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1736 return -1; /* No hint, return -1 */
1738 return ast_extension_state2(e); /* Check all devices in the hint */
1741 void ast_hint_state_changed(const char *device)
1743 struct ast_hint *hint;
1744 struct ast_state_cb *cblist;
1745 char buf[AST_MAX_EXTENSION];
1750 AST_LIST_LOCK(&hints);
1752 AST_LIST_TRAVERSE(&hints, hint, list) {
1753 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1755 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1756 if (strcasecmp(cur, device))
1759 /* Get device state for this hint */
1760 state = ast_extension_state2(hint->exten);
1762 if ((state == -1) || (state == hint->laststate))
1765 /* Device state changed since last check - notify the watchers */
1767 /* For general callbacks */
1768 for (cblist = statecbs; cblist; cblist = cblist->next)
1769 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1771 /* For extension callbacks */
1772 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1773 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1775 hint->laststate = state;
1780 AST_LIST_UNLOCK(&hints);
1783 /*! \brief ast_extension_state_add: Add watcher for extension states */
1784 int ast_extension_state_add(const char *context, const char *exten,
1785 ast_state_cb_type callback, void *data)
1787 struct ast_hint *hint;
1788 struct ast_state_cb *cblist;
1789 struct ast_exten *e;
1791 /* If there's no context and extension: add callback to statecbs list */
1792 if (!context && !exten) {
1793 AST_LIST_LOCK(&hints);
1795 for (cblist = statecbs; cblist; cblist = cblist->next) {
1796 if (cblist->callback == callback) {
1797 cblist->data = data;
1798 AST_LIST_UNLOCK(&hints);
1803 /* Now insert the callback */
1804 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1805 AST_LIST_UNLOCK(&hints);
1809 cblist->callback = callback;
1810 cblist->data = data;
1812 cblist->next = statecbs;
1815 AST_LIST_UNLOCK(&hints);
1819 if (!context || !exten)
1822 /* This callback type is for only one hint, so get the hint */
1823 e = ast_hint_extension(NULL, context, exten);
1828 /* Find the hint in the list of hints */
1829 AST_LIST_LOCK(&hints);
1831 AST_LIST_TRAVERSE(&hints, hint, list) {
1832 if (hint->exten == e)
1837 /* We have no hint, sorry */
1838 AST_LIST_UNLOCK(&hints);
1842 /* Now insert the callback in the callback list */
1843 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1844 AST_LIST_UNLOCK(&hints);
1847 cblist->id = stateid++; /* Unique ID for this callback */
1848 cblist->callback = callback; /* Pointer to callback routine */
1849 cblist->data = data; /* Data for the callback */
1851 cblist->next = hint->callbacks;
1852 hint->callbacks = cblist;
1854 AST_LIST_UNLOCK(&hints);
1858 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1859 int ast_extension_state_del(int id, ast_state_cb_type callback)
1861 struct ast_hint *hint;
1862 struct ast_state_cb *cblist, *cbprev;
1864 if (!id && !callback)
1867 AST_LIST_LOCK(&hints);
1869 /* id is zero is a callback without extension */
1872 for (cblist = statecbs; cblist; cblist = cblist->next) {
1873 if (cblist->callback == callback) {
1875 statecbs = cblist->next;
1877 cbprev->next = cblist->next;
1881 AST_LIST_UNLOCK(&hints);
1887 AST_LIST_UNLOCK(&hints);
1891 /* id greater than zero is a callback with extension */
1892 /* Find the callback based on ID */
1893 AST_LIST_TRAVERSE(&hints, hint, list) {
1895 for (cblist = hint->callbacks; cblist; cblist = cblist->next) {
1896 if (cblist->id==id) {
1898 hint->callbacks = cblist->next;
1900 cbprev->next = cblist->next;
1904 AST_LIST_UNLOCK(&hints);
1911 AST_LIST_UNLOCK(&hints);
1915 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
1916 static int ast_add_hint(struct ast_exten *e)
1918 struct ast_hint *hint;
1923 AST_LIST_LOCK(&hints);
1925 /* Search if hint exists, do nothing */
1926 AST_LIST_TRAVERSE(&hints, hint, list) {
1927 if (hint->exten == e) {
1928 AST_LIST_UNLOCK(&hints);
1929 if (option_debug > 1)
1930 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1935 if (option_debug > 1)
1936 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1938 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
1939 AST_LIST_UNLOCK(&hints);
1942 /* Initialize and insert new item at the top */
1944 hint->laststate = ast_extension_state2(e);
1945 AST_LIST_INSERT_HEAD(&hints, hint, list);
1947 AST_LIST_UNLOCK(&hints);
1951 /*! \brief ast_change_hint: Change hint for an extension */
1952 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1954 struct ast_hint *hint;
1957 AST_LIST_LOCK(&hints);
1958 AST_LIST_TRAVERSE(&hints, hint, list) {
1959 if (hint->exten == oe) {
1965 AST_LIST_UNLOCK(&hints);
1970 /*! \brief ast_remove_hint: Remove hint from extension */
1971 static int ast_remove_hint(struct ast_exten *e)
1973 /* Cleanup the Notifys if hint is removed */
1974 struct ast_hint *hint;
1975 struct ast_state_cb *cblist, *cbprev;
1981 AST_LIST_LOCK(&hints);
1982 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
1983 if (hint->exten == e) {
1985 cblist = hint->callbacks;
1987 /* Notify with -1 and remove all callbacks */
1989 cblist = cblist->next;
1990 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
1993 hint->callbacks = NULL;
1994 AST_LIST_REMOVE_CURRENT(&hints, list);
2000 AST_LIST_TRAVERSE_SAFE_END
2001 AST_LIST_UNLOCK(&hints);
2007 /*! \brief ast_get_hint: Get hint for channel */
2008 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2010 struct ast_exten *e = ast_hint_extension(c, context, exten);
2014 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2016 const char *tmp = ast_get_extension_app_data(e);
2018 ast_copy_string(name, tmp, namesize);
2025 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2027 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2030 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2032 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2035 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2037 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2040 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2042 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2045 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2047 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2050 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2052 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2055 /* helper function to set extension and priority */
2056 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
2058 ast_copy_string(c->exten, exten, sizeof(c->exten));
2062 static int __ast_pbx_run(struct ast_channel *c)
2072 /* A little initial setup here */
2074 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2075 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2079 c->cdr = ast_cdr_alloc();
2081 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2085 ast_cdr_init(c->cdr, c);
2088 /* Set reasonable defaults */
2089 c->pbx->rtimeout = 10;
2090 c->pbx->dtimeout = 5;
2092 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2093 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2095 /* Start by trying whatever the channel is set to */
2096 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2097 /* If not successful fall back to 's' */
2098 if (option_verbose > 1)
2099 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);
2100 /* XXX the original code used the existing priority in the call to
2101 * ast_exists_extension(), and reset it to 1 afterwards.
2102 * I believe the correct thing is to set it to 1 immediately.
2104 set_ext_pri(c, "s", 1);
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));
2112 if (c->cdr && ast_tvzero(c->cdr->start))
2113 ast_cdr_start(c->cdr);
2117 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2118 memset(exten, 0, sizeof(exten));
2119 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2120 /* Something bad happened, or a hangup has been requested. */
2121 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2122 (res == '*') || (res == '#')) {
2123 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2124 memset(exten, 0, sizeof(exten));
2126 exten[pos++] = digit = res;
2130 case AST_PBX_KEEPALIVE:
2132 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2133 else if (option_verbose > 1)
2134 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2139 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2140 else if (option_verbose > 1)
2141 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2142 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2147 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2157 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
2158 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2159 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2160 c->whentohangup = 0;
2161 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2162 } else if (c->_softhangup) {
2163 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2164 c->exten, c->priority);
2170 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2171 /* If there is no match at priority 1, it is not a valid extension anymore.
2172 * Try to continue at "i", 1 or exit if the latter does not exist.
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 set_ext_pri(c, "i", 1);
2180 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2181 c->name, c->exten, c->context);
2184 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2185 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2188 /* Done, wait for an extension */
2191 waittime = c->pbx->dtimeout;
2192 else if (!autofallthrough)
2193 waittime = c->pbx->rtimeout;
2195 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2196 /* As long as we're willing to wait, and as long as it's not defined,
2197 keep reading digits until we can't possibly get a right answer anymore. */
2198 digit = ast_waitfordigit(c, waittime * 1000);
2199 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2206 /* Error, maybe a hangup */
2208 exten[pos++] = digit;
2209 waittime = c->pbx->dtimeout;
2212 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2213 /* Prepare the next cycle */
2214 set_ext_pri(c, exten, 1);
2216 /* No such extension */
2217 if (!ast_strlen_zero(exten)) {
2218 /* An invalid extension */
2219 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2220 if (option_verbose > 2)
2221 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2222 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2223 set_ext_pri(c, "i", 1);
2225 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2229 /* A simple timeout */
2230 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2231 if (option_verbose > 2)
2232 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2233 set_ext_pri(c, "t", 1);
2235 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2241 if (option_verbose > 2)
2242 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2248 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2251 if (option_verbose > 2)
2252 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2253 if (!strcasecmp(status, "CONGESTION"))
2254 res = pbx_builtin_congestion(c, "10");
2255 else if (!strcasecmp(status, "CHANUNAVAIL"))
2256 res = pbx_builtin_congestion(c, "10");
2257 else if (!strcasecmp(status, "BUSY"))
2258 res = pbx_builtin_busy(c, "10");
2264 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2266 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2267 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2268 ast_cdr_end(c->cdr);
2269 set_ext_pri(c, "h", 1);
2270 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2271 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2272 /* Something bad happened, or a hangup has been requested. */
2274 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2275 else if (option_verbose > 1)
2276 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2282 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2284 pbx_destroy(c->pbx);
2286 if (res != AST_PBX_KEEPALIVE)
2291 /* Returns 0 on success, non-zero if call limit was reached */
2292 static int increase_call_count(const struct ast_channel *c)
2296 ast_mutex_lock(&maxcalllock);
2297 if (option_maxcalls) {
2298 if (countcalls >= option_maxcalls) {
2299 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2303 if (option_maxload) {
2304 getloadavg(&curloadavg, 1);
2305 if (curloadavg >= option_maxload) {
2306 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2312 ast_mutex_unlock(&maxcalllock);
2317 static void decrease_call_count(void)
2319 ast_mutex_lock(&maxcalllock);
2322 ast_mutex_unlock(&maxcalllock);
2325 static void *pbx_thread(void *data)
2327 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2328 answer this channel and get it going.
2331 The launcher of this function _MUST_ increment 'countcalls'
2332 before invoking the function; it will be decremented when the
2333 PBX has finished running on the channel
2335 struct ast_channel *c = data;
2338 decrease_call_count();
2345 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2348 pthread_attr_t attr;
2351 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2352 return AST_PBX_FAILED;
2355 if (increase_call_count(c))
2356 return AST_PBX_CALL_LIMIT;
2358 /* Start a new thread, and get something handling this channel. */
2359 pthread_attr_init(&attr);
2360 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2361 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2362 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2363 return AST_PBX_FAILED;
2366 return AST_PBX_SUCCESS;
2369 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2371 enum ast_pbx_result res = AST_PBX_SUCCESS;
2373 if (increase_call_count(c))
2374 return AST_PBX_CALL_LIMIT;
2376 res = __ast_pbx_run(c);
2377 decrease_call_count();
2382 int ast_active_calls(void)
2387 int pbx_set_autofallthrough(int newval)
2389 int oldval = autofallthrough;
2390 autofallthrough = newval;
2394 /* lookup for a context with a given name,
2395 * return with conlock held if found, NULL if not found
2397 static struct ast_context *find_context_locked(const char *context)
2399 struct ast_context *c = NULL;
2400 if (ast_lock_contexts()) {
2404 while ( (c = ast_walk_contexts(c)) ) {
2405 if (!strcmp(ast_get_context_name(c), context))
2408 ast_unlock_contexts();
2414 * This function locks contexts list by &conlist, search for the right context
2415 * structure, leave context list locked and call ast_context_remove_include2
2416 * which removes include, unlock contexts list and return ...
2418 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2421 struct ast_context *c = find_context_locked(context);
2424 /* found, remove include from this context ... */
2425 ret = ast_context_remove_include2(c, include, registrar);
2426 ast_unlock_contexts();
2432 * When we call this function, &conlock lock must be locked, because when
2433 * we giving *con argument, some process can remove/change this context
2434 * and after that there can be segfault.
2436 * This function locks given context, removes include, unlock context and
2439 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2441 struct ast_include *i, *pi = NULL;
2443 if (ast_mutex_lock(&con->lock))
2447 for (i = con->includes; i; pi = i, i = i->next) {
2448 /* find our include */
2449 if (!strcmp(i->name, include) &&
2450 (!registrar || !strcmp(i->registrar, registrar))) {
2451 /* remove from list */
2455 con->includes = i->next;
2456 /* free include and return */
2458 ast_mutex_unlock(&con->lock);
2463 /* we can't find the right include */
2464 ast_mutex_unlock(&con->lock);
2469 * \note This function locks contexts list by &conlist, search for the rigt context
2470 * structure, leave context list locked and call ast_context_remove_switch2
2471 * which removes switch, unlock contexts list and return ...
2473 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2475 int ret = -1; /* default error return */
2476 struct ast_context *c = find_context_locked(context);
2479 /* remove switch from this context ... */
2480 ret = ast_context_remove_switch2(c, sw, data, registrar);
2481 ast_unlock_contexts();
2487 * \brief This function locks given context, removes switch, unlock context and
2489 * \note When we call this function, &conlock lock must be locked, because when
2490 * we giving *con argument, some process can remove/change this context
2491 * and after that there can be segfault.
2494 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2496 struct ast_sw *i, *pi = NULL;
2499 if (ast_mutex_lock(&con->lock))
2503 for (i = con->alts; i; pi = i, i = i->next) {
2504 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2505 (!registrar || !strcmp(i->registrar, registrar))) {
2506 /* found, remove from list */
2510 con->alts = i->next;
2511 free(i); /* free switch and return */
2516 ast_mutex_unlock(&con->lock);
2521 * \note This functions lock contexts list, search for the right context,
2522 * call ast_context_remove_extension2, unlock contexts list and return.
2523 * In this function we are using
2525 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2527 int ret = -1; /* default error return */
2528 struct ast_context *c = find_context_locked(context);
2530 if (c) { /* ... remove extension ... */
2531 ret = ast_context_remove_extension2(c, extension, priority, registrar);
2532 ast_unlock_contexts();
2538 * \brief This functionc locks given context, search for the right extension and
2539 * fires out all peer in this extensions with given priority. If priority
2540 * is set to 0, all peers are removed. After that, unlock context and
2542 * \note When do you want to call this function, make sure that &conlock is locked,
2543 * because some process can handle with your *con context before you lock
2547 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2549 struct ast_exten *exten, *prev_exten = NULL;
2551 if (ast_mutex_lock(&con->lock))
2554 /* go through all extensions in context and search the right one ... */
2558 /* look for right extension */
2559 if (!strcmp(exten->exten, extension) &&
2560 (!registrar || !strcmp(exten->registrar, registrar))) {
2561 struct ast_exten *peer;
2563 /* should we free all peers in this extension? (priority == 0)? */
2564 if (priority == 0) {
2565 /* remove this extension from context list */
2567 prev_exten->next = exten->next;
2569 con->root = exten->next;
2571 /* fire out all peers */
2576 if (!peer->priority==PRIORITY_HINT)
2577 ast_remove_hint(peer);
2579 peer->datad(peer->data);
2585 ast_mutex_unlock(&con->lock);
2588 /* remove only extension with exten->priority == priority */
2589 struct ast_exten *previous_peer = NULL;
2593 /* is this our extension? */
2594 if (peer->priority == priority &&
2595 (!registrar || !strcmp(peer->registrar, registrar) )) {
2596 /* we are first priority extension? */
2597 if (!previous_peer) {
2598 /* exists previous extension here? */
2600 /* yes, so we must change next pointer in
2601 * previous connection to next peer
2604 prev_exten->next = peer->peer;
2605 peer->peer->next = exten->next;
2607 prev_exten->next = exten->next;
2609 /* no previous extension, we are first
2610 * extension, so change con->root ...
2613 con->root = peer->peer;
2615 con->root = exten->next;
2618 /* we are not first priority in extension */
2619 previous_peer->peer = peer->peer;
2622 /* now, free whole priority extension */
2623 if (peer->priority==PRIORITY_HINT)
2624 ast_remove_hint(peer);
2625 peer->datad(peer->data);
2628 ast_mutex_unlock(&con->lock);
2631 /* this is not right extension, skip to next peer */
2632 previous_peer = peer;
2637 ast_mutex_unlock(&con->lock);
2643 exten = exten->next;
2646 /* we can't find right extension */
2647 ast_mutex_unlock(&con->lock);
2652 /*! \brief Dynamically register a new dial plan application */
2653 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2655 struct ast_app *tmp, *prev, *cur;
2658 length = sizeof(struct ast_app);
2659 length += strlen(app) + 1;
2660 if (ast_mutex_lock(&applock)) {
2661 ast_log(LOG_ERROR, "Unable to lock application list\n");
2664 for (tmp = apps; tmp; tmp = tmp->next) {
2665 if (!strcasecmp(app, tmp->name)) {
2666 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2667 ast_mutex_unlock(&applock);
2672 if (!(tmp = ast_calloc(1, length))) {
2673 ast_mutex_unlock(&applock);
2677 strcpy(tmp->name, app);
2678 tmp->execute = execute;
2679 tmp->synopsis = synopsis;
2680 tmp->description = description;
2681 /* Store in alphabetical order */
2683 for (cur = apps; cur; cur = cur->next) {
2684 if (strcasecmp(tmp->name, cur->name) < 0)
2689 tmp->next = prev->next;
2696 if (option_verbose > 1)
2697 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2698 ast_mutex_unlock(&applock);
2703 * Append to the list. We don't have a tail pointer because we need
2704 * to scan the list anyways to check for duplicates during insertion.
2706 int ast_register_switch(struct ast_switch *sw)
2708 struct ast_switch *tmp, *prev=NULL;
2709 if (ast_mutex_lock(&switchlock)) {
2710 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2713 for (tmp = switches; tmp; prev = tmp, tmp = tmp->next) {
2714 if (!strcasecmp(tmp->name, sw->name))
2718 ast_mutex_unlock(&switchlock);
2719 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2727 ast_mutex_unlock(&switchlock);
2731 void ast_unregister_switch(struct ast_switch *sw)
2733 struct ast_switch *tmp, *prev=NULL;
2734 if (ast_mutex_lock(&switchlock)) {
2735 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2738 for (tmp = switches; tmp; prev = tmp, tmp = tmp->next) {
2741 prev->next = tmp->next;
2743 switches = tmp->next;
2748 ast_mutex_unlock(&switchlock);
2752 * Help for CLI commands ...
2754 static char show_application_help[] =
2755 "Usage: show application <application> [<application> [<application> [...]]]\n"
2756 " Describes a particular application.\n";
2758 static char show_functions_help[] =
2759 "Usage: show functions [like <text>]\n"
2760 " List builtin functions, optionally only those matching a given string\n";
2762 static char show_function_help[] =
2763 "Usage: show function <function>\n"
2764 " Describe a particular dialplan function.\n";
2766 static char show_applications_help[] =
2767 "Usage: show applications [{like|describing} <text>]\n"
2768 " List applications which are currently available.\n"
2769 " If 'like', <text> will be a substring of the app name\n"
2770 " If 'describing', <text> will be a substring of the description\n";
2772 static char show_dialplan_help[] =
2773 "Usage: show dialplan [exten@][context]\n"
2776 static char show_switches_help[] =
2777 "Usage: show switches\n"
2778 " Show registered switches\n";
2780 static char show_hints_help[] =
2781 "Usage: show hints\n"
2782 " Show registered hints\n";
2784 static char show_globals_help[] =
2785 "Usage: show globals\n"
2786 " Show current global dialplan variables and their values\n";
2788 static char set_global_help[] =
2789 "Usage: set global <name> <value>\n"
2790 " Set global dialplan variable <name> to <value>\n";
2794 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2799 * \brief 'show application' CLI command implementation functions ...
2803 * There is a possibility to show informations about more than one
2804 * application at one time. You can type 'show application Dial Echo' and
2805 * you will see informations about these two applications ...
2807 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2812 int wordlen = strlen(word);
2814 /* try to lock applications list ... */
2815 if (ast_mutex_lock(&applock)) {
2816 ast_log(LOG_ERROR, "Unable to lock application list\n");
2820 /* return the n-th [partial] matching entry */
2821 for (a = apps; a && !ret; a = a->next) {
2822 if (!strncasecmp(word, a->name, wordlen) && ++which > state)
2823 ret = strdup(a->name);
2826 ast_mutex_unlock(&applock);
2831 static int handle_show_application(int fd, int argc, char *argv[])
2834 int app, no_registered_app = 1;
2836 if (argc < 3) return RESULT_SHOWUSAGE;
2838 /* try to lock applications list ... */
2839 if (ast_mutex_lock(&applock)) {
2840 ast_log(LOG_ERROR, "Unable to lock application list\n");
2844 /* ... go through all applications ... */
2845 for (a = apps; a; a = a->next) {
2846 /* ... compare this application name with all arguments given
2847 * to 'show application' command ... */
2848 for (app = 2; app < argc; app++) {
2849 if (!strcasecmp(a->name, argv[app])) {
2850 /* Maximum number of characters added by terminal coloring is 22 */
2851 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2852 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2853 int synopsis_size, description_size;
2855 no_registered_app = 0;
2858 synopsis_size = strlen(a->synopsis) + 23;
2860 synopsis_size = strlen("Not available") + 23;
2861 synopsis = alloca(synopsis_size);
2864 description_size = strlen(a->description) + 23;
2866 description_size = strlen("Not available") + 23;
2867 description = alloca(description_size);
2869 if (synopsis && description) {
2870 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2871 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2872 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2873 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2874 term_color(synopsis,
2875 a->synopsis ? a->synopsis : "Not available",
2876 COLOR_CYAN, 0, synopsis_size);
2877 term_color(description,
2878 a->description ? a->description : "Not available",
2879 COLOR_CYAN, 0, description_size);
2881 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2883 /* ... one of our applications, show info ...*/
2884 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2885 "[Synopsis]\n %s\n\n"
2886 "[Description]\n%s\n",
2888 a->synopsis ? a->synopsis : "Not available",
2889 a->description ? a->description : "Not available");
2895 ast_mutex_unlock(&applock);
2897 /* we found at least one app? no? */
2898 if (no_registered_app) {
2899 ast_cli(fd, "Your application(s) is (are) not registered\n");
2900 return RESULT_FAILURE;
2903 return RESULT_SUCCESS;
2906 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2907 static int handle_show_hints(int fd, int argc, char *argv[])
2909 struct ast_hint *hint;
2912 struct ast_state_cb *watcher;
2914 if (AST_LIST_EMPTY(&hints)) {
2915 ast_cli(fd, "There are no registered dialplan hints\n");
2916 return RESULT_SUCCESS;
2918 /* ... we have hints ... */
2919 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2920 if (AST_LIST_LOCK(&hints)) {
2921 ast_log(LOG_ERROR, "Unable to lock hints\n");
2924 AST_LIST_TRAVERSE(&hints, hint, list) {
2926 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2928 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2929 ast_get_extension_name(hint->exten),
2930 ast_get_context_name(ast_get_extension_context(hint->exten)),
2931 ast_get_extension_app(hint->exten),
2932 ast_extension_state2str(hint->laststate), watchers);
2935 ast_cli(fd, "----------------\n");
2936 ast_cli(fd, "- %d hints registered\n", num);
2937 AST_LIST_UNLOCK(&hints);
2938 return RESULT_SUCCESS;
2941 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2942 static int handle_show_switches(int fd, int argc, char *argv[])
2944 struct ast_switch *sw;
2946 ast_cli(fd, "There are no registered alternative switches\n");
2947 return RESULT_SUCCESS;
2949 /* ... we have applications ... */
2950 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2951 if (ast_mutex_lock(&switchlock)) {
2952 ast_log(LOG_ERROR, "Unable to lock switches\n");
2955 for (sw = switches; sw; sw = sw->next)
2956 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2957 ast_mutex_unlock(&switchlock);
2958 return RESULT_SUCCESS;
2962 * 'show applications' CLI command implementation functions ...
2964 static int handle_show_applications(int fd, int argc, char *argv[])
2967 int like = 0, describing = 0;
2968 int total_match = 0; /* Number of matches in like clause */
2969 int total_apps = 0; /* Number of apps registered */
2971 /* try to lock applications list ... */
2972 if (ast_mutex_lock(&applock)) {
2973 ast_log(LOG_ERROR, "Unable to lock application list\n");
2977 /* ... have we got at least one application (first)? no? */
2979 ast_cli(fd, "There are no registered applications\n");
2980 ast_mutex_unlock(&applock);
2984 /* show applications like <keyword> */
2985 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2987 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2991 /* show applications describing <keyword1> [<keyword2>] [...] */
2992 if ((!like) && (!describing)) {
2993 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2995 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2998 /* ... go through all applications ... */
2999 for (a = apps; a; a = a->next) {
3000 /* ... show informations about applications ... */
3004 if (strcasestr(a->name, argv[3])) {
3008 } else if (describing) {
3009 if (a->description) {
3010 /* Match all words on command line */
3013 for (i = 3; i < argc; i++) {
3014 if (!strcasestr(a->description, argv[i])) {
3026 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3029 if ((!like) && (!describing)) {
3030 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3032 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3035 /* ... unlock and return */
3036 ast_mutex_unlock(&applock);
3038 return RESULT_SUCCESS;
3041 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3043 static char* choices[] = { "like", "describing", NULL };
3045 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
3049 * 'show dialplan' CLI command implementation functions ...
3051 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3054 struct ast_context *c = NULL;
3059 /* we are do completion of [exten@]context on second position only */
3063 /* try to lock contexts list ... */
3064 if (ast_lock_contexts()) {
3065 ast_log(LOG_ERROR, "Unable to lock context list\n");
3069 wordlen = strlen(word);
3071 /* walk through all contexts and return the n-th match */
3072 while ( (c = ast_walk_contexts(c)) ) {
3073 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
3074 ret = ast_strdup(ast_get_context_name(c));