2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/types.h>
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29 #include "asterisk/lock.h"
30 #include "asterisk/cli.h"
31 #include "asterisk/pbx.h"
32 #include "asterisk/channel.h"
33 #include "asterisk/options.h"
34 #include "asterisk/logger.h"
35 #include "asterisk/file.h"
36 #include "asterisk/callerid.h"
37 #include "asterisk/cdr.h"
38 #include "asterisk/config.h"
39 #include "asterisk/term.h"
40 #include "asterisk/manager.h"
41 #include "asterisk/ast_expr.h"
42 #include "asterisk/linkedlists.h"
43 #include "asterisk/say.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/causes.h"
46 #include "asterisk/musiconhold.h"
47 #include "asterisk/app.h"
48 #include "asterisk/devicestate.h"
53 * The speed of extension handling will likely be among the most important
54 * aspects of this PBX. The switching scheme as it exists right now isn't
55 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
56 * of priorities, but a constant search time here would be great ;-)
61 #define EXT_DATA_SIZE 256
63 #define EXT_DATA_SIZE 8192
66 #define SWITCH_DATA_LENGTH 256
70 #define VAR_SOFTTRAN 2
71 #define VAR_HARDTRAN 3
73 #define BACKGROUND_SKIP (1 << 0)
74 #define BACKGROUND_NOANSWER (1 << 1)
75 #define BACKGROUND_MATCHEXTEN (1 << 2)
76 #define BACKGROUND_PLAYBACK (1 << 3)
78 AST_DECLARE_OPTIONS(background_opts,{
79 ['s'] = { BACKGROUND_SKIP },
80 ['n'] = { BACKGROUND_NOANSWER },
81 ['m'] = { BACKGROUND_MATCHEXTEN },
82 ['p'] = { BACKGROUND_PLAYBACK },
85 #define WAITEXTEN_MOH (1 << 0)
87 AST_DECLARE_OPTIONS(waitexten_opts,{
88 ['m'] = { WAITEXTEN_MOH, 1 },
93 /* ast_exten: An extension */
95 char *exten; /* Extension name */
96 int matchcid; /* Match caller id ? */
97 char *cidmatch; /* Caller id to match for this extension */
98 int priority; /* Priority */
99 char *label; /* Label */
100 struct ast_context *parent; /* The context this extension belongs to */
101 char *app; /* Application to execute */
102 void *data; /* Data to use (arguments) */
103 void (*datad)(void *); /* Data destructor */
104 struct ast_exten *peer; /* Next higher priority with our extension */
105 const char *registrar; /* Registrar */
106 struct ast_exten *next; /* Extension with a greater ID */
110 /* ast_include: include= support in extensions.conf */
113 char *rname; /* Context to include */
114 const char *registrar; /* Registrar */
115 int hastime; /* If time construct exists */
116 struct ast_timing timing; /* time construct */
117 struct ast_include *next; /* Link them together */
121 /* ast_sw: Switch statement in extensions.conf */
124 const char *registrar; /* Registrar */
125 char *data; /* Data load */
127 struct ast_sw *next; /* Link them together */
132 struct ast_ignorepat {
133 const char *registrar;
134 struct ast_ignorepat *next;
138 /* ast_context: An extension context */
140 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
141 struct ast_exten *root; /* The root of the list of extensions */
142 struct ast_context *next; /* Link them together */
143 struct ast_include *includes; /* Include other contexts */
144 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
145 const char *registrar; /* Registrar */
146 struct ast_sw *alts; /* Alternative switches */
147 char name[0]; /* Name of the context */
151 /* ast_app: An application */
153 int (*execute)(struct ast_channel *chan, void *data);
154 const char *synopsis; /* Synopsis text for 'show applications' */
155 const char *description; /* Description (help text) for 'show application <name>' */
156 struct ast_app *next; /* Next app in list */
157 char name[0]; /* Name of the application */
160 /* ast_state_cb: An extension state notify */
161 struct ast_state_cb {
164 ast_state_cb_type callback;
165 struct ast_state_cb *next;
168 /* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
170 struct ast_exten *exten; /* Extension */
171 int laststate; /* Last known state */
172 struct ast_state_cb *callbacks; /* Callback list for this extension */
173 struct ast_hint *next; /* Pointer to next hint in list */
176 int ast_pbx_outgoing_cdr_failed(void);
178 static int pbx_builtin_prefix(struct ast_channel *, void *);
179 static int pbx_builtin_suffix(struct ast_channel *, void *);
180 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
181 static int pbx_builtin_answer(struct ast_channel *, void *);
182 static int pbx_builtin_goto(struct ast_channel *, void *);
183 static int pbx_builtin_hangup(struct ast_channel *, void *);
184 static int pbx_builtin_background(struct ast_channel *, void *);
185 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
186 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
187 static int pbx_builtin_atimeout(struct ast_channel *, void *);
188 static int pbx_builtin_wait(struct ast_channel *, void *);
189 static int pbx_builtin_waitexten(struct ast_channel *, void *);
190 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
191 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
192 static int pbx_builtin_setaccount(struct ast_channel *, void *);
193 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
194 static int pbx_builtin_ringing(struct ast_channel *, void *);
195 static int pbx_builtin_progress(struct ast_channel *, void *);
196 static int pbx_builtin_congestion(struct ast_channel *, void *);
197 static int pbx_builtin_busy(struct ast_channel *, void *);
198 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
199 static int pbx_builtin_noop(struct ast_channel *, void *);
200 static int pbx_builtin_gotoif(struct ast_channel *, void *);
201 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
202 static int pbx_builtin_execiftime(struct ast_channel *, void *);
203 static int pbx_builtin_saynumber(struct ast_channel *, void *);
204 static int pbx_builtin_saydigits(struct ast_channel *, void *);
205 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
206 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
207 static int pbx_builtin_setvar_old(struct ast_channel *, void *);
208 int pbx_builtin_setvar(struct ast_channel *, void *);
209 static int pbx_builtin_importvar(struct ast_channel *, void *);
211 static struct varshead globals;
213 static int autofallthrough = 0;
215 AST_MUTEX_DEFINE_STATIC(maxcalllock);
216 static int countcalls = 0;
218 AST_MUTEX_DEFINE_STATIC(acflock); /* Lock for the custom function list */
219 static struct ast_custom_function *acf_root = NULL;
221 static struct pbx_builtin {
222 char name[AST_MAX_APP];
223 int (*execute)(struct ast_channel *chan, void *data);
228 /* These applications are built into the PBX core and do not
229 need separate modules */
231 { "AbsoluteTimeout", pbx_builtin_atimeout,
232 "Set absolute maximum time of call",
233 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
234 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
235 "AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
238 { "Answer", pbx_builtin_answer,
239 "Answer a channel if ringing",
240 " Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
241 "If delay is specified, asterisk will pause execution for the specified amount\n"
242 "of milliseconds if an answer is required, in order to give audio a chance to\n"
243 "become ready. Returns 0 unless it tries to answer the channel and fails.\n"
246 { "BackGround", pbx_builtin_background,
247 "Play a file while awaiting extension",
248 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
249 "Plays given files, while simultaneously waiting for the user to begin typing\n"
250 "an extension. The timeouts do not count until the last BackGround\n"
251 "application has ended. Options may also be included following a pipe \n"
252 "symbol. The 'langoverride' may be a language to use for playing the prompt\n"
253 "which differs from the current language of the channel. The optional\n"
254 "'context' can be used to specify an optional context to exit into.\n"
255 "Returns -1 if thhe channel was hung up, or if the file does not exist./n"
256 "Returns 0 otherwise.\n\n"
258 " 's' - causes the playback of the message to be skipped\n"
259 " if the channel is not in the 'up' state (i.e. it\n"
260 " hasn't been answered yet.) If this happens, the\n"
261 " application will return immediately.\n"
262 " 'n' - don't answer the channel before playing the files\n"
263 " 'm' - only break if a digit hit matches a one digit\n"
264 " extension in the destination context\n"
267 { "Busy", pbx_builtin_busy,
268 "Indicate busy condition and stop",
269 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
270 "then waits for the user to hang up or the optional timeout to expire.\n"
274 { "Congestion", pbx_builtin_congestion,
275 "Indicate congestion and stop",
276 " Congestion([timeout]): Requests that the channel indicate congestion\n"
277 "and then waits for the user to hang up or for the optional timeout to\n"
278 "expire. Always returns -1."
281 { "DigitTimeout", pbx_builtin_dtimeout,
282 "Set maximum timeout between digits",
283 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
284 "digits when the user is typing in an extension. When this timeout expires,\n"
285 "after the user has started to type in an extension, the extension will be\n"
286 "considered complete, and will be interpreted. Note that if an extension\n"
287 "typed in is valid, it will not have to timeout to be tested, so typically\n"
288 "at the expiry of this timeout, the extension will be considered invalid\n"
289 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
290 "exist the call would be terminated). The default timeout is 5 seconds.\n"
291 "Always returns 0.\n"
292 "DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout)\n"
295 { "Goto", pbx_builtin_goto,
296 "Goto a particular priority, extension, or context",
297 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
298 "value, optionally setting the extension and optionally the context as well.\n"
299 "The extension BYEXTENSION is special in that it uses the current extension,\n"
300 "thus permitting you to go to a different context, without specifying a\n"
301 "specific extension. Always returns 0, even if the given context, extension,\n"
302 "or priority is invalid.\n"
305 { "GotoIf", pbx_builtin_gotoif,
307 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
308 "true, to label2 if condition is false. Either label1 or label2 may be\n"
309 "omitted (in that case, we just don't take the particular branch) but not\n"
310 "both. Look for the condition syntax in examples or documentation."
313 { "GotoIfTime", pbx_builtin_gotoiftime,
314 "Conditional goto on current time",
315 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
316 "If the current time matches the specified time, then branch to the specified\n"
317 "extension. Each of the elements may be specified either as '*' (for always)\n"
318 "or as a range. See the 'include' syntax for details."
321 { "ExecIfTime", pbx_builtin_execiftime,
322 "Conditional application execution on current time",
323 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?<appname>[|<appdata>]):\n"
324 "If the current time matches the specified time, then execute the specified\n"
325 "application. Each of the elements may be specified either as '*' (for always)\n"
326 "or as a range. See the 'include' syntax for details. It will return whatever\n"
327 "<appname> returns, or a non-zero value if the application is not found.\n"
330 { "Hangup", pbx_builtin_hangup,
331 "Unconditional hangup",
332 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
335 { "NoOp", pbx_builtin_noop,
337 " NoOp(): No-operation; Does nothing."
340 { "Prefix", pbx_builtin_prefix,
341 "Prepend leading digits",
342 " Prefix(digits): Prepends the digit string specified by digits to the\n"
343 "channel's associated extension. For example, the number 1212 when prefixed\n"
344 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
345 "continue processing at the next priority for the *new* extension.\n"
346 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
347 "executed will be priority 4 of 5551212. If you switch into an extension\n"
348 "which has no first step, the PBX will treat it as though the user dialed an\n"
349 "invalid extension.\n"
352 { "Progress", pbx_builtin_progress,
354 " Progress(): Request that the channel indicate in-band progress is \n"
355 "available to the user.\nAlways returns 0.\n"
358 { "ResetCDR", pbx_builtin_resetcdr,
359 "Resets the Call Data Record",
360 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
361 "storing the current CDR before zeroing it out\b"
362 " - if 'w' option is specified record will be stored.\n"
363 " - if 'a' option is specified any stacked records will be stored.\n"
364 " - if 'v' option is specified any variables will be saved.\n"
365 "Always returns 0.\n"
368 { "ResponseTimeout", pbx_builtin_rtimeout,
369 "Set maximum timeout awaiting response",
370 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
371 "falling through a series of priorities for a channel in which the user may\n"
372 "begin typing an extension. If the user does not type an extension in this\n"
373 "amount of time, control will pass to the 't' extension if it exists, and\n"
374 "if not the call would be terminated. The default timeout is 10 seconds.\n"
375 "Always returns 0.\n"
376 "ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout)\n"
379 { "Ringing", pbx_builtin_ringing,
380 "Indicate ringing tone",
381 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
382 "Always returns 0.\n"
385 { "SayNumber", pbx_builtin_saynumber,
387 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
388 "the current language setting for the channel. (See app SetLanguage).\n"
391 { "SayDigits", pbx_builtin_saydigits,
393 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
394 "current language setting for the channel. (See app setLanguage)\n"
397 { "SayAlpha", pbx_builtin_saycharacters,
399 " SayAlpha(string): Spells the passed string\n"
402 { "SayPhonetic", pbx_builtin_sayphonetic,
404 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
407 { "SetAccount", pbx_builtin_setaccount,
409 " SetAccount([account]): Set the channel account code for billing\n"
410 "purposes. Always returns 0.\n"
413 { "SetAMAFlags", pbx_builtin_setamaflags,
415 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
416 "purposes. Always returns 0.\n"
419 { "SetGlobalVar", pbx_builtin_setglobalvar,
420 "Set global variable to value",
421 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
422 "variable are available across channels.\n"
425 { "SetLanguage", pbx_builtin_setlanguage,
426 "Sets channel language",
427 " SetLanguage(language): Set the channel language to 'language'. This\n"
428 "information is used for the syntax in generation of numbers, and to choose\n"
429 "a natural language file when available.\n"
430 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
431 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
432 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
433 "For some language codes, SetLanguage also changes the syntax of some\n"
434 "Asterisk functions, like SayNumber.\n"
435 "Always returns 0.\n"
436 "SetLanguage has been deprecated in favor of Set(LANGUAGE()=language)\n"
439 { "Set", pbx_builtin_setvar,
440 "Set channel variable(s) or function value(s)",
441 " Set(name1=value1|name2=value2|..[|options])\n"
442 "This function can be used to set the value of channel variables\n"
443 "or dialplan functions. It will accept up to 24 name/value pairs.\n"
444 "When setting variables, if the variable name is prefixed with _,\n"
445 "the variable will be inherited into channels created from the\n"
446 "current channel. If the variable name is prefixed with __,\n"
447 "the variable will be inherited into channels created from the\n"
448 "current channel and all child channels.\n"
449 "The last argument, if it does not contain '=', is interpreted\n"
450 "as a string of options. The valid options are:\n"
451 " g - Set variable globally instead of on the channel\n"
452 " (applies only to variables, not functions)\n"
455 { "SetVar", pbx_builtin_setvar_old,
456 "Set channel variable(s)",
457 " SetVar(name1=value1|name2=value2|..[|options])\n"
458 "SetVar has been deprecated in favor of Set.\n"
461 { "ImportVar", pbx_builtin_importvar,
462 "Import a variable from a channel into a new variable",
463 " ImportVar(newvar=channelname|variable): This application imports a\n"
464 "variable from the specified channel (as opposed to the current one)\n"
465 "and stores it as a variable in the current channel (the channel that\n"
466 "is calling this application). If the new variable name is prefixed by\n"
467 "a single underscore \"_\", then it will be inherited into any channels\n"
468 "created from this one. If it is prefixed with two underscores,then\n"
469 "the variable will have infinite inheritance, meaning that it will be\n"
470 "present in any descendent channel of this one.\n"
473 { "StripMSD", pbx_builtin_stripmsd,
474 "Strip leading digits",
475 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
476 "associated extension. For example, the number 5551212 when stripped with a\n"
477 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
478 "will continue processing at the next priority for the *new* extension.\n"
479 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
480 "executed will be priority 4 of 1212. If you switch into an extension which\n"
481 "has no first step, the PBX will treat it as though the user dialed an\n"
482 "invalid extension.\n"
485 { "Suffix", pbx_builtin_suffix,
486 "Append trailing digits",
487 " Suffix(digits): Appends the digit string specified by digits to the\n"
488 "channel's associated extension. For example, the number 555 when suffixed\n"
489 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
490 "continue processing at the next priority for the *new* extension.\n"
491 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
492 "executed will be priority 4 of 5551212. If you switch into an extension\n"
493 "which has no first step, the PBX will treat it as though the user dialed an\n"
494 "invalid extension.\n"
497 { "Wait", pbx_builtin_wait,
498 "Waits for some time",
499 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
500 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
503 { "WaitExten", pbx_builtin_waitexten,
504 "Waits for an extension to be entered",
505 " WaitExten([seconds][|options]): Waits for the user to enter a new extension for the \n"
506 "specified number of seconds, then returns 0. Seconds can be passed with\n"
507 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
508 "default extension timeout will be used.\n"
510 " 'm[(x)]' - Provide music on hold to the caller while waiting for an extension.\n"
511 " Optionally, specify the class for music on hold within parenthesis.\n"
516 static struct ast_context *contexts = NULL;
517 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
518 static struct ast_app *apps = NULL;
519 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
521 struct ast_switch *switches = NULL;
522 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
524 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
525 static int stateid = 1;
526 struct ast_hint *hints = NULL;
527 struct ast_state_cb *statecbs = NULL;
529 int pbx_exec(struct ast_channel *c, /* Channel */
530 struct ast_app *app, /* Application */
531 void *data, /* Data for execution */
532 int newstack) /* Force stack increment */
534 /* This function is special. It saves the stack so that no matter
535 how many times it is called, it returns to the same place */
541 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
545 ast_cdr_setapp(c->cdr, app->name, data);
547 /* save channel values */
548 saved_c_appl= c->appl;
549 saved_c_data= c->data;
553 res = execute(c, data);
554 /* restore channel values */
555 c->appl= saved_c_appl;
556 c->data= saved_c_data;
559 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
564 /* Go no deeper than this through includes (not counting loops) */
565 #define AST_PBX_MAX_STACK 128
567 #define HELPER_EXISTS 0
568 #define HELPER_SPAWN 1
569 #define HELPER_EXEC 2
570 #define HELPER_CANMATCH 3
571 #define HELPER_MATCHMORE 4
572 #define HELPER_FINDLABEL 5
574 struct ast_app *pbx_findapp(const char *app)
578 if (ast_mutex_lock(&applock)) {
579 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
584 if (!strcasecmp(tmp->name, app))
588 ast_mutex_unlock(&applock);
592 static struct ast_switch *pbx_findswitch(const char *sw)
594 struct ast_switch *asw;
596 if (ast_mutex_lock(&switchlock)) {
597 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
602 if (!strcasecmp(asw->name, sw))
606 ast_mutex_unlock(&switchlock);
610 static inline int include_valid(struct ast_include *i)
615 return ast_check_timing(&(i->timing));
618 static void pbx_destroy(struct ast_pbx *p)
623 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
624 /* All patterns begin with _ */\
625 if (pattern[0] != '_') \
627 /* Start optimistic */\
630 while(match && *data && *pattern && (*pattern != '/')) {\
631 while (*data == '-' && (*(data+1) != '\0')) data++;\
632 switch(toupper(*pattern)) {\
639 where=strchr(pattern,']');\
641 border=(int)(where-pattern);\
642 if (!where || border > strlen(pattern)) {\
643 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
646 for (i=0; i<border; i++) {\
649 if (pattern[i+1]=='-') {\
650 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
657 if (res==1 || *data==pattern[i]) {\
666 if ((*data < '2') || (*data > '9'))\
670 if ((*data < '0') || (*data > '9'))\
674 if ((*data < '1') || (*data > '9'))\
685 /* Ignore these characters */\
689 if (*data != *pattern)\
695 /* If we ran off the end of the data and the pattern ends in '!', match */\
696 if (match && !*data && (*pattern == '!'))\
700 int ast_extension_match(const char *pattern, const char *data)
703 /* If they're the same return */
704 if (!strcmp(pattern, data))
706 EXTENSION_MATCH_CORE(data,pattern,match);
707 /* Must be at the end of both */
708 if (*data || (*pattern && (*pattern != '/')))
713 int ast_extension_close(const char *pattern, const char *data, int needmore)
716 /* If "data" is longer, it can'be a subset of pattern unless
717 pattern is a pattern match */
718 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
721 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
722 (!needmore || (strlen(pattern) > strlen(data)))) {
725 EXTENSION_MATCH_CORE(data,pattern,match);
726 /* If there's more or we don't care about more, or if it's a possible early match,
727 return non-zero; otherwise it's a miss */
728 if (!needmore || *pattern || match == 2) {
734 struct ast_context *ast_context_find(const char *name)
736 struct ast_context *tmp;
737 ast_mutex_lock(&conlock);
741 if (!strcasecmp(name, tmp->name))
747 ast_mutex_unlock(&conlock);
751 #define STATUS_NO_CONTEXT 1
752 #define STATUS_NO_EXTENSION 2
753 #define STATUS_NO_PRIORITY 3
754 #define STATUS_NO_LABEL 4
755 #define STATUS_SUCCESS 5
757 static int matchcid(const char *cidpattern, const char *callerid)
761 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
762 failing to get a number should count as a match, otherwise not */
764 if (!ast_strlen_zero(cidpattern))
772 return ast_extension_match(cidpattern, callerid);
775 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)
778 struct ast_context *tmp;
779 struct ast_exten *e, *eroot;
780 struct ast_include *i;
782 struct ast_switch *asw;
784 /* Initialize status if appropriate */
786 *status = STATUS_NO_CONTEXT;
790 /* Check for stack overflow */
791 if (*stacklen >= AST_PBX_MAX_STACK) {
792 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
795 /* Check first to see if we've already been checked */
796 for (x=0; x<*stacklen; x++) {
797 if (!strcasecmp(incstack[x], context))
806 if (bypass || !strcmp(tmp->name, context)) {
807 struct ast_exten *earlymatch = NULL;
809 if (*status < STATUS_NO_EXTENSION)
810 *status = STATUS_NO_EXTENSION;
811 for (eroot = tmp->root; eroot; eroot=eroot->next) {
813 /* Match extension */
814 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
815 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
816 ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
817 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
819 if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
820 /* It matched an extension ending in a '!' wildcard
821 So ignore it for now, unless there's a better match */
825 if (*status < STATUS_NO_PRIORITY)
826 *status = STATUS_NO_PRIORITY;
829 if (action == HELPER_FINDLABEL) {
830 if (*status < STATUS_NO_LABEL)
831 *status = STATUS_NO_LABEL;
832 if (label && e->label && !strcmp(label, e->label)) {
833 *status = STATUS_SUCCESS;
834 *foundcontext = context;
837 } else if (e->priority == priority) {
838 *status = STATUS_SUCCESS;
839 *foundcontext = context;
848 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
849 of the loop waiting for more digits, and _then_ match (normally)
850 the extension we ended up with. We got an early-matching wildcard
851 pattern, so return NULL to break out of the loop. */
854 /* Check alternative switches */
857 if ((asw = pbx_findswitch(sw->name))) {
858 /* Substitute variables now */
860 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
861 if (action == HELPER_CANMATCH)
862 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
863 else if (action == HELPER_MATCHMORE)
864 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
866 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
870 *data = sw->eval ? sw->tmpdata : sw->data;
871 *foundcontext = context;
875 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
879 /* Setup the stack */
880 incstack[*stacklen] = tmp->name;
882 /* Now try any includes we have in this context */
885 if (include_valid(i)) {
886 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
900 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
901 functions in the dialplan
903 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
906 char tmpvar[80] = "";
908 struct tm brokentime;
910 struct ast_var_t *variables;
915 if ((first=strchr(var,':'))) { /* : Remove characters counting from end or start of string */
916 ast_copy_string(tmpvar, var, sizeof(tmpvar));
917 first = strchr(tmpvar, ':');
919 first = tmpvar + strlen(tmpvar);
921 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
924 offset=atoi(first+1); /* The number of characters,
925 positive: remove # of chars from start
926 negative: keep # of chars from end */
928 if ((second=strchr(first+1,':'))) {
930 offset2 = atoi(second+1); /* Number of chars to copy */
931 } else if (offset >= 0) {
932 offset2 = strlen(*ret)-offset; /* Rest of string */
934 offset2 = abs(offset);
937 if (abs(offset) > strlen(*ret)) { /* Offset beyond string */
939 offset = strlen(*ret);
941 offset =- strlen(*ret);
943 if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
945 offset2 = strlen(*ret)-offset;
947 offset2 = strlen(*ret)+offset;
952 *ret += strlen(*ret)+offset;
953 (*ret)[offset2] = '\0'; /* Cut at offset2 position */
954 } else if (c && !strncmp(var, "CALL", 4)) {
955 if (!strncmp(var + 4, "ER", 2)) {
956 if (!strncmp(var + 6, "ID", 2)) {
957 if (!var[8]) { /* CALLERID */
958 if (c->cid.cid_num) {
959 if (c->cid.cid_name) {
960 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
962 ast_copy_string(workspace, c->cid.cid_num, workspacelen);
965 } else if (c->cid.cid_name) {
966 ast_copy_string(workspace, c->cid.cid_name, workspacelen);
970 } else if (!strcmp(var + 8, "NUM")) {
972 if (c->cid.cid_num) {
973 ast_copy_string(workspace, c->cid.cid_num, workspacelen);
977 } else if (!strcmp(var + 8, "NAME")) {
979 if (c->cid.cid_name) {
980 ast_copy_string(workspace, c->cid.cid_name, workspacelen);
985 } else if (!strcmp(var + 6, "ANI")) {
987 if (c->cid.cid_ani) {
988 ast_copy_string(workspace, c->cid.cid_ani, workspacelen);
994 } else if (!strncmp(var + 4, "ING", 3)) {
995 if (!strcmp(var + 7, "PRES")) {
997 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
999 } else if (!strcmp(var + 7, "ANI2")) {
1001 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1003 } else if (!strcmp(var + 7, "TON")) {
1005 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1007 } else if (!strcmp(var + 7, "TNS")) {
1009 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1015 } else if (c && !strcmp(var, "DNID")) {
1016 if (c->cid.cid_dnid) {
1017 ast_copy_string(workspace, c->cid.cid_dnid, workspacelen);
1021 } else if (c && !strcmp(var, "HINT")) {
1022 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
1026 } else if (c && !strcmp(var, "HINTNAME")) {
1027 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
1031 } else if (c && !strcmp(var, "EXTEN")) {
1032 ast_copy_string(workspace, c->exten, workspacelen);
1034 } else if (c && !strcmp(var, "RDNIS")) {
1035 if (c->cid.cid_rdnis) {
1036 ast_copy_string(workspace, c->cid.cid_rdnis, workspacelen);
1040 } else if (c && !strcmp(var, "CONTEXT")) {
1041 ast_copy_string(workspace, c->context, workspacelen);
1043 } else if (c && !strcmp(var, "PRIORITY")) {
1044 snprintf(workspace, workspacelen, "%d", c->priority);
1046 } else if (c && !strcmp(var, "CHANNEL")) {
1047 ast_copy_string(workspace, c->name, workspacelen);
1049 } else if (!strcmp(var, "EPOCH")) {
1050 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1052 } else if (!strcmp(var, "DATETIME")) {
1053 thistime=time(NULL);
1054 localtime_r(&thistime, &brokentime);
1055 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
1057 brokentime.tm_mon+1,
1058 brokentime.tm_year+1900,
1064 } else if (!strcmp(var, "TIMESTAMP")) {
1065 thistime=time(NULL);
1066 localtime_r(&thistime, &brokentime);
1067 /* 20031130-150612 */
1068 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
1069 brokentime.tm_year+1900,
1070 brokentime.tm_mon+1,
1077 } else if (c && !strcmp(var, "UNIQUEID")) {
1078 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1080 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1081 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1083 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1084 ast_copy_string(workspace, c->accountcode, workspacelen);
1086 } else if (c && !strcmp(var, "LANGUAGE")) {
1087 ast_copy_string(workspace, c->language, workspacelen);
1092 AST_LIST_TRAVERSE(headp,variables,entries) {
1094 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1096 if (strcasecmp(ast_var_name(variables),var)==0) {
1097 *ret=ast_var_value(variables);
1099 ast_copy_string(workspace, *ret, workspacelen);
1108 AST_LIST_TRAVERSE(&globals,variables,entries) {
1110 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1112 if (strcasecmp(ast_var_name(variables),var)==0) {
1113 *ret = ast_var_value(variables);
1115 ast_copy_string(workspace, *ret, workspacelen);
1124 static int handle_show_functions(int fd, int argc, char *argv[])
1126 struct ast_custom_function *acf;
1129 ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
1130 for (acf = acf_root ; acf; acf = acf->next) {
1131 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1134 ast_cli(fd, "%d custom functions installed.\n", count_acf);
1138 static int handle_show_function(int fd, int argc, char *argv[])
1140 struct ast_custom_function *acf;
1141 /* Maximum number of characters added by terminal coloring is 22 */
1142 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1143 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1144 char stxtitle[40], *syntax = NULL;
1145 int synopsis_size, description_size, syntax_size;
1147 if (argc < 3) return RESULT_SHOWUSAGE;
1149 if (!(acf = ast_custom_function_find(argv[2]))) {
1150 ast_cli(fd, "No function by that name registered.\n");
1151 return RESULT_FAILURE;
1156 synopsis_size = strlen(acf->synopsis) + 23;
1158 synopsis_size = strlen("Not available") + 23;
1159 synopsis = alloca(synopsis_size);
1162 description_size = strlen(acf->desc) + 23;
1164 description_size = strlen("Not available") + 23;
1165 description = alloca(description_size);
1168 syntax_size = strlen(acf->syntax) + 23;
1170 syntax_size = strlen("Not available") + 23;
1171 syntax = alloca(syntax_size);
1173 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1174 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1175 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1176 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1177 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1179 acf->syntax ? acf->syntax : "Not available",
1180 COLOR_CYAN, 0, syntax_size);
1181 term_color(synopsis,
1182 acf->synopsis ? acf->synopsis : "Not available",
1183 COLOR_CYAN, 0, synopsis_size);
1184 term_color(description,
1185 acf->desc ? acf->desc : "Not available",
1186 COLOR_CYAN, 0, description_size);
1188 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1190 return RESULT_SUCCESS;
1193 static char *complete_show_function(char *line, char *word, int pos, int state)
1195 struct ast_custom_function *acf;
1198 /* try to lock functions list ... */
1199 if (ast_mutex_lock(&acflock)) {
1200 ast_log(LOG_ERROR, "Unable to lock function list\n");
1206 if (!strncasecmp(word, acf->name, strlen(word))) {
1207 if (++which > state) {
1208 char *ret = strdup(acf->name);
1209 ast_mutex_unlock(&acflock);
1216 ast_mutex_unlock(&acflock);
1220 struct ast_custom_function* ast_custom_function_find(char *name)
1222 struct ast_custom_function *acfptr;
1224 /* try to lock functions list ... */
1225 if (ast_mutex_lock(&acflock)) {
1226 ast_log(LOG_ERROR, "Unable to lock function list\n");
1230 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1231 if (!strcmp(name, acfptr->name)) {
1236 ast_mutex_unlock(&acflock);
1241 int ast_custom_function_unregister(struct ast_custom_function *acf)
1243 struct ast_custom_function *acfptr, *lastacf = NULL;
1249 /* try to lock functions list ... */
1250 if (ast_mutex_lock(&acflock)) {
1251 ast_log(LOG_ERROR, "Unable to lock function list\n");
1255 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1256 if (acfptr == acf) {
1258 lastacf->next = acf->next;
1260 acf_root = acf->next;
1268 ast_mutex_unlock(&acflock);
1270 if (!res && (option_verbose > 1))
1271 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1276 int ast_custom_function_register(struct ast_custom_function *acf)
1281 /* try to lock functions list ... */
1282 if (ast_mutex_lock(&acflock)) {
1283 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
1287 if (ast_custom_function_find(acf->name)) {
1288 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1289 ast_mutex_unlock(&acflock);
1293 acf->next = acf_root;
1296 ast_mutex_unlock(&acflock);
1298 if (option_verbose > 1)
1299 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1304 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1306 char *args = NULL, *function, *p;
1308 struct ast_custom_function *acfptr;
1310 function = ast_strdupa(in);
1312 ast_log(LOG_ERROR, "Out of memory\n");
1315 if ((args = strchr(function, '('))) {
1318 if ((p = strrchr(args, ')'))) {
1321 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1324 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1327 if ((acfptr = ast_custom_function_find(function))) {
1328 /* run the custom function */
1330 return acfptr->read(chan, function, args, workspace, len);
1332 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1335 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1340 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1342 char *args = NULL, *function, *p;
1343 struct ast_custom_function *acfptr;
1345 function = ast_strdupa(in);
1347 ast_log(LOG_ERROR, "Out of memory\n");
1350 if ((args = strchr(function, '('))) {
1353 if ((p = strrchr(args, ')'))) {
1356 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1359 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1362 if ((acfptr = ast_custom_function_find(function))) {
1363 /* run the custom function */
1364 if (acfptr->write) {
1365 acfptr->write(chan, function, args, value);
1367 ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
1370 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1374 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1377 const char *tmp, *whereweare;
1379 char workspace[4096];
1380 char ltmp[4096], var[4096];
1381 char *nextvar, *nextexp, *nextthing;
1383 int pos, brackets, needsub, len;
1385 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1388 while(!ast_strlen_zero(whereweare) && count) {
1389 /* Assume we're copying the whole remaining string */
1390 pos = strlen(whereweare);
1393 nextthing = strchr(whereweare, '$');
1395 switch(nextthing[1]) {
1397 nextvar = nextthing;
1400 nextexp = nextthing;
1404 /* If there is one, we only go that far */
1406 pos = nextvar - whereweare;
1408 pos = nextexp - whereweare;
1410 /* Can't copy more than 'count' bytes */
1414 /* Copy that many bytes */
1415 memcpy(cp2, whereweare, pos);
1422 /* We have a variable. Find the start and end, and determine
1423 if we are going to have to recursively call ourselves on the
1425 vars = vare = nextvar + 2;
1429 /* Find the end of it */
1430 while(brackets && *vare) {
1431 if ((vare[0] == '$') && (vare[1] == '{')) {
1434 } else if (vare[0] == '}') {
1436 } else if ((vare[0] == '$') && (vare[1] == '['))
1441 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1442 len = vare - vars - 1;
1444 /* Skip totally over variable name */
1445 whereweare += (len + 3);
1447 /* Store variable name (and truncate) */
1448 memset(var, 0, sizeof(var));
1449 ast_copy_string(var, vars, sizeof(var));
1452 /* Substitute if necessary */
1454 memset(ltmp, 0, sizeof(ltmp));
1455 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1461 workspace[0] = '\0';
1463 if (var[len - 1] == ')') {
1464 /* Evaluate function */
1465 cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
1467 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1469 /* Retrieve variable value */
1470 pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
1473 length = strlen(cp4);
1476 memcpy(cp2, cp4, length);
1480 } else if (nextexp) {
1481 /* We have an expression. Find the start and end, and determine
1482 if we are going to have to recursively call ourselves on the
1484 vars = vare = nextexp + 2;
1488 /* Find the end of it */
1489 while(brackets && *vare) {
1490 if ((vare[0] == '$') && (vare[1] == '[')) {
1494 } else if (vare[0] == '[') {
1496 } else if (vare[0] == ']') {
1498 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1505 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1506 len = vare - vars - 1;
1508 /* Skip totally over variable name */
1509 whereweare += ( len + 3);
1511 /* Store variable name (and truncate) */
1512 memset(var, 0, sizeof(var));
1513 ast_copy_string(var, vars, sizeof(var));
1516 /* Substitute if necessary */
1518 memset(ltmp, 0, sizeof(ltmp));
1519 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1525 length = ast_expr(vars, cp2, count);
1528 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1537 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1539 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1542 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1544 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1547 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1549 memset(passdata, 0, datalen);
1551 /* No variables or expressions in e->data, so why scan it? */
1552 if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1553 ast_copy_string(passdata, e->data, datalen);
1554 passdata[datalen-1] = '\0';
1558 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1561 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)
1563 struct ast_exten *e;
1564 struct ast_app *app;
1565 struct ast_switch *sw;
1567 const char *foundcontext=NULL;
1571 char *incstack[AST_PBX_MAX_STACK];
1572 char passdata[EXT_DATA_SIZE];
1576 char tmp3[EXT_DATA_SIZE];
1578 char atmp2[EXT_DATA_SIZE+100];
1580 if (ast_mutex_lock(&conlock)) {
1581 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1582 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1587 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1590 case HELPER_CANMATCH:
1591 ast_mutex_unlock(&conlock);
1594 ast_mutex_unlock(&conlock);
1596 case HELPER_FINDLABEL:
1598 ast_mutex_unlock(&conlock);
1600 case HELPER_MATCHMORE:
1601 ast_mutex_unlock(&conlock);
1607 app = pbx_findapp(e->app);
1608 ast_mutex_unlock(&conlock);
1610 if (c->context != context)
1611 ast_copy_string(c->context, context, sizeof(c->context));
1612 if (c->exten != exten)
1613 ast_copy_string(c->exten, exten, sizeof(c->exten));
1614 c->priority = priority;
1615 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1617 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1618 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1619 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
1620 pbx_builtin_setvar_helper(c, atmp, atmp2);
1622 if (option_verbose > 2)
1623 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1624 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1625 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1626 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1627 (newstack ? "in new stack" : "in same stack"));
1628 manager_event(EVENT_FLAG_CALL, "Newexten",
1633 "Application: %s\r\n"
1636 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1637 res = pbx_exec(c, app, passdata, newstack);
1640 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1644 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1648 case HELPER_CANMATCH:
1649 ast_mutex_unlock(&conlock);
1652 ast_mutex_unlock(&conlock);
1654 case HELPER_MATCHMORE:
1655 ast_mutex_unlock(&conlock);
1657 case HELPER_FINDLABEL:
1658 ast_mutex_unlock(&conlock);
1664 ast_mutex_unlock(&conlock);
1666 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1668 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1673 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1677 ast_mutex_unlock(&conlock);
1679 case STATUS_NO_CONTEXT:
1680 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1681 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1683 case STATUS_NO_EXTENSION:
1684 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1685 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1687 case STATUS_NO_PRIORITY:
1688 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1689 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1691 case STATUS_NO_LABEL:
1693 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1696 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1699 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1707 /*--- ast_hint_extension: Find hint for given extension in context */
1708 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1710 struct ast_exten *e;
1711 struct ast_switch *sw;
1713 const char *foundcontext = NULL;
1715 char *incstack[AST_PBX_MAX_STACK];
1718 if (ast_mutex_lock(&conlock)) {
1719 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1722 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1723 ast_mutex_unlock(&conlock);
1727 /*--- ast_extensions_state2: Check state of extension by using hints */
1728 static int ast_extension_state2(struct ast_exten *e)
1730 char hint[AST_MAX_EXTENSION] = "";
1733 int allunavailable = 1, allbusy = 1, allfree = 1;
1734 int busy = 0, inuse = 0, ring = 0;
1739 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1741 cur = hint; /* On or more devices separated with a & character */
1743 rest = strchr(cur, '&');
1749 res = ast_device_state(cur);
1751 case AST_DEVICE_NOT_INUSE:
1755 case AST_DEVICE_INUSE:
1760 case AST_DEVICE_RINGING:
1765 case AST_DEVICE_BUSY:
1770 case AST_DEVICE_UNAVAILABLE:
1771 case AST_DEVICE_INVALID:
1784 return AST_EXTENSION_RINGING;
1786 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1788 return AST_EXTENSION_INUSE;
1790 return AST_EXTENSION_NOT_INUSE;
1792 return AST_EXTENSION_BUSY;
1794 return AST_EXTENSION_UNAVAILABLE;
1796 return AST_EXTENSION_INUSE;
1798 return AST_EXTENSION_NOT_INUSE;
1801 /*--- ast_extension_state2str: Return extension_state as string */
1802 const char *ast_extension_state2str(int extension_state)
1806 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1807 if (extension_states[i].extension_state == extension_state) {
1808 return extension_states[i].text;
1814 /*--- ast_extension_state: Check extension state for an extension by using hint */
1815 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1817 struct ast_exten *e;
1819 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1821 return -1; /* No hint, return -1 */
1823 return ast_extension_state2(e); /* Check all devices in the hint */
1826 void ast_hint_state_changed(const char *device)
1828 struct ast_hint *hint;
1829 struct ast_state_cb *cblist;
1830 char buf[AST_MAX_EXTENSION];
1835 ast_mutex_lock(&hintlock);
1837 for (hint = hints; hint; hint = hint->next) {
1838 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1840 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1841 if (strcmp(cur, device))
1844 /* Get device state for this hint */
1845 state = ast_extension_state2(hint->exten);
1847 if ((state == -1) || (state == hint->laststate))
1850 /* Device state changed since last check - notify the watchers */
1852 /* For general callbacks */
1853 for (cblist = statecbs; cblist; cblist = cblist->next)
1854 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1856 /* For extension callbacks */
1857 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1858 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1860 hint->laststate = state;
1865 ast_mutex_unlock(&hintlock);
1868 /*--- ast_extension_state_add: Add watcher for extension states */
1869 int ast_extension_state_add(const char *context, const char *exten,
1870 ast_state_cb_type callback, void *data)
1872 struct ast_hint *list;
1873 struct ast_state_cb *cblist;
1874 struct ast_exten *e;
1876 /* If there's no context and extension: add callback to statecbs list */
1877 if (!context && !exten) {
1878 ast_mutex_lock(&hintlock);
1882 if (cblist->callback == callback) {
1883 cblist->data = data;
1884 ast_mutex_unlock(&hintlock);
1887 cblist = cblist->next;
1890 /* Now insert the callback */
1891 cblist = malloc(sizeof(struct ast_state_cb));
1893 ast_mutex_unlock(&hintlock);
1896 memset(cblist, 0, sizeof(struct ast_state_cb));
1898 cblist->callback = callback;
1899 cblist->data = data;
1901 cblist->next = statecbs;
1904 ast_mutex_unlock(&hintlock);
1908 if (!context || !exten)
1911 /* This callback type is for only one hint, so get the hint */
1912 e = ast_hint_extension(NULL, context, exten);
1917 /* Find the hint in the list of hints */
1918 ast_mutex_lock(&hintlock);
1922 if (list->exten == e)
1928 /* We have no hint, sorry */
1929 ast_mutex_unlock(&hintlock);
1933 /* Now insert the callback in the callback list */
1934 cblist = malloc(sizeof(struct ast_state_cb));
1936 ast_mutex_unlock(&hintlock);
1939 memset(cblist, 0, sizeof(struct ast_state_cb));
1940 cblist->id = stateid++; /* Unique ID for this callback */
1941 cblist->callback = callback; /* Pointer to callback routine */
1942 cblist->data = data; /* Data for the callback */
1944 cblist->next = list->callbacks;
1945 list->callbacks = cblist;
1947 ast_mutex_unlock(&hintlock);
1951 /*--- ast_extension_state_del: Remove a watcher from the callback list */
1952 int ast_extension_state_del(int id, ast_state_cb_type callback)
1954 struct ast_hint *list;
1955 struct ast_state_cb *cblist, *cbprev;
1957 if (!id && !callback)
1960 ast_mutex_lock(&hintlock);
1962 /* id is zero is a callback without extension */
1967 if (cblist->callback == callback) {
1969 statecbs = cblist->next;
1971 cbprev->next = cblist->next;
1975 ast_mutex_unlock(&hintlock);
1979 cblist = cblist->next;
1982 ast_mutex_lock(&hintlock);
1986 /* id greater than zero is a callback with extension */
1987 /* Find the callback based on ID */
1990 cblist = list->callbacks;
1993 if (cblist->id==id) {
1995 list->callbacks = cblist->next;
1997 cbprev->next = cblist->next;
2001 ast_mutex_unlock(&hintlock);
2005 cblist = cblist->next;
2010 ast_mutex_unlock(&hintlock);
2014 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
2015 static int ast_add_hint(struct ast_exten *e)
2017 struct ast_hint *list;
2022 ast_mutex_lock(&hintlock);
2025 /* Search if hint exists, do nothing */
2027 if (list->exten == e) {
2028 ast_mutex_unlock(&hintlock);
2029 if (option_debug > 1)
2030 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2036 if (option_debug > 1)
2037 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2039 list = malloc(sizeof(struct ast_hint));
2041 ast_mutex_unlock(&hintlock);
2042 if (option_debug > 1)
2043 ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
2046 /* Initialize and insert new item at the top */
2047 memset(list, 0, sizeof(struct ast_hint));
2049 list->laststate = ast_extension_state2(e);
2053 ast_mutex_unlock(&hintlock);
2057 /*--- ast_change_hint: Change hint for an extension */
2058 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2060 struct ast_hint *list;
2062 ast_mutex_lock(&hintlock);
2066 if (list->exten == oe) {
2068 ast_mutex_unlock(&hintlock);
2073 ast_mutex_unlock(&hintlock);
2078 /*--- ast_remove_hint: Remove hint from extension */
2079 static int ast_remove_hint(struct ast_exten *e)
2081 /* Cleanup the Notifys if hint is removed */
2082 struct ast_hint *list, *prev = NULL;
2083 struct ast_state_cb *cblist, *cbprev;
2088 ast_mutex_lock(&hintlock);
2092 if (list->exten==e) {
2094 cblist = list->callbacks;
2096 /* Notify with -1 and remove all callbacks */
2098 cblist = cblist->next;
2099 cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2102 list->callbacks = NULL;
2107 prev->next = list->next;
2110 ast_mutex_unlock(&hintlock);
2118 ast_mutex_unlock(&hintlock);
2123 /*--- ast_get_hint: Get hint for channel */
2124 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2126 struct ast_exten *e;
2129 e = ast_hint_extension(c, context, exten);
2132 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2134 tmp = ast_get_extension_app_data(e);
2136 ast_copy_string(name, (char *) tmp, namesize);
2143 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2145 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2148 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2150 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2153 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2155 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2158 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2160 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2163 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2165 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2168 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2170 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2173 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2175 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2178 static int __ast_pbx_run(struct ast_channel *c)
2188 /* A little initial setup here */
2190 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2191 c->pbx = malloc(sizeof(struct ast_pbx));
2193 ast_log(LOG_ERROR, "Out of memory\n");
2198 c->cdr = ast_cdr_alloc();
2200 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2204 ast_cdr_init(c->cdr, c);
2207 memset(c->pbx, 0, sizeof(struct ast_pbx));
2208 /* Set reasonable defaults */
2209 c->pbx->rtimeout = 10;
2210 c->pbx->dtimeout = 5;
2212 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2213 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2215 /* Start by trying whatever the channel is set to */
2216 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2217 /* If not successful fall back to 's' */
2218 if (option_verbose > 1)
2219 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);
2220 ast_copy_string(c->exten, "s", sizeof(c->exten));
2221 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2222 /* JK02: And finally back to default if everything else failed */
2223 if (option_verbose > 1)
2224 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);
2225 ast_copy_string(c->context, "default", sizeof(c->context));
2229 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2230 ast_cdr_start(c->cdr);
2234 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2235 memset(exten, 0, sizeof(exten));
2236 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2237 /* Something bad happened, or a hangup has been requested. */
2238 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2239 (res == '*') || (res == '#')) {
2240 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2241 memset(exten, 0, sizeof(exten));
2243 exten[pos++] = digit = res;
2247 case AST_PBX_KEEPALIVE:
2249 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2250 else if (option_verbose > 1)
2251 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2256 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2257 else if (option_verbose > 1)
2258 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2259 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2264 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2274 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2275 ast_copy_string(c->exten, "T", sizeof(c->exten));
2276 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2277 c->whentohangup = 0;
2279 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2280 } else if (c->_softhangup) {
2281 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2282 c->exten, c->priority);
2288 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2289 /* It's not a valid extension anymore */
2290 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2291 if (option_verbose > 2)
2292 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2293 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2294 ast_copy_string(c->exten, "i", sizeof(c->exten));
2297 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2298 c->name, c->exten, c->context);
2301 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2302 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2305 /* Done, wait for an extension */
2308 waittime = c->pbx->dtimeout;
2309 else if (!autofallthrough)
2310 waittime = c->pbx->rtimeout;
2312 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2313 /* As long as we're willing to wait, and as long as it's not defined,
2314 keep reading digits until we can't possibly get a right answer anymore. */
2315 digit = ast_waitfordigit(c, waittime * 1000);
2316 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2323 /* Error, maybe a hangup */
2325 exten[pos++] = digit;
2326 waittime = c->pbx->dtimeout;
2329 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2330 /* Prepare the next cycle */
2331 ast_copy_string(c->exten, exten, sizeof(c->exten));
2334 /* No such extension */
2335 if (!ast_strlen_zero(exten)) {
2336 /* An invalid extension */
2337 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2338 if (option_verbose > 2)
2339 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2340 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2341 ast_copy_string(c->exten, "i", sizeof(c->exten));
2344 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2348 /* A simple timeout */
2349 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2350 if (option_verbose > 2)
2351 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2352 ast_copy_string(c->exten, "t", sizeof(c->exten));
2355 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2361 if (option_verbose > 2)
2362 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2368 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2371 if (option_verbose > 2)
2372 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2373 if (!strcasecmp(status, "CONGESTION"))
2374 res = pbx_builtin_congestion(c, "10");
2375 else if (!strcasecmp(status, "CHANUNAVAIL"))
2376 res = pbx_builtin_congestion(c, "10");
2377 else if (!strcasecmp(status, "BUSY"))
2378 res = pbx_builtin_busy(c, "10");
2384 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2386 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2390 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2391 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2392 /* Something bad happened, or a hangup has been requested. */
2394 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2395 else if (option_verbose > 1)
2396 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2402 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2404 pbx_destroy(c->pbx);
2406 if (res != AST_PBX_KEEPALIVE)
2411 static void *pbx_thread(void *data)
2413 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2414 answer this channel and get it going. The setjmp stuff is fairly
2415 confusing, but necessary to get smooth transitions between
2416 the execution of different applications (without the use of
2417 additional threads) */
2418 struct ast_channel *c = data;
2424 int ast_pbx_start(struct ast_channel *c)
2427 pthread_attr_t attr;
2429 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2433 /* Start a new thread, and get something handling this channel. */
2434 pthread_attr_init(&attr);
2435 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2436 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2437 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2443 int ast_pbx_run(struct ast_channel *c)
2446 ast_mutex_lock(&maxcalllock);
2447 if (option_maxcalls) {
2448 if (countcalls >= option_maxcalls) {
2449 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2455 ast_mutex_unlock(&maxcalllock);
2457 res = __ast_pbx_run(c);
2458 ast_mutex_lock(&maxcalllock);
2461 ast_mutex_unlock(&maxcalllock);
2466 int ast_active_calls(void)
2471 int pbx_set_autofallthrough(int newval)
2474 oldval = autofallthrough;
2475 if (oldval != newval)
2476 autofallthrough = newval;
2481 * This function locks contexts list by &conlist, search for the right context
2482 * structure, leave context list locked and call ast_context_remove_include2
2483 * which removes include, unlock contexts list and return ...
2485 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2487 struct ast_context *c;
2489 if (ast_lock_contexts()) return -1;
2491 /* walk contexts and search for the right one ...*/
2492 c = ast_walk_contexts(NULL);
2494 /* we found one ... */
2495 if (!strcmp(ast_get_context_name(c), context)) {
2497 /* remove include from this context ... */
2498 ret = ast_context_remove_include2(c, include, registrar);
2500 ast_unlock_contexts();
2502 /* ... return results */
2505 c = ast_walk_contexts(c);
2508 /* we can't find the right one context */
2509 ast_unlock_contexts();
2514 * When we call this function, &conlock lock must be locked, because when
2515 * we giving *con argument, some process can remove/change this context
2516 * and after that there can be segfault.
2518 * This function locks given context, removes include, unlock context and
2521 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2523 struct ast_include *i, *pi = NULL;
2525 if (ast_mutex_lock(&con->lock)) return -1;
2530 /* find our include */
2531 if (!strcmp(i->name, include) &&
2532 (!registrar || !strcmp(i->registrar, registrar))) {
2533 /* remove from list */
2537 con->includes = i->next;
2538 /* free include and return */
2540 ast_mutex_unlock(&con->lock);
2547 /* we can't find the right include */
2548 ast_mutex_unlock(&con->lock);
2553 * This function locks contexts list by &conlist, search for the rigt context
2554 * structure, leave context list locked and call ast_context_remove_switch2
2555 * which removes switch, unlock contexts list and return ...
2557 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2559 struct ast_context *c;
2561 if (ast_lock_contexts()) return -1;
2563 /* walk contexts and search for the right one ...*/
2564 c = ast_walk_contexts(NULL);
2566 /* we found one ... */
2567 if (!strcmp(ast_get_context_name(c), context)) {
2569 /* remove switch from this context ... */
2570 ret = ast_context_remove_switch2(c, sw, data, registrar);
2572 ast_unlock_contexts();
2574 /* ... return results */
2577 c = ast_walk_contexts(c);
2580 /* we can't find the right one context */
2581 ast_unlock_contexts();
2586 * When we call this function, &conlock lock must be locked, because when
2587 * we giving *con argument, some process can remove/change this context
2588 * and after that there can be segfault.
2590 * This function locks given context, removes switch, unlock context and
2593 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2595 struct ast_sw *i, *pi = NULL;
2597 if (ast_mutex_lock(&con->lock)) return -1;
2602 /* find our switch */
2603 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2604 (!registrar || !strcmp(i->registrar, registrar))) {
2605 /* remove from list */
2609 con->alts = i->next;
2610 /* free switch and return */
2612 ast_mutex_unlock(&con->lock);
2619 /* we can't find the right switch */
2620 ast_mutex_unlock(&con->lock);
2625 * This functions lock contexts list, search for the right context,
2626 * call ast_context_remove_extension2, unlock contexts list and return.
2627 * In this function we are using
2629 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2631 struct ast_context *c;
2633 if (ast_lock_contexts()) return -1;
2635 /* walk contexts ... */
2636 c = ast_walk_contexts(NULL);
2638 /* ... search for the right one ... */
2639 if (!strcmp(ast_get_context_name(c), context)) {
2640 /* ... remove extension ... */
2641 int ret = ast_context_remove_extension2(c, extension, priority,
2643 /* ... unlock contexts list and return */
2644 ast_unlock_contexts();
2647 c = ast_walk_contexts(c);
2650 /* we can't find the right context */
2651 ast_unlock_contexts();
2656 * When do you want to call this function, make sure that &conlock is locked,
2657 * because some process can handle with your *con context before you lock
2660 * This functionc locks given context, search for the right extension and
2661 * fires out all peer in this extensions with given priority. If priority
2662 * is set to 0, all peers are removed. After that, unlock context and
2665 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2667 struct ast_exten *exten, *prev_exten = NULL;
2669 if (ast_mutex_lock(&con->lock)) return -1;
2671 /* go through all extensions in context and search the right one ... */
2675 /* look for right extension */
2676 if (!strcmp(exten->exten, extension) &&
2677 (!registrar || !strcmp(exten->registrar, registrar))) {
2678 struct ast_exten *peer;
2680 /* should we free all peers in this extension? (priority == 0)? */
2681 if (priority == 0) {
2682 /* remove this extension from context list */
2684 prev_exten->next = exten->next;
2686 con->root = exten->next;
2688 /* fire out all peers */
2693 if (!peer->priority==PRIORITY_HINT)
2694 ast_remove_hint(peer);
2696 peer->datad(peer->data);
2702 ast_mutex_unlock(&con->lock);
2705 /* remove only extension with exten->priority == priority */
2706 struct ast_exten *previous_peer = NULL;
2710 /* is this our extension? */
2711 if (peer->priority == priority &&
2712 (!registrar || !strcmp(peer->registrar, registrar) )) {
2713 /* we are first priority extension? */
2714 if (!previous_peer) {
2715 /* exists previous extension here? */
2717 /* yes, so we must change next pointer in
2718 * previous connection to next peer
2721 prev_exten->next = peer->peer;
2722 peer->peer->next = exten->next;
2724 prev_exten->next = exten->next;
2726 /* no previous extension, we are first
2727 * extension, so change con->root ...
2730 con->root = peer->peer;
2732 con->root = exten->next;
2735 /* we are not first priority in extension */
2736 previous_peer->peer = peer->peer;
2739 /* now, free whole priority extension */
2740 if (peer->priority==PRIORITY_HINT)
2741 ast_remove_hint(peer);
2742 peer->datad(peer->data);
2745 ast_mutex_unlock(&con->lock);
2748 /* this is not right extension, skip to next peer */
2749 previous_peer = peer;
2754 ast_mutex_unlock(&con->lock);
2760 exten = exten->next;
2763 /* we can't find right extension */
2764 ast_mutex_unlock(&con->lock);
2769 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2771 struct ast_app *tmp, *prev, *cur;
2774 length = sizeof(struct ast_app);
2775 length += strlen(app) + 1;
2776 if (ast_mutex_lock(&applock)) {
2777 ast_log(LOG_ERROR, "Unable to lock application list\n");
2782 if (!strcasecmp(app, tmp->name)) {
2783 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2784 ast_mutex_unlock(&applock);
2789 tmp = malloc(length);
2791 memset(tmp, 0, length);
2792 strcpy(tmp->name, app);
2793 tmp->execute = execute;
2794 tmp->synopsis = synopsis;
2795 tmp->description = description;
2796 /* Store in alphabetical order */
2800 if (strcasecmp(tmp->name, cur->name) < 0)
2806 tmp->next = prev->next;
2813 ast_log(LOG_ERROR, "Out of memory\n");
2814 ast_mutex_unlock(&applock);
2817 if (option_verbose > 1)
2818 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2819 ast_mutex_unlock(&applock);
2823 int ast_register_switch(struct ast_switch *sw)
2825 struct ast_switch *tmp, *prev=NULL;
2826 if (ast_mutex_lock(&switchlock)) {
2827 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2832 if (!strcasecmp(tmp->name, sw->name))
2838 ast_mutex_unlock(&switchlock);
2839 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2847 ast_mutex_unlock(&switchlock);
2851 void ast_unregister_switch(struct ast_switch *sw)
2853 struct ast_switch *tmp, *prev=NULL;
2854 if (ast_mutex_lock(&switchlock)) {
2855 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2862 prev->next = tmp->next;
2864 switches = tmp->next;
2871 ast_mutex_unlock(&switchlock);
2875 * Help for CLI commands ...
2877 static char show_application_help[] =
2878 "Usage: show application <application> [<application> [<application> [...]]]\n"
2879 " Describes a particular application.\n";
2881 static char show_functions_help[] =
2882 "Usage: show functions\n"
2883 " List builtin functions accessable as $(function args)\n";
2885 static char show_function_help[] =
2886 "Usage: show function <function>\n"
2887 " Describe a particular dialplan function.\n";
2889 static char show_applications_help[] =
2890 "Usage: show applications [{like|describing} <text>]\n"
2891 " List applications which are currently available.\n"
2892 " If 'like', <text> will be a substring of the app name\n"
2893 " If 'describing', <text> will be a substring of the description\n";
2895 static char show_dialplan_help[] =
2896 "Usage: show dialplan [exten@][context]\n"
2899 static char show_switches_help[] =
2900 "Usage: show switches\n"
2901 " Show registered switches\n";
2903 static char show_hints_help[] =
2904 "Usage: show hints\n"
2905 " Show registered hints\n";
2909 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2914 * 'show application' CLI command implementation functions ...
2918 * There is a possibility to show informations about more than one
2919 * application at one time. You can type 'show application Dial Echo' and
2920 * you will see informations about these two applications ...
2922 static char *complete_show_application(char *line, char *word,
2928 /* try to lock applications list ... */
2929 if (ast_mutex_lock(&applock)) {
2930 ast_log(LOG_ERROR, "Unable to lock application list\n");
2934 /* ... walk all applications ... */
2937 /* ... check if word matches this application ... */
2938 if (!strncasecmp(word, a->name, strlen(word))) {
2939 /* ... if this is right app serve it ... */
2940 if (++which > state) {
2941 char *ret = strdup(a->name);
2942 ast_mutex_unlock(&applock);
2949 /* no application match */
2950 ast_mutex_unlock(&applock);
2954 static int handle_show_application(int fd, int argc, char *argv[])
2957 int app, no_registered_app = 1;
2959 if (argc < 3) return RESULT_SHOWUSAGE;
2961 /* try to lock applications list ... */
2962 if (ast_mutex_lock(&applock)) {
2963 ast_log(LOG_ERROR, "Unable to lock application list\n");
2967 /* ... go through all applications ... */
2970 /* ... compare this application name with all arguments given
2971 * to 'show application' command ... */
2972 for (app = 2; app < argc; app++) {
2973 if (!strcasecmp(a->name, argv[app])) {
2974 /* Maximum number of characters added by terminal coloring is 22 */
2975 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2976 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2977 int synopsis_size, description_size;
2979 no_registered_app = 0;
2982 synopsis_size = strlen(a->synopsis) + 23;
2984 synopsis_size = strlen("Not available") + 23;
2985 synopsis = alloca(synopsis_size);
2988 description_size = strlen(a->description) + 23;
2990 description_size = strlen("Not available") + 23;
2991 description = alloca(description_size);
2993 if (synopsis && description) {
2994 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2995 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2996 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2997 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2998 term_color(synopsis,
2999 a->synopsis ? a->synopsis : "Not available",
3000 COLOR_CYAN, 0, synopsis_size);
3001 term_color(description,
3002 a->description ? a->description : "Not available",
3003 COLOR_CYAN, 0, description_size);
3005 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
3007 /* ... one of our applications, show info ...*/
3008 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
3009 "[Synopsis]\n %s\n\n"
3010 "[Description]\n%s\n",
3012 a->synopsis ? a->synopsis : "Not available",
3013 a->description ? a->description : "Not available");
3020 ast_mutex_unlock(&applock);
3022 /* we found at least one app? no? */
3023 if (no_registered_app) {
3024 ast_cli(fd, "Your application(s) is (are) not registered\n");
3025 return RESULT_FAILURE;
3028 return RESULT_SUCCESS;
3031 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
3032 static int handle_show_hints(int fd, int argc, char *argv[])
3034 struct ast_hint *hint;
3037 struct ast_state_cb *watcher;
3040 ast_cli(fd, "There are no registered dialplan hints\n");
3041 return RESULT_SUCCESS;
3043 /* ... we have hints ... */
3044 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
3045 if (ast_mutex_lock(&hintlock)) {
3046 ast_log(LOG_ERROR, "Unable to lock hints\n");
3052 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
3054 ast_cli(fd, " %-20.20s: %-20.20s State %2d Watchers %2d\n",
3055 ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten),
3056 hint->laststate, watchers);
3060 ast_cli(fd, "----------------\n");
3061 ast_cli(fd, "- %d hints registred\n", num);
3062 ast_mutex_unlock(&hintlock);
3063 return RESULT_SUCCESS;
3066 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
3067 static int handle_show_switches(int fd, int argc, char *argv[])
3069 struct ast_switch *sw;
3071 ast_cli(fd, "There are no registered alternative switches\n");
3072 return RESULT_SUCCESS;
3074 /* ... we have applications ... */
3075 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
3076 if (ast_mutex_lock(&switchlock)) {
3077 ast_log(LOG_ERROR, "Unable to lock switches\n");
3082 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3085 ast_mutex_unlock(&switchlock);
3086 return RESULT_SUCCESS;
3090 * 'show applications' CLI command implementation functions ...
3092 static int handle_show_applications(int fd, int argc, char *argv[])
3095 int like=0, describing=0;
3096 int total_match = 0; /* Number of matches in like clause */
3097 int total_apps = 0; /* Number of apps registered */
3099 /* try to lock applications list ... */
3100 if (ast_mutex_lock(&applock)) {
3101 ast_log(LOG_ERROR, "Unable to lock application list\n");
3105 /* ... have we got at least one application (first)? no? */
3107 ast_cli(fd, "There are no registered applications\n");
3108 ast_mutex_unlock(&applock);
3112 /* show applications like <keyword> */
3113 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3115 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3119 /* show applications describing <keyword1> [<keyword2>] [...] */
3120 if ((!like) && (!describing)) {
3121 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3123 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3126 /* ... go through all applications ... */
3127 for (a = apps; a; a = a->next) {
3128 /* ... show informations about applications ... */
3132 if (strcasestr(a->name, argv[3])) {
3136 } else if (describing) {
3137 if (a->description) {
3138 /* Match all words on command line */
3141 for (i=3; i<argc; i++) {
3142 if (!strcasestr(a->description, argv[i])) {
3154 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3157 if ((!like) && (!describing)) {
3158 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3160 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3163 /* ... unlock and return */
3164 ast_mutex_unlock(&applock);
3166 return RESULT_SUCCESS;
3169 static char *complete_show_applications(char *line, char *word, int pos, int state)
3172 if (ast_strlen_zero(word)) {
3175 return strdup("like");
3177 return strdup("describing");
3181 } else if (! strncasecmp(word, "like", strlen(word))) {
3183 return strdup("like");
3187 } else if (! strncasecmp(word, "describing", strlen(word))) {
3189 return strdup("describing");
3199 * 'show dialplan' CLI command implementation functions ...
3201 static char *complete_show_dialplan_context(char *line, char *word, int pos,
3204 struct ast_context *c;
3207 /* we are do completion of [exten@]context on second position only */
3208 if (pos != 2) return NULL;
3210 /* try to lock contexts list ... */
3211 if (ast_lock_contexts()) {
3212 ast_log(LOG_ERROR, "Unable to lock context list\n");
3216 /* ... walk through all contexts ... */
3217 c = ast_walk_contexts(NULL);
3219 /* ... word matches context name? yes? ... */
3220 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
3221 /* ... for serve? ... */
3222 if (++which > state) {
3223 /* ... yes, serve this context name ... */
3224 char *ret = strdup(ast_get_context_name(c));
3225 ast_unlock_contexts();
3229 c = ast_walk_contexts(c);
3232 /* ... unlock and return */
3233 ast_unlock_contexts();
3237 struct dialplan_counters {
3241 int context_existence;
3242 int extension_existence;
3245 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
3247 struct ast_context *c;
3248 int res=0, old_total_exten = dpc->total_exten;
3250 /* try to lock contexts */
3251 if (ast_lock_contexts()) {
3252 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3256 /* walk all contexts ... */
3257 for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
3258 /* show this context? */
3260 !strcmp(ast_get_context_name(c), context)) {
3261 dpc->context_existence = 1;
3263 /* try to lock context before walking in ... */
3264 if (!ast_lock_context(c)) {
3265 struct ast_exten *e;
3266 struct ast_include *i;
3267 struct ast_ignorepat *ip;
3269 char buf[256], buf2[256];
3270 int context_info_printed = 0;
3272 /* are we looking for exten too? if yes, we print context
3273 * if we our extension only
3276 dpc->total_context++;
3277 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3278 ast_get_context_name(c), ast_get_context_registrar(c));
3279 context_info_printed = 1;
3282 /* walk extensions ... */
3283 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3284 struct ast_exten *p;
3287 /* looking for extension? is this our extension? */
3289 !ast_extension_match(ast_get_extension_name(e), exten))
3291 /* we are looking for extension and it's not our
3292 * extension, so skip to next extension */
3296 dpc->extension_existence = 1;
3298 /* may we print context info? */
3299 if (!context_info_printed) {
3300 dpc->total_context++;
3302 /* TODO Print more info about rinclude */
3303 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3304 ast_get_context_name(c),
3305 ast_get_context_registrar(c));
3307 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3308 ast_get_context_name(c),
3309 ast_get_context_registrar(c));
3311 context_info_printed = 1;
3315 /* write extension name and first peer */
3316 bzero(buf, sizeof(buf));
3317 snprintf(buf, sizeof(buf), "'%s' =>",
3318 ast_get_extension_name(e));
3320 prio = ast_get_extension_priority(e);
3321 if (prio == PRIORITY_HINT) {
3322 snprintf(buf2, sizeof(buf2),
3324 ast_get_extension_app(e));
3326 snprintf(buf2, sizeof(buf2),
3329 ast_get_extension_app(e),
3330 (char *)ast_get_extension_app_data(e));
3333 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3334 ast_get_extension_registrar(e));
3337 /* walk next extension peers */
3338 for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3340 bzero((void *)buf2, sizeof(buf2));
3341 bzero((void *)buf, sizeof(buf));
3342 if (ast_get_extension_label(p))
3343 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
3344 prio = ast_get_extension_priority(p);
3345 if (prio == PRIORITY_HINT) {
3346 snprintf(buf2, sizeof(buf2),
3348 ast_get_extension_app(p));
3350 snprintf(buf2, sizeof(buf2),
3353 ast_get_extension_app(p),
3354 (char *)ast_get_extension_app_data(p));
3357 ast_cli(fd," %-17s %-45s [%s]\n",
3359 ast_get_extension_registrar(p));
3363 /* walk included and write info ... */
3364 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3365 bzero(buf, sizeof(buf));
3366 snprintf(buf, sizeof(buf), "'%s'",
3367 ast_get_include_name(i));
3369 /* Check all includes for the requested extension */
3370 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
3372 ast_cli(fd, " Include => %-45s [%s]\n",
3373 buf, ast_get_include_registrar(i));
3377 /* walk ignore patterns and write info ... */
3378 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
3379 const char *ipname = ast_get_ignorepat_name(ip);
3380 char ignorepat[AST_MAX_EXTENSION];
3381 snprintf(buf, sizeof(buf), "'%s'", ipname);
3382 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3383 if ((!exten) || ast_extension_match(ignorepat, exten)) {
3384 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3385 buf, ast_get_ignorepat_registrar(ip));
3389 for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
3390 snprintf(buf, sizeof(buf), "'%s/%s'",
3391 ast_get_switch_name(sw),
3392 ast_get_switch_data(sw));
3393 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3394 buf, ast_get_switch_registrar(sw));
3398 ast_unlock_context(c);
3400 /* if we print something in context, make an empty line */
3401 if (context_info_printed) ast_cli(fd, "\r\n");
3405 ast_unlock_contexts();
3407 if (dpc->total_exten == old_total_exten) {
3408 /* Nothing new under the sun */
3415 static int handle_show_dialplan(int fd, int argc, char *argv[])
3417 char *exten = NULL, *context = NULL;
3418 /* Variables used for different counters */
3419 struct dialplan_counters counters;