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>
16 #include <asterisk/lock.h>
17 #include <asterisk/cli.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/channel.h>
20 #include <asterisk/options.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/file.h>
23 #include <asterisk/callerid.h>
24 #include <asterisk/cdr.h>
25 #include <asterisk/config.h>
26 #include <asterisk/term.h>
27 #include <asterisk/manager.h>
28 #include <asterisk/ast_expr.h>
29 #include <asterisk/linkedlists.h>
30 #include <asterisk/say.h>
31 #include <asterisk/utils.h>
32 #include <asterisk/causes.h>
33 #include <asterisk/musiconhold.h>
34 #include <asterisk/app.h>
49 * The speed of extension handling will likely be among the most important
50 * aspects of this PBX. The switching scheme as it exists right now isn't
51 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
52 * of priorities, but a constant search time here would be great ;-)
57 #define EXT_DATA_SIZE 256
59 #define EXT_DATA_SIZE 8192
62 #define SWITCH_DATA_LENGTH 256
66 #define VAR_SOFTTRAN 2
67 #define VAR_HARDTRAN 3
69 #define BACKGROUND_SKIP (1 << 0)
70 #define BACKGROUND_NOANSWER (1 << 1)
72 AST_DECLARE_OPTIONS(background_opts,{
73 ['s'] = { BACKGROUND_SKIP },
74 ['n'] = { BACKGROUND_NOANSWER },
77 #define WAITEXTEN_MOH (1 << 0)
79 AST_DECLARE_OPTIONS(waitexten_opts,{
80 ['m'] = { WAITEXTEN_MOH, 1 },
85 /* ast_exten: An extension */
87 char *exten; /* Extension name */
88 int matchcid; /* Match caller id ? */
89 char *cidmatch; /* Caller id to match for this extension */
90 int priority; /* Priority */
91 char *label; /* Label */
92 struct ast_context *parent; /* The context this extension belongs to */
93 char *app; /* Application to execute */
94 void *data; /* Data to use (arguments) */
95 void (*datad)(void *); /* Data destructor */
96 struct ast_exten *peer; /* Next higher priority with our extension */
97 const char *registrar; /* Registrar */
98 struct ast_exten *next; /* Extension with a greater ID */
102 /* ast_include: include= support in extensions.conf */
105 char *rname; /* Context to include */
106 const char *registrar; /* Registrar */
107 int hastime; /* If time construct exists */
108 struct ast_timing timing; /* time construct */
109 struct ast_include *next; /* Link them together */
113 /* ast_sw: Switch statement in extensions.conf */
116 const char *registrar; /* Registrar */
117 char *data; /* Data load */
119 struct ast_sw *next; /* Link them together */
124 struct ast_ignorepat {
125 const char *registrar;
126 struct ast_ignorepat *next;
130 /* ast_context: An extension context */
132 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
133 struct ast_exten *root; /* The root of the list of extensions */
134 struct ast_context *next; /* Link them together */
135 struct ast_include *includes; /* Include other contexts */
136 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
137 const char *registrar; /* Registrar */
138 struct ast_sw *alts; /* Alternative switches */
139 char name[0]; /* Name of the context */
143 /* ast_app: An application */
145 int (*execute)(struct ast_channel *chan, void *data);
146 const char *synopsis; /* Synopsis text for 'show applications' */
147 const char *description; /* Description (help text) for 'show application <name>' */
148 struct ast_app *next; /* Next app in list */
149 char name[0]; /* Name of the application */
152 /* ast_state_cb: An extension state notify */
153 struct ast_state_cb {
156 ast_state_cb_type callback;
157 struct ast_state_cb *next;
160 /* ast_devstate_cb: An extension state notify */
161 struct ast_devstate_cb {
163 ast_devstate_cb_type callback;
164 struct ast_devstate_cb *next;
167 static struct ast_devstate_cb *devcbs;
169 /* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
171 struct ast_exten *exten; /* Extension */
172 int laststate; /* Last known state */
173 struct ast_state_cb *callbacks; /* Callback list for this extension */
174 struct ast_hint *next; /* Pointer to next hint in list */
177 int ast_pbx_outgoing_cdr_failed(void);
179 static int pbx_builtin_prefix(struct ast_channel *, void *);
180 static int pbx_builtin_suffix(struct ast_channel *, void *);
181 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
182 static int pbx_builtin_answer(struct ast_channel *, void *);
183 static int pbx_builtin_goto(struct ast_channel *, void *);
184 static int pbx_builtin_hangup(struct ast_channel *, void *);
185 static int pbx_builtin_background(struct ast_channel *, void *);
186 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
187 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
188 static int pbx_builtin_atimeout(struct ast_channel *, void *);
189 static int pbx_builtin_wait(struct ast_channel *, void *);
190 static int pbx_builtin_waitexten(struct ast_channel *, void *);
191 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
192 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
193 static int pbx_builtin_setaccount(struct ast_channel *, void *);
194 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
195 static int pbx_builtin_ringing(struct ast_channel *, void *);
196 static int pbx_builtin_progress(struct ast_channel *, void *);
197 static int pbx_builtin_congestion(struct ast_channel *, void *);
198 static int pbx_builtin_busy(struct ast_channel *, void *);
199 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
200 static int pbx_builtin_noop(struct ast_channel *, void *);
201 static int pbx_builtin_gotoif(struct ast_channel *, void *);
202 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
203 static int pbx_builtin_execiftime(struct ast_channel *, void *);
204 static int pbx_builtin_saynumber(struct ast_channel *, void *);
205 static int pbx_builtin_saydigits(struct ast_channel *, void *);
206 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
207 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
208 int pbx_builtin_setvar(struct ast_channel *, void *);
209 static int pbx_builtin_importvar(struct ast_channel *, void *);
210 static char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len);
211 static void ast_func_write(struct ast_channel *chan, const char *in, const char *value);
213 static struct varshead globals;
215 static int autofallthrough = 0;
217 static struct ast_custom_function_obj *acf_root = NULL;
219 static struct pbx_builtin {
220 char name[AST_MAX_APP];
221 int (*execute)(struct ast_channel *chan, void *data);
226 /* These applications are built into the PBX core and do not
227 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"
237 { "Answer", pbx_builtin_answer,
238 "Answer a channel if ringing",
239 " Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
240 "If delay is specified, asterisk will pause execution for the specified amount\n"
241 "of milliseconds if an answer is required, in order to give audio a chance to\n"
242 "become ready. Returns 0 unless it tries to answer the channel and fails.\n"
245 { "BackGround", pbx_builtin_background,
246 "Play a file while awaiting extension",
247 " Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
248 "given files, while simultaneously waiting for the user to begin typing\n"
249 "an extension. The timeouts do not count until the last BackGround\n"
250 "application has ended. Options may also be included following a pipe \n"
251 "symbol. The 'langoverride' may be a language to use for playing the prompt\n"
252 "which differs from the current language of the channel. Returns -1 if \n"
253 "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
255 " 's' - causes the playback of the message to be skipped\n"
256 " if the channel is not in the 'up' state (i.e. it\n"
257 " hasn't been answered yet.) If this happens, the\n"
258 " application will return immediately.\n"
259 " 'n' - don't answer the channel before playing the files\n"
262 { "Busy", pbx_builtin_busy,
263 "Indicate busy condition and stop",
264 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
265 "then waits for the user to hang up or the optional timeout to expire.\n"
269 { "Congestion", pbx_builtin_congestion,
270 "Indicate congestion and stop",
271 " Congestion([timeout]): Requests that the channel indicate congestion\n"
272 "and then waits for the user to hang up or for the optional timeout to\n"
273 "expire. Always returns -1."
276 { "DigitTimeout", pbx_builtin_dtimeout,
277 "Set maximum timeout between digits",
278 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
279 "digits when the user is typing in an extension. When this timeout expires,\n"
280 "after the user has started to type in an extension, the extension will be\n"
281 "considered complete, and will be interpreted. Note that if an extension\n"
282 "typed in is valid, it will not have to timeout to be tested, so typically\n"
283 "at the expiry of this timeout, the extension will be considered invalid\n"
284 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
285 "exist the call would be terminated). The default timeout is 5 seconds.\n"
286 "Always returns 0.\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"
372 { "Ringing", pbx_builtin_ringing,
373 "Indicate ringing tone",
374 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
375 "Always returns 0.\n"
378 { "SayNumber", pbx_builtin_saynumber,
380 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
381 "the current language setting for the channel. (See app SetLanguage).\n"
384 { "SayDigits", pbx_builtin_saydigits,
386 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
387 "current language setting for the channel. (See app setLanguage)\n"
390 { "SayAlpha", pbx_builtin_saycharacters,
392 " SayAlpha(string): Spells the passed string\n"
395 { "SayPhonetic", pbx_builtin_sayphonetic,
397 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
400 { "SetAccount", pbx_builtin_setaccount,
402 " SetAccount([account]): Set the channel account code for billing\n"
403 "purposes. Always returns 0.\n"
406 { "SetAMAFlags", pbx_builtin_setamaflags,
408 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
409 "purposes. Always returns 0.\n"
412 { "SetGlobalVar", pbx_builtin_setglobalvar,
413 "Set global variable to value",
414 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
415 "variable are available across channels.\n"
418 { "SetLanguage", pbx_builtin_setlanguage,
419 "Sets channel language",
420 " SetLanguage(language): Set the channel language to 'language'. This\n"
421 "information is used for the syntax in generation of numbers, and to choose\n"
422 "a natural language file when available.\n"
423 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
424 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
425 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
426 "For some language codes, SetLanguage also changes the syntax of some\n"
427 "Asterisk functions, like SayNumber.\n"
428 "Always returns 0.\n"
431 { "SetVar", pbx_builtin_setvar,
432 "Set channel variable to value",
433 " SetVar(#n1=value|#n2=value|..[|options]) \n"
434 "You can specify an endless list of name / value pairs to be set as channel variables.\n"
435 " #n=value: Sets variable n to value. If prefixed with _, single\n"
436 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n"
437 "The last arg (if it doesn't contain an '=' ) is intrepreted as a string of\n"
438 "options. Valid Options:\n"
439 " - c - CDR, if set set the var as a CDR variable also.\n"
440 " - r - Recursive CDR, if there are any stacked CDRs, also apply to all as a cdr var.\n"
441 " - g - Set a global variable not a channel variable.\n"
444 { "ImportVar", pbx_builtin_importvar,
445 "Set variable to value",
446 " ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on\n"
447 "the specified channel (instead of current). If prefixed with _, single\n"
448 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
450 { "StripMSD", pbx_builtin_stripmsd,
451 "Strip leading digits",
452 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
453 "associated extension. For example, the number 5551212 when stripped with a\n"
454 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
455 "will continue processing at the next priority for the *new* extension.\n"
456 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
457 "executed will be priority 4 of 1212. If you switch into an extension which\n"
458 "has no first step, the PBX will treat it as though the user dialed an\n"
459 "invalid extension.\n"
462 { "Suffix", pbx_builtin_suffix,
463 "Append trailing digits",
464 " Suffix(digits): Appends the digit string specified by digits to the\n"
465 "channel's associated extension. For example, the number 555 when suffixed\n"
466 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
467 "continue processing at the next priority for the *new* extension.\n"
468 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
469 "executed will be priority 4 of 5551212. If you switch into an extension\n"
470 "which has no first step, the PBX will treat it as though the user dialed an\n"
471 "invalid extension.\n"
474 { "Wait", pbx_builtin_wait,
475 "Waits for some time",
476 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
477 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
480 { "WaitExten", pbx_builtin_waitexten,
481 "Waits for an extension to be entered",
482 " WaitExten([seconds][|options]): Waits for the user to enter a new extension for the \n"
483 "specified number of seconds, then returns 0. Seconds can be passed with\n"
484 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
485 "default extension timeout will be used.\n"
487 " 'm[(x)]' - Provide music on hold to the caller while waiting for an extension.\n"
488 " Optionally, specify the class for music on hold within parenthesis.\n"
493 static struct ast_context *contexts = NULL;
494 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
495 static struct ast_app *apps = NULL;
496 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
498 struct ast_switch *switches = NULL;
499 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
501 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
502 static int stateid = 1;
503 struct ast_hint *hints = NULL;
504 struct ast_state_cb *statecbs = NULL;
506 int pbx_exec(struct ast_channel *c, /* Channel */
507 struct ast_app *app, /* Application */
508 void *data, /* Data for execution */
509 int newstack) /* Force stack increment */
511 /* This function is special. It saves the stack so that no matter
512 how many times it is called, it returns to the same place */
518 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
522 ast_cdr_setapp(c->cdr, app->name, data);
524 /* save channel values */
525 saved_c_appl= c->appl;
526 saved_c_data= c->data;
530 res = execute(c, data);
531 /* restore channel values */
532 c->appl= saved_c_appl;
533 c->data= saved_c_data;
536 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
541 /* Go no deeper than this through includes (not counting loops) */
542 #define AST_PBX_MAX_STACK 128
544 #define HELPER_EXISTS 0
545 #define HELPER_SPAWN 1
546 #define HELPER_EXEC 2
547 #define HELPER_CANMATCH 3
548 #define HELPER_MATCHMORE 4
549 #define HELPER_FINDLABEL 5
551 struct ast_app *pbx_findapp(const char *app)
555 if (ast_mutex_lock(&applock)) {
556 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
561 if (!strcasecmp(tmp->name, app))
565 ast_mutex_unlock(&applock);
569 static struct ast_switch *pbx_findswitch(const char *sw)
571 struct ast_switch *asw;
573 if (ast_mutex_lock(&switchlock)) {
574 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
579 if (!strcasecmp(asw->name, sw))
583 ast_mutex_unlock(&switchlock);
587 static inline int include_valid(struct ast_include *i)
592 return ast_check_timing(&(i->timing));
595 static void pbx_destroy(struct ast_pbx *p)
600 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
601 /* All patterns begin with _ */\
602 if (pattern[0] != '_') \
604 /* Start optimistic */\
607 while(match && *data && *pattern && (*pattern != '/')) {\
608 while (*data == '-' && (*(data+1) != '\0')) data++;\
609 switch(toupper(*pattern)) {\
616 where=strchr(pattern,']');\
618 border=(int)(where-pattern);\
619 if (!where || border > strlen(pattern)) {\
620 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
623 for (i=0; i<border; i++) {\
626 if (pattern[i+1]=='-') {\
627 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
634 if (res==1 || *data==pattern[i]) {\
643 if ((*data < '2') || (*data > '9'))\
647 if ((*data < '0') || (*data > '9'))\
651 if ((*data < '1') || (*data > '9'))\
662 /* Ignore these characters */\
666 if (*data != *pattern)\
672 /* If we ran off the end of the data and the pattern ends in '!', match */\
673 if (match && !*data && (*pattern == '!'))\
677 int ast_extension_match(const char *pattern, const char *data)
680 /* If they're the same return */
681 if (!strcmp(pattern, data))
683 EXTENSION_MATCH_CORE(data,pattern,match);
684 /* Must be at the end of both */
685 if (*data || (*pattern && (*pattern != '/')))
690 int ast_extension_close(const char *pattern, const char *data, int needmore)
693 /* If "data" is longer, it can'be a subset of pattern unless
694 pattern is a pattern match */
695 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
698 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
699 (!needmore || (strlen(pattern) > strlen(data)))) {
702 EXTENSION_MATCH_CORE(data,pattern,match);
703 /* If there's more or we don't care about more, or if it's a possible early match,
704 return non-zero; otherwise it's a miss */
705 if (!needmore || *pattern || match == 2) {
711 struct ast_context *ast_context_find(const char *name)
713 struct ast_context *tmp;
714 ast_mutex_lock(&conlock);
718 if (!strcasecmp(name, tmp->name))
724 ast_mutex_unlock(&conlock);
728 #define STATUS_NO_CONTEXT 1
729 #define STATUS_NO_EXTENSION 2
730 #define STATUS_NO_PRIORITY 3
731 #define STATUS_NO_LABEL 4
732 #define STATUS_SUCCESS 5
734 static int matchcid(const char *cidpattern, const char *callerid)
738 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
739 failing to get a number should count as a match, otherwise not */
742 if (!ast_strlen_zero(cidpattern))
750 return ast_extension_match(cidpattern, callerid);
753 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)
756 struct ast_context *tmp;
757 struct ast_exten *e, *eroot;
758 struct ast_include *i;
760 struct ast_switch *asw;
762 /* Initialize status if appropriate */
764 *status = STATUS_NO_CONTEXT;
768 /* Check for stack overflow */
769 if (*stacklen >= AST_PBX_MAX_STACK) {
770 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
773 /* Check first to see if we've already been checked */
774 for (x=0; x<*stacklen; x++) {
775 if (!strcasecmp(incstack[x], context))
784 if (bypass || !strcmp(tmp->name, context)) {
785 struct ast_exten *earlymatch = NULL;
787 if (*status < STATUS_NO_EXTENSION)
788 *status = STATUS_NO_EXTENSION;
789 for (eroot = tmp->root; eroot; eroot=eroot->next) {
791 /* Match extension */
792 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
793 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
794 ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
795 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
797 if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
798 /* It matched an extension ending in a '!' wildcard
799 So ignore it for now, unless there's a better match */
803 if (*status < STATUS_NO_PRIORITY)
804 *status = STATUS_NO_PRIORITY;
807 if (action == HELPER_FINDLABEL) {
808 if (*status < STATUS_NO_LABEL)
809 *status = STATUS_NO_LABEL;
810 if (label && e->label && !strcmp(label, e->label)) {
811 *status = STATUS_SUCCESS;
812 *foundcontext = context;
815 } else if (e->priority == priority) {
816 *status = STATUS_SUCCESS;
817 *foundcontext = context;
826 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
827 of the loop waiting for more digits, and _then_ match (normally)
828 the extension we ended up with. We got an early-matching wildcard
829 pattern, so return NULL to break out of the loop. */
832 /* Check alternative switches */
835 if ((asw = pbx_findswitch(sw->name))) {
836 /* Substitute variables now */
838 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
839 if (action == HELPER_CANMATCH)
840 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
841 else if (action == HELPER_MATCHMORE)
842 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
844 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
848 *data = sw->eval ? sw->tmpdata : sw->data;
849 *foundcontext = context;
853 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
857 /* Setup the stack */
858 incstack[*stacklen] = tmp->name;
860 /* Now try any includes we have in this context */
863 if (include_valid(i)) {
864 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
878 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
879 functions in the dialplan
881 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
884 char tmpvar[80] = "";
886 struct tm brokentime;
888 struct ast_var_t *variables;
893 if ((first=strchr(var,':'))) { /* : Remove characters counting from end or start of string */
894 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
895 first = strchr(tmpvar, ':');
897 first = tmpvar + strlen(tmpvar);
899 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
902 offset=atoi(first+1); /* The number of characters,
903 positive: remove # of chars from start
904 negative: keep # of chars from end */
906 if ((second=strchr(first+1,':'))) {
908 offset2 = atoi(second+1); /* Number of chars to copy */
909 } else if (offset >= 0) {
910 offset2 = strlen(*ret)-offset; /* Rest of string */
912 offset2 = abs(offset);
915 if (abs(offset) > strlen(*ret)) { /* Offset beyond string */
919 offset=-strlen(*ret);
921 if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
923 offset2=strlen(*ret)-offset;
925 offset2=strlen(*ret)+offset;
930 *ret += strlen(*ret)+offset;
931 (*ret)[offset2] = '\0'; /* Cut at offset2 position */
932 } else if (c && !strncmp(var, "CALL", 4)) {
933 if (!strncmp(var + 4, "ER", 2)) {
934 if (!strncmp(var + 6, "ID", 2)) {
935 if (!var[8]) { /* CALLERID */
936 if (c->cid.cid_num) {
937 if (c->cid.cid_name) {
938 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
940 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
943 } else if (c->cid.cid_name) {
944 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
948 } else if (!strcmp(var + 8, "NUM")) {
950 if (c->cid.cid_num) {
951 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
955 } else if (!strcmp(var + 8, "NAME")) {
957 if (c->cid.cid_name) {
958 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
963 } else if (!strcmp(var + 6, "ANI")) {
965 if (c->cid.cid_ani) {
966 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
972 } else if (!strncmp(var + 4, "ING", 3)) {
973 if (!strcmp(var + 7, "PRES")) {
975 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
977 } else if (!strcmp(var + 7, "ANI2")) {
979 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
981 } else if (!strcmp(var + 7, "TON")) {
983 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
985 } else if (!strcmp(var + 7, "TNS")) {
987 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
993 } else if (c && !strcmp(var, "DNID")) {
994 if (c->cid.cid_dnid) {
995 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
999 } else if (c && !strcmp(var, "HINT")) {
1000 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
1004 } else if (c && !strcmp(var, "HINTNAME")) {
1005 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
1009 } else if (c && !strcmp(var, "EXTEN")) {
1010 strncpy(workspace, c->exten, workspacelen - 1);
1012 } else if (c && !strcmp(var, "RDNIS")) {
1013 if (c->cid.cid_rdnis) {
1014 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
1018 } else if (c && !strcmp(var, "CONTEXT")) {
1019 strncpy(workspace, c->context, workspacelen - 1);
1021 } else if (c && !strcmp(var, "PRIORITY")) {
1022 snprintf(workspace, workspacelen, "%d", c->priority);
1024 } else if (c && !strcmp(var, "CHANNEL")) {
1025 strncpy(workspace, c->name, workspacelen - 1);
1027 } else if (!strcmp(var, "EPOCH")) {
1028 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1030 } else if (!strcmp(var, "DATETIME")) {
1031 thistime=time(NULL);
1032 localtime_r(&thistime, &brokentime);
1033 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
1035 brokentime.tm_mon+1,
1036 brokentime.tm_year+1900,
1042 } else if (!strcmp(var, "TIMESTAMP")) {
1043 thistime=time(NULL);
1044 localtime_r(&thistime, &brokentime);
1045 /* 20031130-150612 */
1046 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
1047 brokentime.tm_year+1900,
1048 brokentime.tm_mon+1,
1055 } else if (c && !strcmp(var, "UNIQUEID")) {
1056 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1058 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1059 snprintf(workspace, workspacelen, "%i", c->hangupcause);
1061 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1062 strncpy(workspace, c->accountcode, workspacelen - 1);
1064 } else if (c && !strcmp(var, "LANGUAGE")) {
1065 strncpy(workspace, c->language, workspacelen - 1);
1070 AST_LIST_TRAVERSE(headp,variables,entries) {
1072 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1074 if (strcasecmp(ast_var_name(variables),var)==0) {
1075 *ret=ast_var_value(variables);
1077 strncpy(workspace, *ret, workspacelen - 1);
1086 AST_LIST_TRAVERSE(&globals,variables,entries) {
1088 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1090 if (strcasecmp(ast_var_name(variables),var)==0) {
1091 *ret=ast_var_value(variables);
1093 strncpy(workspace, *ret, workspacelen - 1);
1102 static int handle_show_functions(int fd, int argc, char *argv[])
1104 struct ast_custom_function_obj *acfptr;
1106 ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
1107 for (acfptr = acf_root ; acfptr ; acfptr = acfptr->next) {
1108 ast_cli(fd, "%s\t(%s)\t[%s]\n", acfptr->name, acfptr->desc, acfptr->syntax);
1114 struct ast_custom_function_obj* ast_custom_function_find_obj(char *name)
1116 struct ast_custom_function_obj *acfptr;
1118 for (acfptr = acf_root ; acfptr ; acfptr = acfptr->next) {
1119 if (!strcmp(name, acfptr->name)) {
1127 int ast_custom_function_unregister(struct ast_custom_function_obj *acf)
1129 struct ast_custom_function_obj *acfptr, *lastacf = NULL;
1132 for (acfptr = acf_root ; acfptr ; acfptr = acfptr->next) {
1133 if (acfptr == acf) {
1135 lastacf->next = acf->next;
1137 acf_root = acf->next;
1140 ast_verbose(VERBOSE_PREFIX_1 "Unregistered custom function %s\n", acf->name);
1149 int ast_custom_function_register(struct ast_custom_function_obj *acf)
1151 struct ast_custom_function_obj *acfptr;
1154 if((acfptr = ast_custom_function_find_obj(acf->name))) {
1155 ast_log(LOG_ERROR, "Function %s already in use.\n", acf->name);
1158 acf->next = acf_root;
1161 ast_verbose(VERBOSE_PREFIX_1 "Registered custom function %s\n", acf->name);
1168 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1170 char *args = NULL, *function, *p;
1172 struct ast_custom_function_obj *acfptr;
1174 function = ast_strdupa(in);
1176 if ((args = strchr(function, '('))) {
1179 if ((p = strrchr(args, ')'))) {
1182 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1185 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1188 if ((acfptr = ast_custom_function_find_obj(function))) {
1189 /* run the custom function */
1191 return acfptr->read(chan, function, args, workspace, len);
1193 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1196 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1199 ast_log(LOG_ERROR, "Out of memory\n");
1204 static void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1206 char *args = NULL, *function, *p;
1207 struct ast_custom_function_obj *acfptr;
1209 function = ast_strdupa(in);
1211 if ((args = strchr(function, '('))) {
1214 if ((p = strrchr(args, ')'))) {
1217 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1220 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1223 if ((acfptr = ast_custom_function_find_obj(function))) {
1224 /* run the custom function */
1225 if (acfptr->write) {
1226 acfptr->write(chan, function, args, value);
1228 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1231 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1234 ast_log(LOG_ERROR, "Out of memory\n");
1238 static char *builtin_function_isnull(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1240 char *ret_true = "1", *ret_false = "0";
1241 return data && *data ? ret_false : ret_true;
1244 static char *builtin_function_exists(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1246 char *ret_true = "1", *ret_false = "0";
1247 return data && *data ? ret_true : ret_false;
1250 static char *builtin_function_if(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1253 char *mydata = NULL;
1255 char *iftrue = NULL;
1256 char *iffalse = NULL;
1258 if((mydata = ast_strdupa(data))) {
1260 if ((iftrue = strchr(mydata, '?'))) {
1263 if ((iffalse = strchr(iftrue, ':'))) {
1269 if (expr && iftrue) {
1270 ret = ast_true(expr) ? iftrue : iffalse;
1271 strncpy(buf, ret, len);
1274 ast_log(LOG_WARNING, "Syntax $(if <expr>?[<truecond>][:<falsecond>])\n");
1278 ast_log(LOG_WARNING, "Memory Error!\n");
1285 static char *builtin_function_env_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1293 strncpy(buf, ret, len);
1294 buf[len - 1] = '\0';
1298 static void builtin_function_env_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
1300 if (data && !ast_strlen_zero(data)) {
1301 if (value && !ast_strlen_zero(value)) {
1302 setenv(data, value, 1);
1309 static char *builtin_function_len(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1313 length = strlen(data);
1315 snprintf(buf, len, "%d", length);
1319 static char *builtin_function_cdr_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1322 if (chan && chan->cdr && data) {
1323 ast_cdr_getvar(chan->cdr, data, &ret, buf, len, 1);
1328 static void builtin_function_cdr_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
1330 if (chan && chan->cdr && data) {
1331 ast_cdr_setvar(chan->cdr, data, value, 1);
1335 static char *builtin_function_regex(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
1337 char *ret_true = "1", *ret_false = "0", *ret;
1338 char *arg, *earg, *tmp, errstr[256] = "";
1342 ret = ret_false; /* convince me otherwise */
1343 tmp = ast_strdupa(data);
1345 /* Regex in quotes */
1346 arg = strchr(tmp, '"');
1349 earg = strrchr(arg, '"');
1357 if ((errcode = regcomp(®exbuf, arg, REG_EXTENDED | REG_NOSUB))) {
1358 regerror(errcode, ®exbuf, errstr, sizeof(errstr));
1359 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, data, errstr);
1362 ret = regexec(®exbuf, data, 0, NULL, 0) ? ret_false : ret_true;
1366 ast_log(LOG_ERROR, "Out of memory in %s(%s)\n", cmd, data);
1372 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1375 const char *tmp, *whereweare;
1377 char workspace[4096];
1378 char ltmp[4096], var[4096];
1379 char *nextvar, *nextexp, *nextthing;
1381 int pos, brackets, needsub, len;
1383 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1386 while(!ast_strlen_zero(whereweare) && count) {
1387 /* Assume we're copying the whole remaining string */
1388 pos = strlen(whereweare);
1391 nextthing = strchr(whereweare, '$');
1393 switch(nextthing[1]) {
1395 nextvar = nextthing;
1398 nextexp = nextthing;
1402 /* If there is one, we only go that far */
1404 pos = nextvar - whereweare;
1406 pos = nextexp - whereweare;
1408 /* Can't copy more than 'count' bytes */
1412 /* Copy that many bytes */
1413 memcpy(cp2, whereweare, pos);
1420 /* We have a variable. Find the start and end, and determine
1421 if we are going to have to recursively call ourselves on the
1423 vars = vare = nextvar + 2;
1427 /* Find the end of it */
1428 while(brackets && *vare) {
1429 if ((vare[0] == '$') && (vare[1] == '{')) {
1432 } else if (vare[0] == '}') {
1434 } else if ((vare[0] == '$') && (vare[1] == '['))
1439 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1440 len = vare - vars - 1;
1442 /* Skip totally over variable name */
1443 whereweare += ( len + 3);
1445 /* Store variable name (and truncate) */
1446 memset(var, 0, sizeof(var));
1447 strncpy(var, vars, sizeof(var) - 1);
1450 /* Substitute if necessary */
1452 memset(ltmp, 0, sizeof(ltmp));
1453 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1459 workspace[0] = '\0';
1461 if (var[len - 1] == ')') {
1462 /* Evaluate function */
1463 cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
1465 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4);
1467 /* Retrieve variable value */
1468 pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
1471 length = strlen(cp4);
1474 memcpy(cp2, cp4, length);
1478 } else if (nextexp) {
1479 /* We have an expression. Find the start and end, and determine
1480 if we are going to have to recursively call ourselves on the
1482 vars = vare = nextexp + 2;
1486 /* Find the end of it */
1487 while(brackets && *vare) {
1488 if ((vare[0] == '$') && (vare[1] == '[')) {
1492 } else if (vare[0] == '[') {
1494 } else if (vare[0] == ']') {
1496 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1503 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1504 len = vare - vars - 1;
1506 /* Skip totally over variable name */
1507 whereweare += ( len + 3);
1509 /* Store variable name (and truncate) */
1510 memset(var, 0, sizeof(var));
1511 strncpy(var, vars, sizeof(var) - 1);
1514 /* Substitute if necessary */
1516 memset(ltmp, 0, sizeof(ltmp));
1517 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1523 /* Evaluate expression */
1524 cp4 = ast_expr(vars);
1526 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1529 length = strlen(cp4);
1532 memcpy(cp2, cp4, length);
1542 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1544 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1547 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1549 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1552 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1554 memset(passdata, 0, datalen);
1556 /* No variables or expressions in e->data, so why scan it? */
1557 if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1558 strncpy(passdata, e->data, datalen - 1);
1559 passdata[datalen-1] = '\0';
1563 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1566 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)
1568 struct ast_exten *e;
1569 struct ast_app *app;
1570 struct ast_switch *sw;
1572 const char *foundcontext=NULL;
1576 char *incstack[AST_PBX_MAX_STACK];
1577 char passdata[EXT_DATA_SIZE];
1581 char tmp3[EXT_DATA_SIZE];
1583 char atmp2[EXT_DATA_SIZE+100];
1585 if (ast_mutex_lock(&conlock)) {
1586 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1587 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1592 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1595 case HELPER_CANMATCH:
1596 ast_mutex_unlock(&conlock);
1599 ast_mutex_unlock(&conlock);
1601 case HELPER_FINDLABEL:
1603 ast_mutex_unlock(&conlock);
1605 case HELPER_MATCHMORE:
1606 ast_mutex_unlock(&conlock);
1612 app = pbx_findapp(e->app);
1613 ast_mutex_unlock(&conlock);
1615 if (c->context != context)
1616 strncpy(c->context, context, sizeof(c->context)-1);
1617 if (c->exten != exten)
1618 strncpy(c->exten, exten, sizeof(c->exten)-1);
1619 c->priority = priority;
1620 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1622 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1623 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1624 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"));
1625 pbx_builtin_setvar_helper(c, atmp, atmp2);
1627 if (option_verbose > 2)
1628 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1629 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1630 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1631 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1632 (newstack ? "in new stack" : "in same stack"));
1633 manager_event(EVENT_FLAG_CALL, "Newexten",
1638 "Application: %s\r\n"
1641 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1642 res = pbx_exec(c, app, passdata, newstack);
1645 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1649 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1653 case HELPER_CANMATCH:
1654 ast_mutex_unlock(&conlock);
1657 ast_mutex_unlock(&conlock);
1659 case HELPER_MATCHMORE:
1660 ast_mutex_unlock(&conlock);
1662 case HELPER_FINDLABEL:
1663 ast_mutex_unlock(&conlock);
1669 ast_mutex_unlock(&conlock);
1671 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1673 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1678 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1682 ast_mutex_unlock(&conlock);
1684 case STATUS_NO_CONTEXT:
1685 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1686 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1688 case STATUS_NO_EXTENSION:
1689 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1690 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1692 case STATUS_NO_PRIORITY:
1693 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1694 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1696 case STATUS_NO_LABEL:
1698 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1701 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1704 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1712 /*--- ast_hint_extension: Find hint for given extension in context */
1713 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1715 struct ast_exten *e;
1716 struct ast_switch *sw;
1718 const char *foundcontext = NULL;
1720 char *incstack[AST_PBX_MAX_STACK];
1723 if (ast_mutex_lock(&conlock)) {
1724 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1727 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1728 ast_mutex_unlock(&conlock);
1732 /*--- ast_extensions_state2: Check state of extension by using hints */
1733 static int ast_extension_state2(struct ast_exten *e)
1735 char hint[AST_MAX_EXTENSION] = "";
1738 int allunavailable = 1, allbusy = 1, allfree = 1;
1744 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1746 cur = hint; /* On or more devices separated with a & character */
1748 rest = strchr(cur, '&');
1754 res = ast_device_state(cur);
1756 case AST_DEVICE_NOT_INUSE:
1760 case AST_DEVICE_INUSE:
1761 return AST_EXTENSION_INUSE;
1762 case AST_DEVICE_BUSY:
1767 case AST_DEVICE_UNAVAILABLE:
1768 case AST_DEVICE_INVALID:
1781 return AST_EXTENSION_NOT_INUSE;
1783 return AST_EXTENSION_BUSY;
1785 return AST_EXTENSION_UNAVAILABLE;
1787 return AST_EXTENSION_INUSE;
1789 return AST_EXTENSION_NOT_INUSE;
1793 /*--- ast_extension_state: Check extension state for an extension by using hint */
1794 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1796 struct ast_exten *e;
1798 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1800 return -1; /* No hint, return -1 */
1802 return ast_extension_state2(e); /* Check all devices in the hint */
1805 /*--- ast_device_state_changed: If device state in cblist is changed - then notify callback function */
1806 int ast_device_state_changed(const char *fmt, ...)
1808 struct ast_hint *list;
1809 struct ast_state_cb *cblist;
1810 struct ast_devstate_cb *devcb;
1811 char hint[AST_MAX_EXTENSION] = "";
1812 char device[AST_MAX_EXTENSION];
1820 vsnprintf(device, sizeof(device), fmt, ap);
1823 rest = strchr(device, '-');
1829 state = ast_device_state(device);
1830 if (option_debug > 2)
1831 ast_log(LOG_DEBUG, "Changing state for %s - state %d\n", device, state);
1833 ast_mutex_lock(&hintlock);
1835 /* First check device callbacks */
1838 if (devcb->callback)
1839 devcb->callback(device, state, devcb->data);
1840 devcb = devcb->next;
1843 /* Then check callbacks in hints */
1848 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1851 rest = strchr(cur, '&');
1857 if (!strcmp(cur, device)) { /* Is this device referred to in this hint? */
1859 /* Get device state for this hint */
1860 state = ast_extension_state2(list->exten);
1862 if ((state != -1) && (state != list->laststate)) {
1863 /* Device state changed since last check - notify the watcher */
1865 /* For general callbacks */
1868 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1869 cblist = cblist->next;
1872 /* For extension callbacks */
1873 cblist = list->callbacks;
1875 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1876 cblist = cblist->next;
1879 list->laststate = state;
1887 ast_mutex_unlock(&hintlock);
1891 /*--- ast_devstate_add: Add device state watcher */
1892 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1894 struct ast_devstate_cb *devcb;
1895 devcb = malloc(sizeof(struct ast_devstate_cb));
1897 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1898 ast_mutex_lock(&hintlock);
1900 devcb->callback = callback;
1901 devcb->next = devcbs;
1903 ast_mutex_unlock(&hintlock);
1908 /*--- ast_devstate_del: Remove device state watcher */
1909 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1911 struct ast_devstate_cb *devcb, *prev = NULL, *next;
1912 ast_mutex_lock(&hintlock);
1916 if ((devcb->data == data) && (devcb->callback == callback)) {
1926 ast_mutex_unlock(&hintlock);
1929 /*--- ast_extension_state_add: Add watcher for extension states */
1930 int ast_extension_state_add(const char *context, const char *exten,
1931 ast_state_cb_type callback, void *data)
1933 struct ast_hint *list;
1934 struct ast_state_cb *cblist;
1935 struct ast_exten *e;
1937 /* If there's no context and extension: add callback to statecbs list */
1938 if (!context && !exten) {
1939 ast_mutex_lock(&hintlock);
1943 if (cblist->callback == callback) {
1944 cblist->data = data;
1945 ast_mutex_unlock(&hintlock);
1947 cblist = cblist->next;
1950 /* Now inserts the callback */
1951 cblist = malloc(sizeof(struct ast_state_cb));
1953 ast_mutex_unlock(&hintlock);
1956 memset(cblist, 0, sizeof(struct ast_state_cb));
1958 cblist->callback = callback;
1959 cblist->data = data;
1961 cblist->next = statecbs;
1964 ast_mutex_unlock(&hintlock);
1968 if (!context || !exten)
1971 /* This callback type is for only one hint, so get the hint */
1972 e = ast_hint_extension(NULL, context, exten);
1977 /* Find the hint in the list of hints */
1978 ast_mutex_lock(&hintlock);
1982 if (list->exten == e)
1988 /* We have no hint, sorry */
1989 ast_mutex_unlock(&hintlock);
1993 /* Now insert the callback in the callback list */
1994 cblist = malloc(sizeof(struct ast_state_cb));
1996 ast_mutex_unlock(&hintlock);
1999 memset(cblist, 0, sizeof(struct ast_state_cb));
2000 cblist->id = stateid++; /* Unique ID for this callback */
2001 cblist->callback = callback; /* Pointer to callback routine */
2002 cblist->data = data; /* Data for the callback */
2004 cblist->next = list->callbacks;
2005 list->callbacks = cblist;
2007 ast_mutex_unlock(&hintlock);
2011 /*--- ast_extension_state_del: Remove a watcher from the callback list */
2012 int ast_extension_state_del(int id, ast_state_cb_type callback)
2014 struct ast_hint *list;
2015 struct ast_state_cb *cblist, *cbprev;
2017 if (!id && !callback)
2020 ast_mutex_lock(&hintlock);
2022 /* id is zero is a callback without extension */
2027 if (cblist->callback == callback) {
2029 statecbs = cblist->next;
2031 cbprev->next = cblist->next;
2035 ast_mutex_unlock(&hintlock);
2039 cblist = cblist->next;
2042 ast_mutex_lock(&hintlock);
2046 /* id greater than zero is a callback with extension */
2047 /* Find the callback based on ID */
2050 cblist = list->callbacks;
2053 if (cblist->id==id) {
2055 list->callbacks = cblist->next;
2057 cbprev->next = cblist->next;
2061 ast_mutex_unlock(&hintlock);
2065 cblist = cblist->next;
2070 ast_mutex_unlock(&hintlock);
2074 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
2075 static int ast_add_hint(struct ast_exten *e)
2077 struct ast_hint *list;
2082 ast_mutex_lock(&hintlock);
2085 /* Search if hint exists, do nothing */
2087 if (list->exten == e) {
2088 ast_mutex_unlock(&hintlock);
2089 if (option_debug > 1)
2090 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2096 if (option_debug > 1)
2097 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2099 list = malloc(sizeof(struct ast_hint));
2101 ast_mutex_unlock(&hintlock);
2102 if (option_debug > 1)
2103 ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
2106 /* Initialize and insert new item at the top */
2107 memset(list, 0, sizeof(struct ast_hint));
2109 list->laststate = ast_extension_state2(e);
2113 ast_mutex_unlock(&hintlock);
2117 /*--- ast_change_hint: Change hint for an extension */
2118 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2120 struct ast_hint *list;
2122 ast_mutex_lock(&hintlock);
2126 if (list->exten == oe) {
2128 ast_mutex_unlock(&hintlock);
2133 ast_mutex_unlock(&hintlock);
2138 /*--- ast_remove_hint: Remove hint from extension */
2139 static int ast_remove_hint(struct ast_exten *e)
2141 /* Cleanup the Notifys if hint is removed */
2142 struct ast_hint *list, *prev = NULL;
2143 struct ast_state_cb *cblist, *cbprev;
2148 ast_mutex_lock(&hintlock);
2152 if (list->exten==e) {
2154 cblist = list->callbacks;
2156 /* Notify with -1 and remove all callbacks */
2158 cblist = cblist->next;
2159 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
2162 list->callbacks = NULL;
2167 prev->next = list->next;
2170 ast_mutex_unlock(&hintlock);
2178 ast_mutex_unlock(&hintlock);
2183 /*--- ast_get_hint: Get hint for channel */
2184 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2186 struct ast_exten *e;
2188 e = ast_hint_extension(c, context, exten);
2191 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
2193 tmp = ast_get_extension_app_data(e);
2195 strncpy(name, (char *)tmp, namesize - 1);
2202 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2204 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2207 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2209 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2212 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2214 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2217 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2219 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2222 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2224 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2227 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2229 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2232 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2234 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2237 int ast_pbx_run(struct ast_channel *c)
2246 /* A little initial setup here */
2248 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2249 c->pbx = malloc(sizeof(struct ast_pbx));
2251 ast_log(LOG_ERROR, "Out of memory\n");
2256 c->cdr = ast_cdr_alloc();
2258 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2262 ast_cdr_init(c->cdr, c);
2265 memset(c->pbx, 0, sizeof(struct ast_pbx));
2266 /* Set reasonable defaults */
2267 c->pbx->rtimeout = 10;
2268 c->pbx->dtimeout = 5;
2270 /* Start by trying whatever the channel is set to */
2271 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2272 /* JK02: If not successfull fall back to 's' */
2273 if (option_verbose > 1)
2274 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);
2275 strncpy(c->exten, "s", sizeof(c->exten)-1);
2276 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2277 /* JK02: And finally back to default if everything else failed */
2278 if (option_verbose > 1)
2279 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);
2280 strncpy(c->context, "default", sizeof(c->context)-1);
2284 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2285 ast_cdr_start(c->cdr);
2289 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2290 memset(exten, 0, sizeof(exten));
2291 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2292 /* Something bad happened, or a hangup has been requested. */
2293 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2294 (res == '*') || (res == '#')) {
2295 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2296 memset(exten, 0, sizeof(exten));
2298 exten[pos++] = digit = res;
2302 case AST_PBX_KEEPALIVE:
2304 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2305 else if (option_verbose > 1)
2306 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2311 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2312 else if (option_verbose > 1)
2313 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2314 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2319 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2329 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2330 strncpy(c->exten,"T",sizeof(c->exten) - 1);
2331 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2332 c->whentohangup = 0;
2334 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2335 } else if (c->_softhangup) {
2336 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2337 c->exten, c->priority);
2343 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2344 /* It's not a valid extension anymore */
2345 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2346 if (option_verbose > 2)
2347 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2348 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2349 strncpy(c->exten, "i", sizeof(c->exten)-1);
2352 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2353 c->name, c->exten, c->context);
2356 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2357 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2360 /* Done, wait for an extension */
2363 waittime = c->pbx->dtimeout;
2364 else if (!autofallthrough)
2365 waittime = c->pbx->rtimeout;
2367 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2368 /* As long as we're willing to wait, and as long as it's not defined,
2369 keep reading digits until we can't possibly get a right answer anymore. */
2370 digit = ast_waitfordigit(c, waittime * 1000);
2371 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2378 /* Error, maybe a hangup */
2380 exten[pos++] = digit;
2381 waittime = c->pbx->dtimeout;
2384 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2385 /* Prepare the next cycle */
2386 strncpy(c->exten, exten, sizeof(c->exten)-1);
2389 /* No such extension */
2390 if (!ast_strlen_zero(exten)) {
2391 /* An invalid extension */
2392 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2393 if (option_verbose > 2)
2394 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2395 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2396 strncpy(c->exten, "i", sizeof(c->exten)-1);
2399 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2403 /* A simple timeout */
2404 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2405 if (option_verbose > 2)
2406 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2407 strncpy(c->exten, "t", sizeof(c->exten)-1);
2410 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2416 if (option_verbose > 2)
2417 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2422 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2425 if (option_verbose > 2)
2426 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2427 if (!strcasecmp(status, "CONGESTION"))
2428 res = pbx_builtin_congestion(c, "10");
2429 else if (!strcasecmp(status, "CHANUNAVAIL"))
2430 res = pbx_builtin_congestion(c, "10");
2431 else if (!strcasecmp(status, "BUSY"))
2432 res = pbx_builtin_busy(c, "10");
2438 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2440 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2444 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2445 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2446 /* Something bad happened, or a hangup has been requested. */
2448 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2449 else if (option_verbose > 1)
2450 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2457 pbx_destroy(c->pbx);
2459 if (res != AST_PBX_KEEPALIVE)
2464 static void *pbx_thread(void *data)
2466 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2467 answer this channel and get it going. The setjmp stuff is fairly
2468 confusing, but necessary to get smooth transitions between
2469 the execution of different applications (without the use of
2470 additional threads) */
2471 struct ast_channel *c = data;
2477 int ast_pbx_start(struct ast_channel *c)
2480 pthread_attr_t attr;
2482 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2486 /* Start a new thread, and get something handling this channel. */
2487 pthread_attr_init(&attr);
2488 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2489 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2490 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2496 int pbx_set_autofallthrough(int newval)
2499 oldval = autofallthrough;
2500 if (oldval != newval)
2501 autofallthrough = newval;
2506 * This function locks contexts list by &conlist, search for the right context
2507 * structure, leave context list locked and call ast_context_remove_include2
2508 * which removes include, unlock contexts list and return ...
2510 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2512 struct ast_context *c;
2514 if (ast_lock_contexts()) return -1;
2516 /* walk contexts and search for the right one ...*/
2517 c = ast_walk_contexts(NULL);
2519 /* we found one ... */
2520 if (!strcmp(ast_get_context_name(c), context)) {
2522 /* remove include from this context ... */
2523 ret = ast_context_remove_include2(c, include, registrar);
2525 ast_unlock_contexts();
2527 /* ... return results */
2530 c = ast_walk_contexts(c);
2533 /* we can't find the right one context */
2534 ast_unlock_contexts();
2539 * When we call this function, &conlock lock must be locked, because when
2540 * we giving *con argument, some process can remove/change this context
2541 * and after that there can be segfault.
2543 * This function locks given context, removes include, unlock context and
2546 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2548 struct ast_include *i, *pi = NULL;
2550 if (ast_mutex_lock(&con->lock)) return -1;
2555 /* find our include */
2556 if (!strcmp(i->name, include) &&
2557 (!registrar || !strcmp(i->registrar, registrar))) {
2558 /* remove from list */
2562 con->includes = i->next;
2563 /* free include and return */
2565 ast_mutex_unlock(&con->lock);
2572 /* we can't find the right include */
2573 ast_mutex_unlock(&con->lock);
2578 * This function locks contexts list by &conlist, search for the rigt context
2579 * structure, leave context list locked and call ast_context_remove_switch2
2580 * which removes switch, unlock contexts list and return ...
2582 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2584 struct ast_context *c;
2586 if (ast_lock_contexts()) return -1;
2588 /* walk contexts and search for the right one ...*/
2589 c = ast_walk_contexts(NULL);
2591 /* we found one ... */
2592 if (!strcmp(ast_get_context_name(c), context)) {
2594 /* remove switch from this context ... */
2595 ret = ast_context_remove_switch2(c, sw, data, registrar);
2597 ast_unlock_contexts();
2599 /* ... return results */
2602 c = ast_walk_contexts(c);
2605 /* we can't find the right one context */
2606 ast_unlock_contexts();
2611 * When we call this function, &conlock lock must be locked, because when
2612 * we giving *con argument, some process can remove/change this context
2613 * and after that there can be segfault.
2615 * This function locks given context, removes switch, unlock context and
2618 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2620 struct ast_sw *i, *pi = NULL;
2622 if (ast_mutex_lock(&con->lock)) return -1;
2627 /* find our switch */
2628 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2629 (!registrar || !strcmp(i->registrar, registrar))) {
2630 /* remove from list */
2634 con->alts = i->next;
2635 /* free switch and return */
2637 ast_mutex_unlock(&con->lock);
2644 /* we can't find the right switch */
2645 ast_mutex_unlock(&con->lock);
2650 * This functions lock contexts list, search for the right context,
2651 * call ast_context_remove_extension2, unlock contexts list and return.
2652 * In this function we are using
2654 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2656 struct ast_context *c;
2658 if (ast_lock_contexts()) return -1;
2660 /* walk contexts ... */
2661 c = ast_walk_contexts(NULL);
2663 /* ... search for the right one ... */
2664 if (!strcmp(ast_get_context_name(c), context)) {
2665 /* ... remove extension ... */
2666 int ret = ast_context_remove_extension2(c, extension, priority,
2668 /* ... unlock contexts list and return */
2669 ast_unlock_contexts();
2672 c = ast_walk_contexts(c);
2675 /* we can't find the right context */
2676 ast_unlock_contexts();
2681 * When do you want to call this function, make sure that &conlock is locked,
2682 * because some process can handle with your *con context before you lock
2685 * This functionc locks given context, search for the right extension and
2686 * fires out all peer in this extensions with given priority. If priority
2687 * is set to 0, all peers are removed. After that, unlock context and
2690 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2692 struct ast_exten *exten, *prev_exten = NULL;
2694 if (ast_mutex_lock(&con->lock)) return -1;
2696 /* go through all extensions in context and search the right one ... */
2700 /* look for right extension */
2701 if (!strcmp(exten->exten, extension) &&
2702 (!registrar || !strcmp(exten->registrar, registrar))) {
2703 struct ast_exten *peer;
2705 /* should we free all peers in this extension? (priority == 0)? */
2706 if (priority == 0) {
2707 /* remove this extension from context list */
2709 prev_exten->next = exten->next;
2711 con->root = exten->next;
2713 /* fire out all peers */
2718 if (!peer->priority==PRIORITY_HINT)
2719 ast_remove_hint(peer);
2721 peer->datad(peer->data);
2727 ast_mutex_unlock(&con->lock);
2730 /* remove only extension with exten->priority == priority */
2731 struct ast_exten *previous_peer = NULL;
2735 /* is this our extension? */
2736 if (peer->priority == priority &&
2737 (!registrar || !strcmp(peer->registrar, registrar) )) {
2738 /* we are first priority extension? */
2739 if (!previous_peer) {
2740 /* exists previous extension here? */
2742 /* yes, so we must change next pointer in
2743 * previous connection to next peer
2746 prev_exten->next = peer->peer;
2747 peer->peer->next = exten->next;
2749 prev_exten->next = exten->next;
2751 /* no previous extension, we are first
2752 * extension, so change con->root ...
2755 con->root = peer->peer;
2757 con->root = exten->next;
2760 /* we are not first priority in extension */
2761 previous_peer->peer = peer->peer;
2764 /* now, free whole priority extension */
2765 if (peer->priority==PRIORITY_HINT)
2766 ast_remove_hint(peer);
2767 peer->datad(peer->data);
2770 ast_mutex_unlock(&con->lock);
2773 /* this is not right extension, skip to next peer */
2774 previous_peer = peer;
2779 ast_mutex_unlock(&con->lock);
2785 exten = exten->next;
2788 /* we can't find right extension */
2789 ast_mutex_unlock(&con->lock);
2794 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2796 struct ast_app *tmp, *prev, *cur;
2799 length = sizeof(struct ast_app);
2800 length += strlen(app) + 1;
2801 if (ast_mutex_lock(&applock)) {
2802 ast_log(LOG_ERROR, "Unable to lock application list\n");
2807 if (!strcasecmp(app, tmp->name)) {
2808 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2809 ast_mutex_unlock(&applock);
2814 tmp = malloc(length);
2816 memset(tmp, 0, length);
2817 strcpy(tmp->name, app);
2818 tmp->execute = execute;
2819 tmp->synopsis = synopsis;
2820 tmp->description = description;
2821 /* Store in alphabetical order */
2825 if (strcasecmp(tmp->name, cur->name) < 0)
2831 tmp->next = prev->next;
2838 ast_log(LOG_ERROR, "Out of memory\n");
2839 ast_mutex_unlock(&applock);
2842 if (option_verbose > 1)
2843 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2844 ast_mutex_unlock(&applock);
2848 int ast_register_switch(struct ast_switch *sw)
2850 struct ast_switch *tmp, *prev=NULL;
2851 if (ast_mutex_lock(&switchlock)) {
2852 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2857 if (!strcasecmp(tmp->name, sw->name))
2863 ast_mutex_unlock(&switchlock);
2864 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2872 ast_mutex_unlock(&switchlock);
2876 void ast_unregister_switch(struct ast_switch *sw)
2878 struct ast_switch *tmp, *prev=NULL;
2879 if (ast_mutex_lock(&switchlock)) {
2880 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2887 prev->next = tmp->next;
2889 switches = tmp->next;
2896 ast_mutex_unlock(&switchlock);
2900 * Help for CLI commands ...
2902 static char show_application_help[] =
2903 "Usage: show application <application> [<application> [<application> [...]]]\n"
2904 " Describes a particular application.\n";
2906 static char show_functions_help[] =
2907 "Usage: show functions\n"
2908 " List builtin functions accessable as $(function args)";
2910 static char show_applications_help[] =
2911 "Usage: show applications [{like|describing} <text>]\n"
2912 " List applications which are currently available.\n"
2913 " If 'like', <text> will be a substring of the app name\n"
2914 " If 'describing', <text> will be a substring of the description\n";
2916 static char show_dialplan_help[] =
2917 "Usage: show dialplan [exten@][context]\n"
2920 static char show_switches_help[] =
2921 "Usage: show switches\n"
2922 " Show registered switches\n";
2924 static char show_hints_help[] =
2925 "Usage: show hints\n"
2926 " Show registered hints\n";
2930 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2935 * 'show application' CLI command implementation functions ...
2939 * There is a possibility to show informations about more than one
2940 * application at one time. You can type 'show application Dial Echo' and
2941 * you will see informations about these two applications ...
2943 static char *complete_show_application(char *line, char *word,
2949 /* try to lock applications list ... */
2950 if (ast_mutex_lock(&applock)) {
2951 ast_log(LOG_ERROR, "Unable to lock application list\n");
2955 /* ... walk all applications ... */
2958 /* ... check if word matches this application ... */
2959 if (!strncasecmp(word, a->name, strlen(word))) {
2960 /* ... if this is right app serve it ... */
2961 if (++which > state) {
2962 char *ret = strdup(a->name);
2963 ast_mutex_unlock(&applock);
2970 /* no application match */
2971 ast_mutex_unlock(&applock);
2975 static int handle_show_application(int fd, int argc, char *argv[])
2978 int app, no_registered_app = 1;
2980 if (argc < 3) return RESULT_SHOWUSAGE;
2982 /* try to lock applications list ... */
2983 if (ast_mutex_lock(&applock)) {
2984 ast_log(LOG_ERROR, "Unable to lock application list\n");
2988 /* ... go through all applications ... */
2991 /* ... compare this application name with all arguments given
2992 * to 'show application' command ... */
2993 for (app = 2; app < argc; app++) {
2994 if (!strcasecmp(a->name, argv[app])) {
2995 /* Maximum number of characters added by terminal coloring is 22 */
2996 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2997 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2998 int synopsis_size, description_size;
3000 no_registered_app = 0;
3003 synopsis_size = strlen(a->synopsis) + 23;
3005 synopsis_size = strlen("Not available") + 23;
3006 synopsis = alloca(synopsis_size);
3009 description_size = strlen(a->description) + 23;
3011 description_size = strlen("Not available") + 23;
3012 description = alloca(description_size);
3014 if (synopsis && description) {
3015 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
3016 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
3017 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
3018 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
3019 term_color(synopsis,
3020 a->synopsis ? a->synopsis : "Not available",
3021 COLOR_CYAN, 0, synopsis_size);
3022 term_color(description,
3023 a->description ? a->description : "Not available",
3024 COLOR_CYAN, 0, description_size);
3026 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
3028 /* ... one of our applications, show info ...*/
3029 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
3030 "[Synopsis]:\n %s\n\n"
3031 "[Description]:\n%s\n",
3033 a->synopsis ? a->synopsis : "Not available",
3034 a->description ? a->description : "Not available");
3041 ast_mutex_unlock(&applock);
3043 /* we found at least one app? no? */
3044 if (no_registered_app) {
3045 ast_cli(fd, "Your application(s) is (are) not registered\n");
3046 return RESULT_FAILURE;
3049 return RESULT_SUCCESS;
3052 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
3053 static int handle_show_hints(int fd, int argc, char *argv[])
3055 struct ast_hint *hint;
3059 ast_cli(fd, "There are no registered dialplan hints\n");
3060 return RESULT_SUCCESS;
3062 /* ... we have hints ... */
3063 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
3064 if (ast_mutex_lock(&hintlock)) {
3065 ast_log(LOG_ERROR, "Unable to lock hints\n");
3070 ast_cli(fd, " %-20.20s: %-20.20s State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
3074 ast_cli(fd, "----------------\n");
3075 ast_cli(fd, "- %d hints registred\n", num);
3076 ast_mutex_unlock(&hintlock);
3077 return RESULT_SUCCESS;
3080 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
3081 static int handle_show_switches(int fd, int argc, char *argv[])
3083 struct ast_switch *sw;
3085 ast_cli(fd, "There are no registered alternative switches\n");
3086 return RESULT_SUCCESS;
3088 /* ... we have applications ... */
3089 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
3090 if (ast_mutex_lock(&switchlock)) {
3091 ast_log(LOG_ERROR, "Unable to lock switches\n");
3096 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3099 ast_mutex_unlock(&switchlock);
3100 return RESULT_SUCCESS;
3104 * 'show applications' CLI command implementation functions ...
3106 static int handle_show_applications(int fd, int argc, char *argv[])
3109 int like=0, describing=0;
3110 int total_match = 0; /* Number of matches in like clause */
3111 int total_apps = 0; /* Number of apps registered */
3113 /* try to lock applications list ... */
3114 if (ast_mutex_lock(&applock)) {
3115 ast_log(LOG_ERROR, "Unable to lock application list\n");
3119 /* ... have we got at least one application (first)? no? */
3121 ast_cli(fd, "There are no registered applications\n");
3122 ast_mutex_unlock(&applock);
3126 /* show applications like <keyword> */
3127 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3129 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3133 /* show applications describing <keyword1> [<keyword2>] [...] */
3134 if ((!like) && (!describing)) {
3135 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3137 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3140 /* ... go through all applications ... */
3141 for (a = apps; a; a = a->next) {
3142 /* ... show informations about applications ... */
3146 if (ast_strcasestr(a->name, argv[3])) {
3150 } else if (describing) {
3151 if (a->description) {
3152 /* Match all words on command line */
3155 for (i=3;i<argc;i++) {
3156 if (! ast_strcasestr(a->description, argv[i])) {
3168 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3171 if ((!like) && (!describing)) {
3172 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3174 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3177 /* ... unlock and return */
3178 ast_mutex_unlock(&applock);
3180 return RESULT_SUCCESS;
3183 static char *complete_show_applications(char *line, char *word, int pos, int state)
3186 if (ast_strlen_zero(word)) {
3189 return strdup("like");
3191 return strdup("describing");
3195 } else if (! strncasecmp(word, "like", strlen(word))) {
3197 return strdup("like");
3201 } else if (! strncasecmp(word, "describing", strlen(word))) {
3203 return strdup("describing");
3213 * 'show dialplan' CLI command implementation functions ...
3215 static char *complete_show_dialplan_context(char *line, char *word, int pos,
3218 struct ast_context *c;
3221 /* we are do completion of [exten@]context on second position only */
3222 if (pos != 2) return NULL;
3224 /* try to lock contexts list ... */
3225 if (ast_lock_contexts()) {
3226 ast_log(LOG_ERROR, "Unable to lock context list\n");
3230 /* ... walk through all contexts ... */
3231 c = ast_walk_contexts(NULL);
3233 /* ... word matches context name? yes? ... */
3234 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
3235 /* ... for serve? ... */
3236 if (++which > state) {
3237 /* ... yes, serve this context name ... */
3238 char *ret = strdup(ast_get_context_name(c));
3239 ast_unlock_contexts();
3243 c = ast_walk_contexts(c);
3246 /* ... unlock and return */
3247 ast_unlock_contexts();
3251 struct dialplan_counters {
3255 int context_existence;
3256 int extension_existence;
3259 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
3261 struct ast_context *c;
3262 int res=0, old_total_exten = dpc->total_exten;
3264 /* try to lock contexts */
3265 if (ast_lock_contexts()) {
3266 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3270 /* walk all contexts ... */
3271 for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
3272 /* show this context? */
3274 !strcmp(ast_get_context_name(c), context)) {
3275 dpc->context_existence = 1;
3277 /* try to lock context before walking in ... */
3278 if (!ast_lock_context(c)) {
3279 struct ast_exten *e;
3280 struct ast_include *i;
3281 struct ast_ignorepat *ip;
3283 char buf[256], buf2[256];
3284 int context_info_printed = 0;
3286 /* are we looking for exten too? if yes, we print context
3287 * if we our extension only
3290 dpc->total_context++;
3291 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3292 ast_get_context_name(c), ast_get_context_registrar(c));
3293 context_info_printed = 1;
3296 /* walk extensions ... */
3297 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3298 struct ast_exten *p;
3301 /* looking for extension? is this our extension? */
3303 !ast_extension_match(ast_get_extension_name(e), exten))
3305 /* we are looking for extension and it's not our
3306 * extension, so skip to next extension */
3310 dpc->extension_existence = 1;
3312 /* may we print context info? */
3313 if (!context_info_printed) {
3314 dpc->total_context++;
3316 /* TODO Print more info about rinclude */
3317 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3318 ast_get_context_name(c),
3319 ast_get_context_registrar(c));
3321 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3322 ast_get_context_name(c),
3323 ast_get_context_registrar(c));
3325 context_info_printed = 1;
3329 /* write extension name and first peer */
3330 bzero(buf, sizeof(buf));
3331 snprintf(buf, sizeof(buf), "'%s' =>",
3332 ast_get_extension_name(e));
3334 prio = ast_get_extension_priority(e);
3335 if (prio == PRIORITY_HINT) {
3336 snprintf(buf2, sizeof(buf2),
3338 ast_get_extension_app(e));
3340 snprintf(buf2, sizeof(buf2),
3343 ast_get_extension_app(e),
3344 (char *)ast_get_extension_app_data(e));
3347 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3348 ast_get_extension_registrar(e));
3351 /* walk next extension peers */
3352 for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3354 bzero((void *)buf2, sizeof(buf2));
3355 bzero((void *)buf, sizeof(buf));
3356 if (ast_get_extension_label(p))
3357 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
3358 prio = ast_get_extension_priority(p);
3359 if (prio == PRIORITY_HINT) {
3360 snprintf(buf2, sizeof(buf2),
3362 ast_get_extension_app(p));
3364 snprintf(buf2, sizeof(buf2),
3367 ast_get_extension_app(p),
3368 (char *)ast_get_extension_app_data(p));
3371 ast_cli(fd," %-17s %-45s [%s]\n",
3373 ast_get_extension_registrar(p));
3377 /* walk included and write info ... */
3378 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3379 bzero(buf, sizeof(buf));
3380 snprintf(buf, sizeof(buf), "'%s'",
3381 ast_get_include_name(i));
3383 /* Check all includes for the requested extension */
3384 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
3386 ast_cli(fd, " Include => %-45s [%s]\n",
3387 buf, ast_get_include_registrar(i));
3391 /* walk ignore patterns and write info ... */
3392 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
3393 const char *ipname = ast_get_ignorepat_name(ip);
3394 char ignorepat[AST_MAX_EXTENSION];
3395 snprintf(buf, sizeof(buf), "'%s'", ipname);
3396 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3397 if ((!exten) || ast_extension_match(ignorepat, exten)) {
3398 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3399 buf, ast_get_ignorepat_registrar(ip));
3403 for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
3404 snprintf(buf, sizeof(buf), "'%s/%s'",
3405 ast_get_switch_name(sw),