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)
76 AST_DECLARE_OPTIONS(background_opts,{
77 ['s'] = { BACKGROUND_SKIP },
78 ['n'] = { BACKGROUND_NOANSWER },
81 #define WAITEXTEN_MOH (1 << 0)
83 AST_DECLARE_OPTIONS(waitexten_opts,{
84 ['m'] = { WAITEXTEN_MOH, 1 },
89 /* ast_exten: An extension */
91 char *exten; /* Extension name */
92 int matchcid; /* Match caller id ? */
93 char *cidmatch; /* Caller id to match for this extension */
94 int priority; /* Priority */
95 char *label; /* Label */
96 struct ast_context *parent; /* The context this extension belongs to */
97 char *app; /* Application to execute */
98 void *data; /* Data to use (arguments) */
99 void (*datad)(void *); /* Data destructor */
100 struct ast_exten *peer; /* Next higher priority with our extension */
101 const char *registrar; /* Registrar */
102 struct ast_exten *next; /* Extension with a greater ID */
106 /* ast_include: include= support in extensions.conf */
109 char *rname; /* Context to include */
110 const char *registrar; /* Registrar */
111 int hastime; /* If time construct exists */
112 struct ast_timing timing; /* time construct */
113 struct ast_include *next; /* Link them together */
117 /* ast_sw: Switch statement in extensions.conf */
120 const char *registrar; /* Registrar */
121 char *data; /* Data load */
123 struct ast_sw *next; /* Link them together */
128 struct ast_ignorepat {
129 const char *registrar;
130 struct ast_ignorepat *next;
134 /* ast_context: An extension context */
136 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
137 struct ast_exten *root; /* The root of the list of extensions */
138 struct ast_context *next; /* Link them together */
139 struct ast_include *includes; /* Include other contexts */
140 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
141 const char *registrar; /* Registrar */
142 struct ast_sw *alts; /* Alternative switches */
143 char name[0]; /* Name of the context */
147 /* ast_app: An application */
149 int (*execute)(struct ast_channel *chan, void *data);
150 const char *synopsis; /* Synopsis text for 'show applications' */
151 const char *description; /* Description (help text) for 'show application <name>' */
152 struct ast_app *next; /* Next app in list */
153 char name[0]; /* Name of the application */
156 /* ast_state_cb: An extension state notify */
157 struct ast_state_cb {
160 ast_state_cb_type callback;
161 struct ast_state_cb *next;
164 /* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
166 struct ast_exten *exten; /* Extension */
167 int laststate; /* Last known state */
168 struct ast_state_cb *callbacks; /* Callback list for this extension */
169 struct ast_hint *next; /* Pointer to next hint in list */
172 int ast_pbx_outgoing_cdr_failed(void);
174 static int pbx_builtin_prefix(struct ast_channel *, void *);
175 static int pbx_builtin_suffix(struct ast_channel *, void *);
176 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
177 static int pbx_builtin_answer(struct ast_channel *, void *);
178 static int pbx_builtin_goto(struct ast_channel *, void *);
179 static int pbx_builtin_hangup(struct ast_channel *, void *);
180 static int pbx_builtin_background(struct ast_channel *, void *);
181 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
182 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
183 static int pbx_builtin_atimeout(struct ast_channel *, void *);
184 static int pbx_builtin_wait(struct ast_channel *, void *);
185 static int pbx_builtin_waitexten(struct ast_channel *, void *);
186 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
187 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
188 static int pbx_builtin_setaccount(struct ast_channel *, void *);
189 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
190 static int pbx_builtin_ringing(struct ast_channel *, void *);
191 static int pbx_builtin_progress(struct ast_channel *, void *);
192 static int pbx_builtin_congestion(struct ast_channel *, void *);
193 static int pbx_builtin_busy(struct ast_channel *, void *);
194 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
195 static int pbx_builtin_noop(struct ast_channel *, void *);
196 static int pbx_builtin_gotoif(struct ast_channel *, void *);
197 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
198 static int pbx_builtin_execiftime(struct ast_channel *, void *);
199 static int pbx_builtin_saynumber(struct ast_channel *, void *);
200 static int pbx_builtin_saydigits(struct ast_channel *, void *);
201 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
202 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
203 static int pbx_builtin_setvar_old(struct ast_channel *, void *);
204 int pbx_builtin_setvar(struct ast_channel *, void *);
205 static int pbx_builtin_importvar(struct ast_channel *, void *);
207 static struct varshead globals;
209 static int autofallthrough = 0;
211 AST_MUTEX_DEFINE_STATIC(maxcalllock);
212 static int countcalls = 0;
214 AST_MUTEX_DEFINE_STATIC(acflock); /* Lock for the custom function list */
215 static struct ast_custom_function *acf_root = NULL;
217 static struct pbx_builtin {
218 char name[AST_MAX_APP];
219 int (*execute)(struct ast_channel *chan, void *data);
224 /* These applications are built into the PBX core and do not
225 need separate modules
229 { "AbsoluteTimeout", pbx_builtin_atimeout,
230 "Set absolute maximum time of call",
231 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
232 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
233 "AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
236 { "Answer", pbx_builtin_answer,
237 "Answer a channel if ringing",
238 " Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
239 "If delay is specified, asterisk will pause execution for the specified amount\n"
240 "of milliseconds if an answer is required, in order to give audio a chance to\n"
241 "become ready. Returns 0 unless it tries to answer the channel and fails.\n"
244 { "BackGround", pbx_builtin_background,
245 "Play a file while awaiting extension",
246 " Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
247 "given files, while simultaneously waiting for the user to begin typing\n"
248 "an extension. The timeouts do not count until the last BackGround\n"
249 "application has ended. Options may also be included following a pipe \n"
250 "symbol. The 'langoverride' may be a language to use for playing the prompt\n"
251 "which differs from the current language of the channel. Returns -1 if \n"
252 "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
254 " 's' - causes the playback of the message to be skipped\n"
255 " if the channel is not in the 'up' state (i.e. it\n"
256 " hasn't been answered yet.) If this happens, the\n"
257 " application will return immediately.\n"
258 " 'n' - don't answer the channel before playing the files\n"
261 { "Busy", pbx_builtin_busy,
262 "Indicate busy condition and stop",
263 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
264 "then waits for the user to hang up or the optional timeout to expire.\n"
268 { "Congestion", pbx_builtin_congestion,
269 "Indicate congestion and stop",
270 " Congestion([timeout]): Requests that the channel indicate congestion\n"
271 "and then waits for the user to hang up or for the optional timeout to\n"
272 "expire. Always returns -1."
275 { "DigitTimeout", pbx_builtin_dtimeout,
276 "Set maximum timeout between digits",
277 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
278 "digits when the user is typing in an extension. When this timeout expires,\n"
279 "after the user has started to type in an extension, the extension will be\n"
280 "considered complete, and will be interpreted. Note that if an extension\n"
281 "typed in is valid, it will not have to timeout to be tested, so typically\n"
282 "at the expiry of this timeout, the extension will be considered invalid\n"
283 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
284 "exist the call would be terminated). The default timeout is 5 seconds.\n"
285 "Always returns 0.\n"
286 "DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout)\n"
289 { "Goto", pbx_builtin_goto,
290 "Goto a particular priority, extension, or context",
291 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
292 "value, optionally setting the extension and optionally the context as well.\n"
293 "The extension BYEXTENSION is special in that it uses the current extension,\n"
294 "thus permitting you to go to a different context, without specifying a\n"
295 "specific extension. Always returns 0, even if the given context, extension,\n"
296 "or priority is invalid.\n"
299 { "GotoIf", pbx_builtin_gotoif,
301 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
302 "true, to label2 if condition is false. Either label1 or label2 may be\n"
303 "omitted (in that case, we just don't take the particular branch) but not\n"
304 "both. Look for the condition syntax in examples or documentation."
307 { "GotoIfTime", pbx_builtin_gotoiftime,
308 "Conditional goto on current time",
309 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
310 "If the current time matches the specified time, then branch to the specified\n"
311 "extension. Each of the elements may be specified either as '*' (for always)\n"
312 "or as a range. See the 'include' syntax for details."
315 { "ExecIfTime", pbx_builtin_execiftime,
316 "Conditional application execution on current time",
317 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?<appname>[|<appdata>]):\n"
318 "If the current time matches the specified time, then execute the specified\n"
319 "application. Each of the elements may be specified either as '*' (for always)\n"
320 "or as a range. See the 'include' syntax for details. It will return whatever\n"
321 "<appname> returns, or a non-zero value if the application is not found.\n"
324 { "Hangup", pbx_builtin_hangup,
325 "Unconditional hangup",
326 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
329 { "NoOp", pbx_builtin_noop,
331 " NoOp(): No-operation; Does nothing."
334 { "Prefix", pbx_builtin_prefix,
335 "Prepend leading digits",
336 " Prefix(digits): Prepends the digit string specified by digits to the\n"
337 "channel's associated extension. For example, the number 1212 when prefixed\n"
338 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
339 "continue processing at the next priority for the *new* extension.\n"
340 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
341 "executed will be priority 4 of 5551212. If you switch into an extension\n"
342 "which has no first step, the PBX will treat it as though the user dialed an\n"
343 "invalid extension.\n"
346 { "Progress", pbx_builtin_progress,
348 " Progress(): Request that the channel indicate in-band progress is \n"
349 "available to the user.\nAlways returns 0.\n"
352 { "ResetCDR", pbx_builtin_resetcdr,
353 "Resets the Call Data Record",
354 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
355 "storing the current CDR before zeroing it out\b"
356 " - if 'w' option is specified record will be stored.\n"
357 " - if 'a' option is specified any stacked records will be stored.\n"
358 " - if 'v' option is specified any variables will be saved.\n"
359 "Always returns 0.\n"
362 { "ResponseTimeout", pbx_builtin_rtimeout,
363 "Set maximum timeout awaiting response",
364 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
365 "falling through a series of priorities for a channel in which the user may\n"
366 "begin typing an extension. If the user does not type an extension in this\n"
367 "amount of time, control will pass to the 't' extension if it exists, and\n"
368 "if not the call would be terminated. The default timeout is 10 seconds.\n"
369 "Always returns 0.\n"
370 "ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout)\n"
373 { "Ringing", pbx_builtin_ringing,
374 "Indicate ringing tone",
375 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
376 "Always returns 0.\n"
379 { "SayNumber", pbx_builtin_saynumber,
381 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
382 "the current language setting for the channel. (See app SetLanguage).\n"
385 { "SayDigits", pbx_builtin_saydigits,
387 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
388 "current language setting for the channel. (See app setLanguage)\n"
391 { "SayAlpha", pbx_builtin_saycharacters,
393 " SayAlpha(string): Spells the passed string\n"
396 { "SayPhonetic", pbx_builtin_sayphonetic,
398 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
401 { "SetAccount", pbx_builtin_setaccount,
403 " SetAccount([account]): Set the channel account code for billing\n"
404 "purposes. Always returns 0.\n"
407 { "SetAMAFlags", pbx_builtin_setamaflags,
409 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
410 "purposes. Always returns 0.\n"
413 { "SetGlobalVar", pbx_builtin_setglobalvar,
414 "Set global variable to value",
415 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
416 "variable are available across channels.\n"
419 { "SetLanguage", pbx_builtin_setlanguage,
420 "Sets channel language",
421 " SetLanguage(language): Set the channel language to 'language'. This\n"
422 "information is used for the syntax in generation of numbers, and to choose\n"
423 "a natural language file when available.\n"
424 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
425 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
426 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
427 "For some language codes, SetLanguage also changes the syntax of some\n"
428 "Asterisk functions, like SayNumber.\n"
429 "Always returns 0.\n"
430 "SetLanguage has been deprecated in favor of Set(LANGUAGE()=language)\n"
433 { "Set", pbx_builtin_setvar,
434 "Set channel variable(s) or function value(s)",
435 " Set(name1=value1|name2=value2|..[|options])\n"
436 "This function can be used to set the value of channel variables\n"
437 "or dialplan functions. It will accept up to 24 name/value pairs.\n"
438 "When setting variables, if the variable name is prefixed with _,\n"
439 "the variable will be inherited into channels created from the\n"
440 "current channel. If the variable name is prefixed with __,\n"
441 "the variable will be inherited into channels created from the\n"
442 "current channel and all child channels.\n"
443 "The last argument, if it does not contain '=', is interpreted\n"
444 "as a string of options. The valid options are:\n"
445 " g - Set variable globally instead of on the channel\n"
446 " (applies only to variables, not functions)\n"
449 { "SetVar", pbx_builtin_setvar_old,
450 "Set channel variable(s)",
451 " SetVar(name1=value1|name2=value2|..[|options])\n"
452 "SetVar has been deprecated in favor of Set.\n"
455 { "ImportVar", pbx_builtin_importvar,
456 "Import a variable from a channel into a new variable",
457 " ImportVar(newvar=channelname|variable): This application imports a\n"
458 "variable from the specified channel (as opposed to the current one)\n"
459 "and stores it as a variable in the current channel (the channel that\n"
460 "is calling this application). If the new variable name is prefixed by\n"
461 "a single underscore \"_\", then it will be inherited into any channels\n"
462 "created from this one. If it is prefixed with two underscores,then\n"
463 "the variable will have infinite inheritance, meaning that it will be\n"
464 "present in any descendent channel of this one.\n"
467 { "StripMSD", pbx_builtin_stripmsd,
468 "Strip leading digits",
469 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
470 "associated extension. For example, the number 5551212 when stripped with a\n"
471 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
472 "will continue processing at the next priority for the *new* extension.\n"
473 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
474 "executed will be priority 4 of 1212. If you switch into an extension which\n"
475 "has no first step, the PBX will treat it as though the user dialed an\n"
476 "invalid extension.\n"
479 { "Suffix", pbx_builtin_suffix,
480 "Append trailing digits",
481 " Suffix(digits): Appends the digit string specified by digits to the\n"
482 "channel's associated extension. For example, the number 555 when suffixed\n"
483 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
484 "continue processing at the next priority for the *new* extension.\n"
485 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
486 "executed will be priority 4 of 5551212. If you switch into an extension\n"
487 "which has no first step, the PBX will treat it as though the user dialed an\n"
488 "invalid extension.\n"
491 { "Wait", pbx_builtin_wait,
492 "Waits for some time",
493 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
494 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
497 { "WaitExten", pbx_builtin_waitexten,
498 "Waits for an extension to be entered",
499 " WaitExten([seconds][|options]): Waits for the user to enter a new extension for the \n"
500 "specified number of seconds, then returns 0. Seconds can be passed with\n"
501 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
502 "default extension timeout will be used.\n"
504 " 'm[(x)]' - Provide music on hold to the caller while waiting for an extension.\n"
505 " Optionally, specify the class for music on hold within parenthesis.\n"
510 static struct ast_context *contexts = NULL;
511 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
512 static struct ast_app *apps = NULL;
513 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
515 struct ast_switch *switches = NULL;
516 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
518 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
519 static int stateid = 1;
520 struct ast_hint *hints = NULL;
521 struct ast_state_cb *statecbs = NULL;
523 int pbx_exec(struct ast_channel *c, /* Channel */
524 struct ast_app *app, /* Application */
525 void *data, /* Data for execution */
526 int newstack) /* Force stack increment */
528 /* This function is special. It saves the stack so that no matter
529 how many times it is called, it returns to the same place */
535 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
539 ast_cdr_setapp(c->cdr, app->name, data);
541 /* save channel values */
542 saved_c_appl= c->appl;
543 saved_c_data= c->data;
547 res = execute(c, data);
548 /* restore channel values */
549 c->appl= saved_c_appl;
550 c->data= saved_c_data;
553 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
558 /* Go no deeper than this through includes (not counting loops) */
559 #define AST_PBX_MAX_STACK 128
561 #define HELPER_EXISTS 0
562 #define HELPER_SPAWN 1
563 #define HELPER_EXEC 2
564 #define HELPER_CANMATCH 3
565 #define HELPER_MATCHMORE 4
566 #define HELPER_FINDLABEL 5
568 struct ast_app *pbx_findapp(const char *app)
572 if (ast_mutex_lock(&applock)) {
573 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
578 if (!strcasecmp(tmp->name, app))
582 ast_mutex_unlock(&applock);
586 static struct ast_switch *pbx_findswitch(const char *sw)
588 struct ast_switch *asw;
590 if (ast_mutex_lock(&switchlock)) {
591 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
596 if (!strcasecmp(asw->name, sw))
600 ast_mutex_unlock(&switchlock);
604 static inline int include_valid(struct ast_include *i)
609 return ast_check_timing(&(i->timing));
612 static void pbx_destroy(struct ast_pbx *p)
617 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
618 /* All patterns begin with _ */\
619 if (pattern[0] != '_') \
621 /* Start optimistic */\
624 while(match && *data && *pattern && (*pattern != '/')) {\
625 while (*data == '-' && (*(data+1) != '\0')) data++;\
626 switch(toupper(*pattern)) {\
633 where=strchr(pattern,']');\
635 border=(int)(where-pattern);\
636 if (!where || border > strlen(pattern)) {\
637 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
640 for (i=0; i<border; i++) {\
643 if (pattern[i+1]=='-') {\
644 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
651 if (res==1 || *data==pattern[i]) {\
660 if ((*data < '2') || (*data > '9'))\
664 if ((*data < '0') || (*data > '9'))\
668 if ((*data < '1') || (*data > '9'))\
679 /* Ignore these characters */\
683 if (*data != *pattern)\
689 /* If we ran off the end of the data and the pattern ends in '!', match */\
690 if (match && !*data && (*pattern == '!'))\
694 int ast_extension_match(const char *pattern, const char *data)
697 /* If they're the same return */
698 if (!strcmp(pattern, data))
700 EXTENSION_MATCH_CORE(data,pattern,match);
701 /* Must be at the end of both */
702 if (*data || (*pattern && (*pattern != '/')))
707 int ast_extension_close(const char *pattern, const char *data, int needmore)
710 /* If "data" is longer, it can'be a subset of pattern unless
711 pattern is a pattern match */
712 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
715 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
716 (!needmore || (strlen(pattern) > strlen(data)))) {
719 EXTENSION_MATCH_CORE(data,pattern,match);
720 /* If there's more or we don't care about more, or if it's a possible early match,
721 return non-zero; otherwise it's a miss */
722 if (!needmore || *pattern || match == 2) {
728 struct ast_context *ast_context_find(const char *name)
730 struct ast_context *tmp;
731 ast_mutex_lock(&conlock);
735 if (!strcasecmp(name, tmp->name))
741 ast_mutex_unlock(&conlock);
745 #define STATUS_NO_CONTEXT 1
746 #define STATUS_NO_EXTENSION 2
747 #define STATUS_NO_PRIORITY 3
748 #define STATUS_NO_LABEL 4
749 #define STATUS_SUCCESS 5
751 static int matchcid(const char *cidpattern, const char *callerid)
755 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
756 failing to get a number should count as a match, otherwise not */
759 if (!ast_strlen_zero(cidpattern))
767 return ast_extension_match(cidpattern, callerid);
770 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)
773 struct ast_context *tmp;
774 struct ast_exten *e, *eroot;
775 struct ast_include *i;
777 struct ast_switch *asw;
779 /* Initialize status if appropriate */
781 *status = STATUS_NO_CONTEXT;
785 /* Check for stack overflow */
786 if (*stacklen >= AST_PBX_MAX_STACK) {
787 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
790 /* Check first to see if we've already been checked */
791 for (x=0; x<*stacklen; x++) {
792 if (!strcasecmp(incstack[x], context))
801 if (bypass || !strcmp(tmp->name, context)) {
802 struct ast_exten *earlymatch = NULL;
804 if (*status < STATUS_NO_EXTENSION)
805 *status = STATUS_NO_EXTENSION;
806 for (eroot = tmp->root; eroot; eroot=eroot->next) {
808 /* Match extension */
809 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
810 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
811 ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
812 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
814 if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
815 /* It matched an extension ending in a '!' wildcard
816 So ignore it for now, unless there's a better match */
820 if (*status < STATUS_NO_PRIORITY)
821 *status = STATUS_NO_PRIORITY;
824 if (action == HELPER_FINDLABEL) {
825 if (*status < STATUS_NO_LABEL)
826 *status = STATUS_NO_LABEL;
827 if (label && e->label && !strcmp(label, e->label)) {
828 *status = STATUS_SUCCESS;
829 *foundcontext = context;
832 } else if (e->priority == priority) {
833 *status = STATUS_SUCCESS;
834 *foundcontext = context;
843 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
844 of the loop waiting for more digits, and _then_ match (normally)
845 the extension we ended up with. We got an early-matching wildcard
846 pattern, so return NULL to break out of the loop. */
849 /* Check alternative switches */
852 if ((asw = pbx_findswitch(sw->name))) {
853 /* Substitute variables now */
855 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
856 if (action == HELPER_CANMATCH)
857 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
858 else if (action == HELPER_MATCHMORE)
859 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
861 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
865 *data = sw->eval ? sw->tmpdata : sw->data;
866 *foundcontext = context;
870 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
874 /* Setup the stack */
875 incstack[*stacklen] = tmp->name;
877 /* Now try any includes we have in this context */
880 if (include_valid(i)) {
881 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
895 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
896 functions in the dialplan
898 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
901 char tmpvar[80] = "";
903 struct tm brokentime;
905 struct ast_var_t *variables;
910 if ((first=strchr(var,':'))) { /* : Remove characters counting from end or start of string */
911 ast_copy_string(tmpvar, var, sizeof(tmpvar));
912 first = strchr(tmpvar, ':');
914 first = tmpvar + strlen(tmpvar);
916 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
919 offset=atoi(first+1); /* The number of characters,
920 positive: remove # of chars from start
921 negative: keep # of chars from end */
923 if ((second=strchr(first+1,':'))) {
925 offset2 = atoi(second+1); /* Number of chars to copy */
926 } else if (offset >= 0) {
927 offset2 = strlen(*ret)-offset; /* Rest of string */
929 offset2 = abs(offset);
932 if (abs(offset) > strlen(*ret)) { /* Offset beyond string */
936 offset=-strlen(*ret);
938 if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
940 offset2=strlen(*ret)-offset;
942 offset2=strlen(*ret)+offset;
947 *ret += strlen(*ret)+offset;
948 (*ret)[offset2] = '\0'; /* Cut at offset2 position */
949 } else if (c && !strncmp(var, "CALL", 4)) {
950 if (!strncmp(var + 4, "ER", 2)) {
951 if (!strncmp(var + 6, "ID", 2)) {
952 if (!var[8]) { /* CALLERID */
953 if (c->cid.cid_num) {
954 if (c->cid.cid_name) {
955 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
957 ast_copy_string(workspace, c->cid.cid_num, workspacelen);
960 } else if (c->cid.cid_name) {
961 ast_copy_string(workspace, c->cid.cid_name, workspacelen);
965 } else if (!strcmp(var + 8, "NUM")) {
967 if (c->cid.cid_num) {
968 ast_copy_string(workspace, c->cid.cid_num, workspacelen);
972 } else if (!strcmp(var + 8, "NAME")) {
974 if (c->cid.cid_name) {
975 ast_copy_string(workspace, c->cid.cid_name, workspacelen);
980 } else if (!strcmp(var + 6, "ANI")) {
982 if (c->cid.cid_ani) {
983 ast_copy_string(workspace, c->cid.cid_ani, workspacelen);
989 } else if (!strncmp(var + 4, "ING", 3)) {
990 if (!strcmp(var + 7, "PRES")) {
992 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
994 } else if (!strcmp(var + 7, "ANI2")) {
996 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
998 } else if (!strcmp(var + 7, "TON")) {
1000 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1002 } else if (!strcmp(var + 7, "TNS")) {
1004 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1010 } else if (c && !strcmp(var, "DNID")) {
1011 if (c->cid.cid_dnid) {
1012 ast_copy_string(workspace, c->cid.cid_dnid, workspacelen);
1016 } else if (c && !strcmp(var, "HINT")) {
1017 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
1021 } else if (c && !strcmp(var, "HINTNAME")) {
1022 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
1026 } else if (c && !strcmp(var, "EXTEN")) {
1027 ast_copy_string(workspace, c->exten, workspacelen);
1029 } else if (c && !strcmp(var, "RDNIS")) {
1030 if (c->cid.cid_rdnis) {
1031 ast_copy_string(workspace, c->cid.cid_rdnis, workspacelen);
1035 } else if (c && !strcmp(var, "CONTEXT")) {
1036 ast_copy_string(workspace, c->context, workspacelen);
1038 } else if (c && !strcmp(var, "PRIORITY")) {
1039 snprintf(workspace, workspacelen, "%d", c->priority);
1041 } else if (c && !strcmp(var, "CHANNEL")) {
1042 ast_copy_string(workspace, c->name, workspacelen);
1044 } else if (!strcmp(var, "EPOCH")) {
1045 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1047 } else if (!strcmp(var, "DATETIME")) {
1048 thistime=time(NULL);
1049 localtime_r(&thistime, &brokentime);
1050 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
1052 brokentime.tm_mon+1,
1053 brokentime.tm_year+1900,
1059 } else if (!strcmp(var, "TIMESTAMP")) {
1060 thistime=time(NULL);
1061 localtime_r(&thistime, &brokentime);
1062 /* 20031130-150612 */
1063 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
1064 brokentime.tm_year+1900,
1065 brokentime.tm_mon+1,
1072 } else if (c && !strcmp(var, "UNIQUEID")) {
1073 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1075 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1076 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1078 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1079 ast_copy_string(workspace, c->accountcode, workspacelen);
1081 } else if (c && !strcmp(var, "LANGUAGE")) {
1082 ast_copy_string(workspace, c->language, workspacelen);
1087 AST_LIST_TRAVERSE(headp,variables,entries) {
1089 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1091 if (strcasecmp(ast_var_name(variables),var)==0) {
1092 *ret=ast_var_value(variables);
1094 ast_copy_string(workspace, *ret, workspacelen);
1103 AST_LIST_TRAVERSE(&globals,variables,entries) {
1105 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1107 if (strcasecmp(ast_var_name(variables),var)==0) {
1108 *ret=ast_var_value(variables);
1110 ast_copy_string(workspace, *ret, workspacelen);
1119 static int handle_show_functions(int fd, int argc, char *argv[])
1121 struct ast_custom_function *acf;
1123 ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
1124 for (acf = acf_root ; acf; acf = acf->next) {
1125 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1131 static int handle_show_function(int fd, int argc, char *argv[])
1133 struct ast_custom_function *acf;
1134 /* Maximum number of characters added by terminal coloring is 22 */
1135 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1136 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1137 char stxtitle[40], *syntax = NULL;
1138 int synopsis_size, description_size, syntax_size;
1140 if (argc < 3) return RESULT_SHOWUSAGE;
1142 if (!(acf = ast_custom_function_find(argv[2]))) {
1143 ast_cli(fd, "No function by that name registered.\n");
1144 return RESULT_FAILURE;
1149 synopsis_size = strlen(acf->synopsis) + 23;
1151 synopsis_size = strlen("Not available") + 23;
1152 synopsis = alloca(synopsis_size);
1155 description_size = strlen(acf->desc) + 23;
1157 description_size = strlen("Not available") + 23;
1158 description = alloca(description_size);
1161 syntax_size = strlen(acf->syntax) + 23;
1163 syntax_size = strlen("Not available") + 23;
1164 syntax = alloca(syntax_size);
1166 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1167 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1168 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1169 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1170 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1172 acf->syntax ? acf->syntax : "Not available",
1173 COLOR_CYAN, 0, syntax_size);
1174 term_color(synopsis,
1175 acf->synopsis ? acf->synopsis : "Not available",
1176 COLOR_CYAN, 0, synopsis_size);
1177 term_color(description,
1178 acf->desc ? acf->desc : "Not available",
1179 COLOR_CYAN, 0, description_size);
1181 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1183 return RESULT_SUCCESS;
1186 static char *complete_show_function(char *line, char *word, int pos, int state)
1188 struct ast_custom_function *acf;
1191 /* try to lock functions list ... */
1192 if (ast_mutex_lock(&acflock)) {
1193 ast_log(LOG_ERROR, "Unable to lock function list\n");
1199 if (!strncasecmp(word, acf->name, strlen(word))) {
1200 if (++which > state) {
1201 char *ret = strdup(acf->name);
1202 ast_mutex_unlock(&acflock);
1209 ast_mutex_unlock(&acflock);
1213 struct ast_custom_function* ast_custom_function_find(char *name)
1215 struct ast_custom_function *acfptr;
1217 /* try to lock functions list ... */
1218 if (ast_mutex_lock(&acflock)) {
1219 ast_log(LOG_ERROR, "Unable to lock function list\n");
1223 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1224 if (!strcmp(name, acfptr->name)) {
1229 ast_mutex_unlock(&acflock);
1234 int ast_custom_function_unregister(struct ast_custom_function *acf)
1236 struct ast_custom_function *acfptr, *lastacf = NULL;
1242 /* try to lock functions list ... */
1243 if (ast_mutex_lock(&acflock)) {
1244 ast_log(LOG_ERROR, "Unable to lock function list\n");
1248 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1249 if (acfptr == acf) {
1251 lastacf->next = acf->next;
1253 acf_root = acf->next;
1261 ast_mutex_unlock(&acflock);
1263 if (!res && (option_verbose > 1))
1264 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1269 int ast_custom_function_register(struct ast_custom_function *acf)
1274 /* try to lock functions list ... */
1275 if (ast_mutex_lock(&acflock)) {
1276 ast_log(LOG_ERROR, "Unable to lock function list\n");
1280 if (ast_custom_function_find(acf->name)) {
1281 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1282 ast_mutex_unlock(&acflock);
1286 acf->next = acf_root;
1289 ast_mutex_unlock(&acflock);
1291 if (option_verbose > 1)
1292 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1297 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1299 char *args = NULL, *function, *p;
1301 struct ast_custom_function *acfptr;
1303 function = ast_strdupa(in);
1305 if ((args = strchr(function, '('))) {
1308 if ((p = strrchr(args, ')'))) {
1311 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1314 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1317 if ((acfptr = ast_custom_function_find(function))) {
1318 /* run the custom function */
1320 return acfptr->read(chan, function, args, workspace, len);
1322 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1325 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1328 ast_log(LOG_ERROR, "Out of memory\n");
1333 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1335 char *args = NULL, *function, *p;
1336 struct ast_custom_function *acfptr;
1338 function = ast_strdupa(in);
1340 if ((args = strchr(function, '('))) {
1343 if ((p = strrchr(args, ')'))) {
1346 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1349 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1352 if ((acfptr = ast_custom_function_find(function))) {
1353 /* run the custom function */
1354 if (acfptr->write) {
1355 acfptr->write(chan, function, args, value);
1357 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1360 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1363 ast_log(LOG_ERROR, "Out of memory\n");
1367 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1370 const char *tmp, *whereweare;
1372 char workspace[4096];
1373 char ltmp[4096], var[4096];
1374 char *nextvar, *nextexp, *nextthing;
1376 int pos, brackets, needsub, len;
1378 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1381 while(!ast_strlen_zero(whereweare) && count) {
1382 /* Assume we're copying the whole remaining string */
1383 pos = strlen(whereweare);
1386 nextthing = strchr(whereweare, '$');
1388 switch(nextthing[1]) {
1390 nextvar = nextthing;
1393 nextexp = nextthing;
1397 /* If there is one, we only go that far */
1399 pos = nextvar - whereweare;
1401 pos = nextexp - whereweare;
1403 /* Can't copy more than 'count' bytes */
1407 /* Copy that many bytes */
1408 memcpy(cp2, whereweare, pos);
1415 /* We have a variable. Find the start and end, and determine
1416 if we are going to have to recursively call ourselves on the
1418 vars = vare = nextvar + 2;
1422 /* Find the end of it */
1423 while(brackets && *vare) {
1424 if ((vare[0] == '$') && (vare[1] == '{')) {
1427 } else if (vare[0] == '}') {
1429 } else if ((vare[0] == '$') && (vare[1] == '['))
1434 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1435 len = vare - vars - 1;
1437 /* Skip totally over variable name */
1438 whereweare += ( len + 3);
1440 /* Store variable name (and truncate) */
1441 memset(var, 0, sizeof(var));
1442 ast_copy_string(var, vars, sizeof(var));
1445 /* Substitute if necessary */
1447 memset(ltmp, 0, sizeof(ltmp));
1448 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1454 workspace[0] = '\0';
1456 if (var[len - 1] == ')') {
1457 /* Evaluate function */
1458 cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
1460 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1462 /* Retrieve variable value */
1463 pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
1466 length = strlen(cp4);
1469 memcpy(cp2, cp4, length);
1473 } else if (nextexp) {
1474 /* We have an expression. Find the start and end, and determine
1475 if we are going to have to recursively call ourselves on the
1477 vars = vare = nextexp + 2;
1481 /* Find the end of it */
1482 while(brackets && *vare) {
1483 if ((vare[0] == '$') && (vare[1] == '[')) {
1487 } else if (vare[0] == '[') {
1489 } else if (vare[0] == ']') {
1491 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1498 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1499 len = vare - vars - 1;
1501 /* Skip totally over variable name */
1502 whereweare += ( len + 3);
1504 /* Store variable name (and truncate) */
1505 memset(var, 0, sizeof(var));
1506 ast_copy_string(var, vars, sizeof(var));
1509 /* Substitute if necessary */
1511 memset(ltmp, 0, sizeof(ltmp));
1512 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1518 /* Evaluate expression */
1519 cp4 = ast_expr(vars);
1521 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1524 length = strlen(cp4);
1527 memcpy(cp2, cp4, length);
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;
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:
1756 return AST_EXTENSION_INUSE;
1757 case AST_DEVICE_BUSY:
1762 case AST_DEVICE_UNAVAILABLE:
1763 case AST_DEVICE_INVALID:
1776 return AST_EXTENSION_NOT_INUSE;
1778 return AST_EXTENSION_BUSY;
1780 return AST_EXTENSION_UNAVAILABLE;
1782 return AST_EXTENSION_INUSE;
1784 return AST_EXTENSION_NOT_INUSE;
1788 /*--- ast_extension_state: Check extension state for an extension by using hint */
1789 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1791 struct ast_exten *e;
1793 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1795 return -1; /* No hint, return -1 */
1797 return ast_extension_state2(e); /* Check all devices in the hint */
1800 void ast_hint_state_changed(const char *device)
1802 struct ast_hint *hint;
1803 struct ast_state_cb *cblist;
1804 char buf[AST_MAX_EXTENSION];
1809 ast_mutex_lock(&hintlock);
1811 for (hint = hints; hint; hint = hint->next) {
1812 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1814 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1815 if (strcmp(cur, device))
1818 /* Get device state for this hint */
1819 state = ast_extension_state2(hint->exten);
1821 if ((state == -1) || (state == hint->laststate))
1824 /* Device state changed since last check - notify the watchers */
1826 /* For general callbacks */
1827 for (cblist = statecbs; cblist; cblist = cblist->next)
1828 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1830 /* For extension callbacks */
1831 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1832 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1834 hint->laststate = state;
1839 ast_mutex_unlock(&hintlock);
1842 /*--- ast_extension_state_add: Add watcher for extension states */
1843 int ast_extension_state_add(const char *context, const char *exten,
1844 ast_state_cb_type callback, void *data)
1846 struct ast_hint *list;
1847 struct ast_state_cb *cblist;
1848 struct ast_exten *e;
1850 /* If there's no context and extension: add callback to statecbs list */
1851 if (!context && !exten) {
1852 ast_mutex_lock(&hintlock);
1856 if (cblist->callback == callback) {
1857 cblist->data = data;
1858 ast_mutex_unlock(&hintlock);
1861 cblist = cblist->next;
1864 /* Now insert the callback */
1865 cblist = malloc(sizeof(struct ast_state_cb));
1867 ast_mutex_unlock(&hintlock);
1870 memset(cblist, 0, sizeof(struct ast_state_cb));
1872 cblist->callback = callback;
1873 cblist->data = data;
1875 cblist->next = statecbs;
1878 ast_mutex_unlock(&hintlock);
1882 if (!context || !exten)
1885 /* This callback type is for only one hint, so get the hint */
1886 e = ast_hint_extension(NULL, context, exten);
1891 /* Find the hint in the list of hints */
1892 ast_mutex_lock(&hintlock);
1896 if (list->exten == e)
1902 /* We have no hint, sorry */
1903 ast_mutex_unlock(&hintlock);
1907 /* Now insert the callback in the callback list */
1908 cblist = malloc(sizeof(struct ast_state_cb));
1910 ast_mutex_unlock(&hintlock);
1913 memset(cblist, 0, sizeof(struct ast_state_cb));
1914 cblist->id = stateid++; /* Unique ID for this callback */
1915 cblist->callback = callback; /* Pointer to callback routine */
1916 cblist->data = data; /* Data for the callback */
1918 cblist->next = list->callbacks;
1919 list->callbacks = cblist;
1921 ast_mutex_unlock(&hintlock);
1925 /*--- ast_extension_state_del: Remove a watcher from the callback list */
1926 int ast_extension_state_del(int id, ast_state_cb_type callback)
1928 struct ast_hint *list;
1929 struct ast_state_cb *cblist, *cbprev;
1931 if (!id && !callback)
1934 ast_mutex_lock(&hintlock);
1936 /* id is zero is a callback without extension */
1941 if (cblist->callback == callback) {
1943 statecbs = cblist->next;
1945 cbprev->next = cblist->next;
1949 ast_mutex_unlock(&hintlock);
1953 cblist = cblist->next;
1956 ast_mutex_lock(&hintlock);
1960 /* id greater than zero is a callback with extension */
1961 /* Find the callback based on ID */
1964 cblist = list->callbacks;
1967 if (cblist->id==id) {
1969 list->callbacks = cblist->next;
1971 cbprev->next = cblist->next;
1975 ast_mutex_unlock(&hintlock);
1979 cblist = cblist->next;
1984 ast_mutex_unlock(&hintlock);
1988 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
1989 static int ast_add_hint(struct ast_exten *e)
1991 struct ast_hint *list;
1996 ast_mutex_lock(&hintlock);
1999 /* Search if hint exists, do nothing */
2001 if (list->exten == e) {
2002 ast_mutex_unlock(&hintlock);
2003 if (option_debug > 1)
2004 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2010 if (option_debug > 1)
2011 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2013 list = malloc(sizeof(struct ast_hint));
2015 ast_mutex_unlock(&hintlock);
2016 if (option_debug > 1)
2017 ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
2020 /* Initialize and insert new item at the top */
2021 memset(list, 0, sizeof(struct ast_hint));
2023 list->laststate = ast_extension_state2(e);
2027 ast_mutex_unlock(&hintlock);
2031 /*--- ast_change_hint: Change hint for an extension */
2032 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2034 struct ast_hint *list;
2036 ast_mutex_lock(&hintlock);
2040 if (list->exten == oe) {
2042 ast_mutex_unlock(&hintlock);
2047 ast_mutex_unlock(&hintlock);
2052 /*--- ast_remove_hint: Remove hint from extension */
2053 static int ast_remove_hint(struct ast_exten *e)
2055 /* Cleanup the Notifys if hint is removed */
2056 struct ast_hint *list, *prev = NULL;
2057 struct ast_state_cb *cblist, *cbprev;
2062 ast_mutex_lock(&hintlock);
2066 if (list->exten==e) {
2068 cblist = list->callbacks;
2070 /* Notify with -1 and remove all callbacks */
2072 cblist = cblist->next;
2073 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
2076 list->callbacks = NULL;
2081 prev->next = list->next;
2084 ast_mutex_unlock(&hintlock);
2092 ast_mutex_unlock(&hintlock);
2097 /*--- ast_get_hint: Get hint for channel */
2098 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2100 struct ast_exten *e;
2103 e = ast_hint_extension(c, context, exten);
2106 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2108 tmp = ast_get_extension_app_data(e);
2110 ast_copy_string(name, (char *) tmp, namesize);
2117 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2119 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2122 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2124 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2127 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2129 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2132 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2134 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2137 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2139 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2142 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2144 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2147 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2149 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2152 static int __ast_pbx_run(struct ast_channel *c)
2162 /* A little initial setup here */
2164 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2165 c->pbx = malloc(sizeof(struct ast_pbx));
2167 ast_log(LOG_ERROR, "Out of memory\n");
2172 c->cdr = ast_cdr_alloc();
2174 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2178 ast_cdr_init(c->cdr, c);
2181 memset(c->pbx, 0, sizeof(struct ast_pbx));
2182 /* Set reasonable defaults */
2183 c->pbx->rtimeout = 10;
2184 c->pbx->dtimeout = 5;
2186 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2187 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2189 /* Start by trying whatever the channel is set to */
2190 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2191 /* If not successful fall back to 's' */
2192 if (option_verbose > 1)
2193 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);
2194 ast_copy_string(c->exten, "s", sizeof(c->exten));
2195 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2196 /* JK02: And finally back to default if everything else failed */
2197 if (option_verbose > 1)
2198 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);
2199 ast_copy_string(c->context, "default", sizeof(c->context));
2203 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2204 ast_cdr_start(c->cdr);
2208 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2209 memset(exten, 0, sizeof(exten));
2210 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2211 /* Something bad happened, or a hangup has been requested. */
2212 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2213 (res == '*') || (res == '#')) {
2214 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2215 memset(exten, 0, sizeof(exten));
2217 exten[pos++] = digit = res;
2221 case AST_PBX_KEEPALIVE:
2223 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2224 else if (option_verbose > 1)
2225 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2230 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2231 else if (option_verbose > 1)
2232 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2233 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2238 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2248 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2249 ast_copy_string(c->exten, "T", sizeof(c->exten));
2250 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2251 c->whentohangup = 0;
2253 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2254 } else if (c->_softhangup) {
2255 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2256 c->exten, c->priority);
2262 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2263 /* It's not a valid extension anymore */
2264 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2265 if (option_verbose > 2)
2266 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2267 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2268 ast_copy_string(c->exten, "i", sizeof(c->exten));
2271 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2272 c->name, c->exten, c->context);
2275 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2276 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2279 /* Done, wait for an extension */
2282 waittime = c->pbx->dtimeout;
2283 else if (!autofallthrough)
2284 waittime = c->pbx->rtimeout;
2286 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2287 /* As long as we're willing to wait, and as long as it's not defined,
2288 keep reading digits until we can't possibly get a right answer anymore. */
2289 digit = ast_waitfordigit(c, waittime * 1000);
2290 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2297 /* Error, maybe a hangup */
2299 exten[pos++] = digit;
2300 waittime = c->pbx->dtimeout;
2303 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2304 /* Prepare the next cycle */
2305 ast_copy_string(c->exten, exten, sizeof(c->exten));
2308 /* No such extension */
2309 if (!ast_strlen_zero(exten)) {
2310 /* An invalid extension */
2311 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2312 if (option_verbose > 2)
2313 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2314 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2315 ast_copy_string(c->exten, "i", sizeof(c->exten));
2318 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2322 /* A simple timeout */
2323 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2324 if (option_verbose > 2)
2325 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2326 ast_copy_string(c->exten, "t", sizeof(c->exten));
2329 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2335 if (option_verbose > 2)
2336 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2342 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2345 if (option_verbose > 2)
2346 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2347 if (!strcasecmp(status, "CONGESTION"))
2348 res = pbx_builtin_congestion(c, "10");
2349 else if (!strcasecmp(status, "CHANUNAVAIL"))
2350 res = pbx_builtin_congestion(c, "10");
2351 else if (!strcasecmp(status, "BUSY"))
2352 res = pbx_builtin_busy(c, "10");
2358 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2360 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2364 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2365 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2366 /* Something bad happened, or a hangup has been requested. */
2368 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2369 else if (option_verbose > 1)
2370 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2376 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2378 pbx_destroy(c->pbx);
2380 if (res != AST_PBX_KEEPALIVE)
2385 static void *pbx_thread(void *data)
2387 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2388 answer this channel and get it going. The setjmp stuff is fairly
2389 confusing, but necessary to get smooth transitions between
2390 the execution of different applications (without the use of
2391 additional threads) */
2392 struct ast_channel *c = data;
2398 int ast_pbx_start(struct ast_channel *c)
2401 pthread_attr_t attr;
2403 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2407 /* Start a new thread, and get something handling this channel. */
2408 pthread_attr_init(&attr);
2409 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2410 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2411 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2417 int ast_pbx_run(struct ast_channel *c)
2420 ast_mutex_lock(&maxcalllock);
2421 if (option_maxcalls) {
2422 if (countcalls >= option_maxcalls) {
2423 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2429 ast_mutex_unlock(&maxcalllock);
2431 res = __ast_pbx_run(c);
2432 ast_mutex_lock(&maxcalllock);
2435 ast_mutex_unlock(&maxcalllock);
2440 int ast_active_calls(void)
2445 int pbx_set_autofallthrough(int newval)
2448 oldval = autofallthrough;
2449 if (oldval != newval)
2450 autofallthrough = newval;
2455 * This function locks contexts list by &conlist, search for the right context
2456 * structure, leave context list locked and call ast_context_remove_include2
2457 * which removes include, unlock contexts list and return ...
2459 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2461 struct ast_context *c;
2463 if (ast_lock_contexts()) return -1;
2465 /* walk contexts and search for the right one ...*/
2466 c = ast_walk_contexts(NULL);
2468 /* we found one ... */
2469 if (!strcmp(ast_get_context_name(c), context)) {
2471 /* remove include from this context ... */
2472 ret = ast_context_remove_include2(c, include, registrar);
2474 ast_unlock_contexts();
2476 /* ... return results */
2479 c = ast_walk_contexts(c);
2482 /* we can't find the right one context */
2483 ast_unlock_contexts();
2488 * When we call this function, &conlock lock must be locked, because when
2489 * we giving *con argument, some process can remove/change this context
2490 * and after that there can be segfault.
2492 * This function locks given context, removes include, unlock context and
2495 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2497 struct ast_include *i, *pi = NULL;
2499 if (ast_mutex_lock(&con->lock)) return -1;
2504 /* find our include */
2505 if (!strcmp(i->name, include) &&
2506 (!registrar || !strcmp(i->registrar, registrar))) {
2507 /* remove from list */
2511 con->includes = i->next;
2512 /* free include and return */
2514 ast_mutex_unlock(&con->lock);
2521 /* we can't find the right include */
2522 ast_mutex_unlock(&con->lock);
2527 * This function locks contexts list by &conlist, search for the rigt context
2528 * structure, leave context list locked and call ast_context_remove_switch2
2529 * which removes switch, unlock contexts list and return ...
2531 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2533 struct ast_context *c;
2535 if (ast_lock_contexts()) return -1;
2537 /* walk contexts and search for the right one ...*/
2538 c = ast_walk_contexts(NULL);
2540 /* we found one ... */
2541 if (!strcmp(ast_get_context_name(c), context)) {
2543 /* remove switch from this context ... */
2544 ret = ast_context_remove_switch2(c, sw, data, registrar);
2546 ast_unlock_contexts();
2548 /* ... return results */
2551 c = ast_walk_contexts(c);
2554 /* we can't find the right one context */
2555 ast_unlock_contexts();
2560 * When we call this function, &conlock lock must be locked, because when
2561 * we giving *con argument, some process can remove/change this context
2562 * and after that there can be segfault.
2564 * This function locks given context, removes switch, unlock context and
2567 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2569 struct ast_sw *i, *pi = NULL;
2571 if (ast_mutex_lock(&con->lock)) return -1;
2576 /* find our switch */
2577 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2578 (!registrar || !strcmp(i->registrar, registrar))) {
2579 /* remove from list */
2583 con->alts = i->next;
2584 /* free switch and return */
2586 ast_mutex_unlock(&con->lock);
2593 /* we can't find the right switch */
2594 ast_mutex_unlock(&con->lock);
2599 * This functions lock contexts list, search for the right context,
2600 * call ast_context_remove_extension2, unlock contexts list and return.
2601 * In this function we are using
2603 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2605 struct ast_context *c;
2607 if (ast_lock_contexts()) return -1;
2609 /* walk contexts ... */
2610 c = ast_walk_contexts(NULL);
2612 /* ... search for the right one ... */
2613 if (!strcmp(ast_get_context_name(c), context)) {
2614 /* ... remove extension ... */
2615 int ret = ast_context_remove_extension2(c, extension, priority,
2617 /* ... unlock contexts list and return */
2618 ast_unlock_contexts();
2621 c = ast_walk_contexts(c);
2624 /* we can't find the right context */
2625 ast_unlock_contexts();
2630 * When do you want to call this function, make sure that &conlock is locked,
2631 * because some process can handle with your *con context before you lock
2634 * This functionc locks given context, search for the right extension and
2635 * fires out all peer in this extensions with given priority. If priority
2636 * is set to 0, all peers are removed. After that, unlock context and
2639 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2641 struct ast_exten *exten, *prev_exten = NULL;
2643 if (ast_mutex_lock(&con->lock)) return -1;
2645 /* go through all extensions in context and search the right one ... */
2649 /* look for right extension */
2650 if (!strcmp(exten->exten, extension) &&
2651 (!registrar || !strcmp(exten->registrar, registrar))) {
2652 struct ast_exten *peer;
2654 /* should we free all peers in this extension? (priority == 0)? */
2655 if (priority == 0) {
2656 /* remove this extension from context list */
2658 prev_exten->next = exten->next;
2660 con->root = exten->next;
2662 /* fire out all peers */
2667 if (!peer->priority==PRIORITY_HINT)
2668 ast_remove_hint(peer);
2670 peer->datad(peer->data);
2676 ast_mutex_unlock(&con->lock);
2679 /* remove only extension with exten->priority == priority */
2680 struct ast_exten *previous_peer = NULL;
2684 /* is this our extension? */
2685 if (peer->priority == priority &&
2686 (!registrar || !strcmp(peer->registrar, registrar) )) {
2687 /* we are first priority extension? */
2688 if (!previous_peer) {
2689 /* exists previous extension here? */
2691 /* yes, so we must change next pointer in
2692 * previous connection to next peer
2695 prev_exten->next = peer->peer;
2696 peer->peer->next = exten->next;
2698 prev_exten->next = exten->next;
2700 /* no previous extension, we are first
2701 * extension, so change con->root ...
2704 con->root = peer->peer;
2706 con->root = exten->next;
2709 /* we are not first priority in extension */
2710 previous_peer->peer = peer->peer;
2713 /* now, free whole priority extension */
2714 if (peer->priority==PRIORITY_HINT)
2715 ast_remove_hint(peer);
2716 peer->datad(peer->data);
2719 ast_mutex_unlock(&con->lock);
2722 /* this is not right extension, skip to next peer */
2723 previous_peer = peer;
2728 ast_mutex_unlock(&con->lock);
2734 exten = exten->next;
2737 /* we can't find right extension */
2738 ast_mutex_unlock(&con->lock);
2743 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2745 struct ast_app *tmp, *prev, *cur;
2748 length = sizeof(struct ast_app);
2749 length += strlen(app) + 1;
2750 if (ast_mutex_lock(&applock)) {
2751 ast_log(LOG_ERROR, "Unable to lock application list\n");
2756 if (!strcasecmp(app, tmp->name)) {
2757 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2758 ast_mutex_unlock(&applock);
2763 tmp = malloc(length);
2765 memset(tmp, 0, length);
2766 strcpy(tmp->name, app);
2767 tmp->execute = execute;
2768 tmp->synopsis = synopsis;
2769 tmp->description = description;
2770 /* Store in alphabetical order */
2774 if (strcasecmp(tmp->name, cur->name) < 0)
2780 tmp->next = prev->next;
2787 ast_log(LOG_ERROR, "Out of memory\n");
2788 ast_mutex_unlock(&applock);
2791 if (option_verbose > 1)
2792 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2793 ast_mutex_unlock(&applock);
2797 int ast_register_switch(struct ast_switch *sw)
2799 struct ast_switch *tmp, *prev=NULL;
2800 if (ast_mutex_lock(&switchlock)) {
2801 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2806 if (!strcasecmp(tmp->name, sw->name))
2812 ast_mutex_unlock(&switchlock);
2813 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2821 ast_mutex_unlock(&switchlock);
2825 void ast_unregister_switch(struct ast_switch *sw)
2827 struct ast_switch *tmp, *prev=NULL;
2828 if (ast_mutex_lock(&switchlock)) {
2829 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2836 prev->next = tmp->next;
2838 switches = tmp->next;
2845 ast_mutex_unlock(&switchlock);
2849 * Help for CLI commands ...
2851 static char show_application_help[] =
2852 "Usage: show application <application> [<application> [<application> [...]]]\n"
2853 " Describes a particular application.\n";
2855 static char show_functions_help[] =
2856 "Usage: show functions\n"
2857 " List builtin functions accessable as $(function args)\n";
2859 static char show_function_help[] =
2860 "Usage: show function <function>\n"
2861 " Describe a particular dialplan function.\n";
2863 static char show_applications_help[] =
2864 "Usage: show applications [{like|describing} <text>]\n"
2865 " List applications which are currently available.\n"
2866 " If 'like', <text> will be a substring of the app name\n"
2867 " If 'describing', <text> will be a substring of the description\n";
2869 static char show_dialplan_help[] =
2870 "Usage: show dialplan [exten@][context]\n"
2873 static char show_switches_help[] =
2874 "Usage: show switches\n"
2875 " Show registered switches\n";
2877 static char show_hints_help[] =
2878 "Usage: show hints\n"
2879 " Show registered hints\n";
2883 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2888 * 'show application' CLI command implementation functions ...
2892 * There is a possibility to show informations about more than one
2893 * application at one time. You can type 'show application Dial Echo' and
2894 * you will see informations about these two applications ...
2896 static char *complete_show_application(char *line, char *word,
2902 /* try to lock applications list ... */
2903 if (ast_mutex_lock(&applock)) {
2904 ast_log(LOG_ERROR, "Unable to lock application list\n");
2908 /* ... walk all applications ... */
2911 /* ... check if word matches this application ... */
2912 if (!strncasecmp(word, a->name, strlen(word))) {
2913 /* ... if this is right app serve it ... */
2914 if (++which > state) {
2915 char *ret = strdup(a->name);
2916 ast_mutex_unlock(&applock);
2923 /* no application match */
2924 ast_mutex_unlock(&applock);
2928 static int handle_show_application(int fd, int argc, char *argv[])
2931 int app, no_registered_app = 1;
2933 if (argc < 3) return RESULT_SHOWUSAGE;
2935 /* try to lock applications list ... */
2936 if (ast_mutex_lock(&applock)) {
2937 ast_log(LOG_ERROR, "Unable to lock application list\n");
2941 /* ... go through all applications ... */
2944 /* ... compare this application name with all arguments given
2945 * to 'show application' command ... */
2946 for (app = 2; app < argc; app++) {
2947 if (!strcasecmp(a->name, argv[app])) {
2948 /* Maximum number of characters added by terminal coloring is 22 */
2949 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2950 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2951 int synopsis_size, description_size;
2953 no_registered_app = 0;
2956 synopsis_size = strlen(a->synopsis) + 23;
2958 synopsis_size = strlen("Not available") + 23;
2959 synopsis = alloca(synopsis_size);
2962 description_size = strlen(a->description) + 23;
2964 description_size = strlen("Not available") + 23;
2965 description = alloca(description_size);
2967 if (synopsis && description) {
2968 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2969 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2970 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2971 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2972 term_color(synopsis,
2973 a->synopsis ? a->synopsis : "Not available",
2974 COLOR_CYAN, 0, synopsis_size);
2975 term_color(description,
2976 a->description ? a->description : "Not available",
2977 COLOR_CYAN, 0, description_size);
2979 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2981 /* ... one of our applications, show info ...*/
2982 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2983 "[Synopsis]\n %s\n\n"
2984 "[Description]\n%s\n",
2986 a->synopsis ? a->synopsis : "Not available",
2987 a->description ? a->description : "Not available");
2994 ast_mutex_unlock(&applock);
2996 /* we found at least one app? no? */
2997 if (no_registered_app) {
2998 ast_cli(fd, "Your application(s) is (are) not registered\n");
2999 return RESULT_FAILURE;
3002 return RESULT_SUCCESS;
3005 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
3006 static int handle_show_hints(int fd, int argc, char *argv[])
3008 struct ast_hint *hint;
3012 ast_cli(fd, "There are no registered dialplan hints\n");
3013 return RESULT_SUCCESS;
3015 /* ... we have hints ... */
3016 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
3017 if (ast_mutex_lock(&hintlock)) {
3018 ast_log(LOG_ERROR, "Unable to lock hints\n");
3023 ast_cli(fd, " %-20.20s: %-20.20s State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
3027 ast_cli(fd, "----------------\n");
3028 ast_cli(fd, "- %d hints registred\n", num);
3029 ast_mutex_unlock(&hintlock);
3030 return RESULT_SUCCESS;
3033 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
3034 static int handle_show_switches(int fd, int argc, char *argv[])
3036 struct ast_switch *sw;
3038 ast_cli(fd, "There are no registered alternative switches\n");
3039 return RESULT_SUCCESS;
3041 /* ... we have applications ... */
3042 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
3043 if (ast_mutex_lock(&switchlock)) {
3044 ast_log(LOG_ERROR, "Unable to lock switches\n");
3049 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3052 ast_mutex_unlock(&switchlock);
3053 return RESULT_SUCCESS;
3057 * 'show applications' CLI command implementation functions ...
3059 static int handle_show_applications(int fd, int argc, char *argv[])
3062 int like=0, describing=0;
3063 int total_match = 0; /* Number of matches in like clause */
3064 int total_apps = 0; /* Number of apps registered */
3066 /* try to lock applications list ... */
3067 if (ast_mutex_lock(&applock)) {
3068 ast_log(LOG_ERROR, "Unable to lock application list\n");
3072 /* ... have we got at least one application (first)? no? */
3074 ast_cli(fd, "There are no registered applications\n");
3075 ast_mutex_unlock(&applock);
3079 /* show applications like <keyword> */
3080 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3082 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3086 /* show applications describing <keyword1> [<keyword2>] [...] */
3087 if ((!like) && (!describing)) {
3088 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3090 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3093 /* ... go through all applications ... */
3094 for (a = apps; a; a = a->next) {
3095 /* ... show informations about applications ... */
3099 if (ast_strcasestr(a->name, argv[3])) {
3103 } else if (describing) {
3104 if (a->description) {
3105 /* Match all words on command line */
3108 for (i=3;i<argc;i++) {
3109 if (! ast_strcasestr(a->description, argv[i])) {
3121 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3124 if ((!like) && (!describing)) {
3125 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3127 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3130 /* ... unlock and return */
3131 ast_mutex_unlock(&applock);
3133 return RESULT_SUCCESS;
3136 static char *complete_show_applications(char *line, char *word, int pos, int state)
3139 if (ast_strlen_zero(word)) {
3142 return strdup("like");
3144 return strdup("describing");
3148 } else if (! strncasecmp(word, "like", strlen(word))) {
3150 return strdup("like");
3154 } else if (! strncasecmp(word, "describing", strlen(word))) {
3156 return strdup("describing");
3166 * 'show dialplan' CLI command implementation functions ...
3168 static char *complete_show_dialplan_context(char *line, char *word, int pos,
3171 struct ast_context *c;
3174 /* we are do completion of [exten@]context on second position only */
3175 if (pos != 2) return NULL;
3177 /* try to lock contexts list ... */
3178 if (ast_lock_contexts()) {
3179 ast_log(LOG_ERROR, "Unable to lock context list\n");
3183 /* ... walk through all contexts ... */
3184 c = ast_walk_contexts(NULL);
3186 /* ... word matches context name? yes? ... */
3187 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
3188 /* ... for serve? ... */
3189 if (++which > state) {
3190 /* ... yes, serve this context name ... */
3191 char *ret = strdup(ast_get_context_name(c));
3192 ast_unlock_contexts();
3196 c = ast_walk_contexts(c);
3199 /* ... unlock and return */
3200 ast_unlock_contexts();
3204 struct dialplan_counters {
3208 int context_existence;
3209 int extension_existence;
3212 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
3214 struct ast_context *c;
3215 int res=0, old_total_exten = dpc->total_exten;
3217 /* try to lock contexts */
3218 if (ast_lock_contexts()) {
3219 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3223 /* walk all contexts ... */
3224 for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
3225 /* show this context? */
3227 !strcmp(ast_get_context_name(c), context)) {
3228 dpc->context_existence = 1;
3230 /* try to lock context before walking in ... */
3231 if (!ast_lock_context(c)) {
3232 struct ast_exten *e;
3233 struct ast_include *i;
3234 struct ast_ignorepat *ip;
3236 char buf[256], buf2[256];
3237 int context_info_printed = 0;
3239 /* are we looking for exten too? if yes, we print context
3240 * if we our extension only
3243 dpc->total_context++;
3244 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3245 ast_get_context_name(c), ast_get_context_registrar(c));
3246 context_info_printed = 1;
3249 /* walk extensions ... */
3250 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3251 struct ast_exten *p;
3254 /* looking for extension? is this our extension? */
3256 !ast_extension_match(ast_get_extension_name(e), exten))
3258 /* we are looking for extension and it's not our
3259 * extension, so skip to next extension */
3263 dpc->extension_existence = 1;
3265 /* may we print context info? */
3266 if (!context_info_printed) {
3267 dpc->total_context++;
3269 /* TODO Print more info about rinclude */
3270 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3271 ast_get_context_name(c),
3272 ast_get_context_registrar(c));
3274 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3275 ast_get_context_name(c),
3276 ast_get_context_registrar(c));
3278 context_info_printed = 1;
3282 /* write extension name and first peer */
3283 bzero(buf, sizeof(buf));
3284 snprintf(buf, sizeof(buf), "'%s' =>",
3285 ast_get_extension_name(e));
3287 prio = ast_get_extension_priority(e);
3288 if (prio == PRIORITY_HINT) {
3289 snprintf(buf2, sizeof(buf2),
3291 ast_get_extension_app(e));
3293 snprintf(buf2, sizeof(buf2),
3296 ast_get_extension_app(e),
3297 (char *)ast_get_extension_app_data(e));
3300 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3301 ast_get_extension_registrar(e));
3304 /* walk next extension peers */
3305 for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3307 bzero((void *)buf2, sizeof(buf2));
3308 bzero((void *)buf, sizeof(buf));
3309 if (ast_get_extension_label(p))
3310 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
3311 prio = ast_get_extension_priority(p);
3312 if (prio == PRIORITY_HINT) {
3313 snprintf(buf2, sizeof(buf2),
3315 ast_get_extension_app(p));
3317 snprintf(buf2, sizeof(buf2),
3320 ast_get_extension_app(p),
3321 (char *)ast_get_extension_app_data(p));
3324 ast_cli(fd," %-17s %-45s [%s]\n",
3326 ast_get_extension_registrar(p));
3330 /* walk included and write info ... */
3331 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3332 bzero(buf, sizeof(buf));
3333 snprintf(buf, sizeof(buf), "'%s'",
3334 ast_get_include_name(i));
3336 /* Check all includes for the requested extension */
3337 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
3339 ast_cli(fd, " Include => %-45s [%s]\n",
3340 buf, ast_get_include_registrar(i));
3344 /* walk ignore patterns and write info ... */
3345 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
3346 const char *ipname = ast_get_ignorepat_name(ip);
3347 char ignorepat[AST_MAX_EXTENSION];
3348 snprintf(buf, sizeof(buf), "'%s'", ipname);
3349 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3350 if ((!exten) || ast_extension_match(ignorepat, exten)) {
3351 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3352 buf, ast_get_ignorepat_registrar(ip));
3356 for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
3357 snprintf(buf, sizeof(buf), "'%s/%s'",
3358 ast_get_switch_name(sw),
3359 ast_get_switch_data(sw));
3360 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3361 buf, ast_get_switch_registrar(sw));
3365 ast_unlock_context(c);
3367 /* if we print something in context, make an empty line */
3368 if (context_info_printed) ast_cli(fd, "\r\n");
3372 ast_unlock_contexts();
3374 if (dpc->total_exten == old_total_exten) {
3375 /* Nothing new under the sun */
3382 static int handle_show_dialplan(int fd, int argc, char *argv[])
3384 char *exten = NULL, *context = NULL;
3385 /* Variables used for different counters */
3386 struct dialplan_counters counters;
3388 memset(&counters, 0, sizeof(counters));
3390 if (argc != 2 && argc != 3)
3391 return RESULT_SHOWUSAGE;
3393 /* we obtain [exten@]context? if yes, split them ... */
3395 char *splitter = ast_strdupa(argv[2]);
3396 /* is there a '@' character? */
3397 if (splitter && strchr(argv[2], '@')) {
3398 /* yes, split into exten & context ... */
3399 exten = strsep(&splitter, "@");
3402 /* check for length and change to NULL if ast_strlen_zero() */
3403 if (ast_strlen_zero(exten))
3405 if (ast_strlen_zero(context))
3407 show_dialplan_helper(fd, context, exten, &counters, NULL);
3409 /* no '@' char, only context given */