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 <asterisk/lock.h>
15 #include <asterisk/cli.h>
16 #include <asterisk/pbx.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/options.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/file.h>
21 #include <asterisk/callerid.h>
22 #include <asterisk/cdr.h>
23 #include <asterisk/config.h>
24 #include <asterisk/term.h>
25 #include <asterisk/manager.h>
26 #include <asterisk/ast_expr.h>
27 #include <asterisk/channel_pvt.h>
28 #include <asterisk/linkedlists.h>
29 #include <asterisk/say.h>
30 #include <asterisk/utils.h>
31 #include <asterisk/causes.h>
46 * The speed of extension handling will likely be among the most important
47 * aspects of this PBX. The switching scheme as it exists right now isn't
48 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
49 * of priorities, but a constant search time here would be great ;-)
54 #define EXT_DATA_SIZE 256
56 #define EXT_DATA_SIZE 8192
59 #define SWITCH_DATA_LENGTH 256
63 #define VAR_SOFTTRAN 2
64 #define VAR_HARDTRAN 3
68 /* ast_exten: An extension */
70 char *exten; /* Extension name */
71 int matchcid; /* Match caller id ? */
72 char *cidmatch; /* Caller id to match for this extension */
73 int priority; /* Priority */
74 char *label; /* Label */
75 struct ast_context *parent; /* The context this extension belongs to */
76 char *app; /* Application to execute */
77 void *data; /* Data to use (arguments) */
78 void (*datad)(void *); /* Data destructor */
79 struct ast_exten *peer; /* Next higher priority with our extension */
80 const char *registrar; /* Registrar */
81 struct ast_exten *next; /* Extension with a greater ID */
85 /* ast_include: include= support in extensions.conf */
88 char *rname; /* Context to include */
89 const char *registrar; /* Registrar */
90 int hastime; /* If time construct exists */
91 struct ast_timing timing; /* time construct */
92 struct ast_include *next; /* Link them together */
96 /* ast_sw: Switch statement in extensions.conf */
99 const char *registrar; /* Registrar */
100 char *data; /* Data load */
102 struct ast_sw *next; /* Link them together */
107 struct ast_ignorepat {
108 const char *registrar;
109 struct ast_ignorepat *next;
113 /* ast_context: An extension context */
115 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
116 struct ast_exten *root; /* The root of the list of extensions */
117 struct ast_context *next; /* Link them together */
118 struct ast_include *includes; /* Include other contexts */
119 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
120 const char *registrar; /* Registrar */
121 struct ast_sw *alts; /* Alternative switches */
122 char name[0]; /* Name of the context */
126 /* ast_app: An application */
128 int (*execute)(struct ast_channel *chan, void *data);
129 const char *synopsis; /* Synopsis text for 'show applications' */
130 const char *description; /* Description (help text) for 'show application <name>' */
131 struct ast_app *next; /* Next app in list */
132 char name[0]; /* Name of the application */
135 /* ast_state_cb: An extension state notify */
136 struct ast_state_cb {
139 ast_state_cb_type callback;
140 struct ast_state_cb *next;
143 /* ast_state_cb: An extension state notify */
144 struct ast_devstate_cb {
146 ast_devstate_cb_type callback;
147 struct ast_devstate_cb *next;
150 static struct ast_devstate_cb *devcbs;
153 struct ast_exten *exten;
155 struct ast_state_cb *callbacks;
156 struct ast_hint *next;
159 int ast_pbx_outgoing_cdr_failed(void);
161 static int pbx_builtin_prefix(struct ast_channel *, void *);
162 static int pbx_builtin_suffix(struct ast_channel *, void *);
163 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
164 static int pbx_builtin_answer(struct ast_channel *, void *);
165 static int pbx_builtin_goto(struct ast_channel *, void *);
166 static int pbx_builtin_hangup(struct ast_channel *, void *);
167 static int pbx_builtin_background(struct ast_channel *, void *);
168 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
169 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
170 static int pbx_builtin_atimeout(struct ast_channel *, void *);
171 static int pbx_builtin_wait(struct ast_channel *, void *);
172 static int pbx_builtin_waitexten(struct ast_channel *, void *);
173 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
174 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
175 static int pbx_builtin_setaccount(struct ast_channel *, void *);
176 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
177 static int pbx_builtin_ringing(struct ast_channel *, void *);
178 static int pbx_builtin_progress(struct ast_channel *, void *);
179 static int pbx_builtin_congestion(struct ast_channel *, void *);
180 static int pbx_builtin_busy(struct ast_channel *, void *);
181 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
182 static int pbx_builtin_noop(struct ast_channel *, void *);
183 static int pbx_builtin_gotoif(struct ast_channel *, void *);
184 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
185 static int pbx_builtin_execiftime(struct ast_channel *, void *);
186 static int pbx_builtin_saynumber(struct ast_channel *, void *);
187 static int pbx_builtin_saydigits(struct ast_channel *, void *);
188 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
189 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
190 int pbx_builtin_setvar(struct ast_channel *, void *);
191 static int pbx_builtin_importvar(struct ast_channel *, void *);
192 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
193 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
195 static struct varshead globals;
197 static int autofallthrough = 0;
199 static struct pbx_builtin {
200 char name[AST_MAX_APP];
201 int (*execute)(struct ast_channel *chan, void *data);
206 /* These applications are built into the PBX core and do not
207 need separate modules
211 { "AbsoluteTimeout", pbx_builtin_atimeout,
212 "Set absolute maximum time of call",
213 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
214 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
217 { "Answer", pbx_builtin_answer,
218 "Answer a channel if ringing",
219 " Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
220 "If delay is specified, asterisk will pause execution for the specified amount\n"
221 "of milliseconds if an answer is required, in order to give audio a chance to\n"
222 "become ready. Returns 0 unless it tries to answer the channel and fails.\n"
225 { "BackGround", pbx_builtin_background,
226 "Play a file while awaiting extension",
227 " Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
228 "given files, while simultaneously waiting for the user to begin typing\n"
229 "an extension. The timeouts do not count until the last BackGround\n"
230 "application has ended. Options may also be included following a pipe \n"
231 "symbol. The 'skip' option causes the playback of the message to be \n"
232 "skipped if the channel is not in the 'up' state (i.e. it hasn't been\n"
233 "answered yet. If 'skip' is specified, the application will return\n"
234 "immediately should the channel not be off hook. Otherwise, unless \n"
235 "'noanswer' is specified, the channel channel will be answered before the\n"
236 "sound is played. Not all channels support playing messages while still\n"
237 "hook. The 'langoverride' may be a language to use for playing the prompt\n"
238 "which differs from the current language of the channel. Returns -1 if \n"
239 "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n"
242 { "Busy", pbx_builtin_busy,
243 "Indicate busy condition and stop",
244 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
245 "then waits for the user to hang up or the optional timeout to expire.\n"
249 { "Congestion", pbx_builtin_congestion,
250 "Indicate congestion and stop",
251 " Congestion([timeout]): Requests that the channel indicate congestion\n"
252 "and then waits for the user to hang up or for the optional timeout to\n"
253 "expire. Always returns -1."
256 { "DigitTimeout", pbx_builtin_dtimeout,
257 "Set maximum timeout between digits",
258 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
259 "digits when the user is typing in an extension. When this timeout expires,\n"
260 "after the user has started to type in an extension, the extension will be\n"
261 "considered complete, and will be interpreted. Note that if an extension\n"
262 "typed in is valid, it will not have to timeout to be tested, so typically\n"
263 "at the expiry of this timeout, the extension will be considered invalid\n"
264 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
265 "exist the call would be terminated). Always returns 0.\n"
268 { "Goto", pbx_builtin_goto,
269 "Goto a particular priority, extension, or context",
270 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
271 "value, optionally setting the extension and optionally the context as well.\n"
272 "The extension BYEXTENSION is special in that it uses the current extension,\n"
273 "thus permitting you to go to a different context, without specifying a\n"
274 "specific extension. Always returns 0, even if the given context, extension,\n"
275 "or priority is invalid.\n"
278 { "GotoIf", pbx_builtin_gotoif,
280 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
281 "true, to label2 if condition is false. Either label1 or label2 may be\n"
282 "omitted (in that case, we just don't take the particular branch) but not\n"
283 "both. Look for the condition syntax in examples or documentation."
286 { "GotoIfTime", pbx_builtin_gotoiftime,
287 "Conditional goto on current time",
288 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
289 "If the current time matches the specified time, then branch to the specified\n"
290 "extension. Each of the elements may be specified either as '*' (for always)\n"
291 "or as a range. See the 'include' syntax for details."
294 { "ExecIfTime", pbx_builtin_execiftime,
295 "Conditional application execution on current time",
296 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?<appname>[|<appdata>]):\n"
297 "If the current time matches the specified time, then execute the specified\n"
298 "application. Each of the elements may be specified either as '*' (for always)\n"
299 "or as a range. See the 'include' syntax for details."
302 { "Hangup", pbx_builtin_hangup,
303 "Unconditional hangup",
304 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
307 { "NoOp", pbx_builtin_noop,
309 " NoOp(): No-operation; Does nothing."
312 { "Prefix", pbx_builtin_prefix,
313 "Prepend leading digits",
314 " Prefix(digits): Prepends the digit string specified by digits to the\n"
315 "channel's associated extension. For example, the number 1212 when prefixed\n"
316 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
317 "continue processing at the next priority for the *new* extension.\n"
318 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
319 "executed will be priority 4 of 5551212. If you switch into an extension\n"
320 "which has no first step, the PBX will treat it as though the user dialed an\n"
321 "invalid extension.\n"
324 { "Progress", pbx_builtin_progress,
326 " Progress(): Request that the channel indicate in-band progress is \n"
327 "available to the user.\nAlways returns 0.\n"
330 { "ResetCDR", pbx_builtin_resetcdr,
331 "Resets the Call Data Record",
332 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
333 "storing the current CDR before zeroing it out\b"
334 "(if 'w' option is specifed) record will be stored.\n"
335 "(if 'a' option is specifed) any stacked records will be stored.\n"
336 "(if 'v' option is specifed) any variables will be saved.\n"
337 "Always returns 0.\n"
340 { "ResponseTimeout", pbx_builtin_rtimeout,
341 "Set maximum timeout awaiting response",
342 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
343 "falling through a series of priorities for a channel in which the user may\n"
344 "begin typing an extension. If the user does not type an extension in this\n"
345 "amount of time, control will pass to the 't' extension if it exists, and\n"
346 "if not the call would be terminated.\nAlways returns 0.\n"
349 { "Ringing", pbx_builtin_ringing,
350 "Indicate ringing tone",
351 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
352 "Always returns 0.\n"
355 { "SayNumber", pbx_builtin_saynumber,
357 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
358 "the current language setting for the channel. (See app SetLanguage).\n"
361 { "SayDigits", pbx_builtin_saydigits,
363 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
364 "current language setting for the channel. (See app setLanguage)\n"
367 { "SayAlpha", pbx_builtin_saycharacters,
369 " SayAlpha(string): Spells the passed string\n"
372 { "SayPhonetic", pbx_builtin_sayphonetic,
374 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
377 { "SetAccount", pbx_builtin_setaccount,
379 " SetAccount([account]): Set the channel account code for billing\n"
380 "purposes. Always returns 0.\n"
383 { "SetAMAFlags", pbx_builtin_setamaflags,
385 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
386 "purposes. Always returns 0.\n"
389 { "SetGlobalVar", pbx_builtin_setglobalvar,
390 "Set global variable to value",
391 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
392 "variable are available across channels.\n"
395 { "SetLanguage", pbx_builtin_setlanguage,
396 "Sets user language",
397 " SetLanguage(language): Set the channel language to 'language'. This\n"
398 "information is used for the syntax in generation of numbers, and to choose\n"
399 "a natural language file when available.\n"
400 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
401 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
402 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
403 "Always returns 0.\n"
406 { "SetVar", pbx_builtin_setvar,
407 "Set variable to value",
408 " SetVar(#n1=value|#n2=value|..[|options]) Set a variables to a CDR.\n"
409 "You can specify an endless list of name / value pairs to be set as channel variables.\n"
410 "The last arg (if it doesn't contain an '=' ) is intrepreted as a string of\n"
411 "options. Valid Options:\n"
412 " - c - CDR, if set set the var as a CDR variable also.\n"
413 " - r - Recursive CDR, if there are any stacked CDRs, also apply to all as a cdr var.\n"
414 " - g - Set a global variable not a channel variable.\n"
415 " #n=value: Sets variable n to value. If prefixed with _, single\n"
416 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
418 { "ImportVar", pbx_builtin_importvar,
419 "Set variable to value",
420 " ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on\n"
421 "the specified channel (instead of current). If prefixed with _, single\n"
422 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
424 { "StripMSD", pbx_builtin_stripmsd,
425 "Strip leading digits",
426 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
427 "associated extension. For example, the number 5551212 when stripped with a\n"
428 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
429 "will continue processing at the next priority for the *new* extension.\n"
430 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
431 "executed will be priority 4 of 1212. If you switch into an extension which\n"
432 "has no first step, the PBX will treat it as though the user dialed an\n"
433 "invalid extension.\n"
436 { "Suffix", pbx_builtin_suffix,
437 "Append trailing digits",
438 " Suffix(digits): Appends the digit string specified by digits to the\n"
439 "channel's associated extension. For example, the number 555 when suffixed\n"
440 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
441 "continue processing at the next priority for the *new* extension.\n"
442 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
443 "executed will be priority 4 of 5551212. If you switch into an extension\n"
444 "which has no first step, the PBX will treat it as though the user dialed an\n"
445 "invalid extension.\n"
448 { "Wait", pbx_builtin_wait,
449 "Waits for some time",
450 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
451 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
454 { "WaitExten", pbx_builtin_waitexten,
455 "Waits for an extension to be entered",
456 " WaitExten([seconds]): Waits for the user to enter a new extension for the \n"
457 "specified number of seconds, then returns 0. Seconds can be passed with\n"
458 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
459 "default extension timeout will be used.\n"
464 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
465 static struct ast_context *contexts = NULL;
466 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
467 static struct ast_app *apps = NULL;
469 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
470 struct ast_switch *switches = NULL;
472 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
473 static int stateid = 1;
474 struct ast_hint *hints = NULL;
475 struct ast_state_cb *statecbs = NULL;
477 int pbx_exec(struct ast_channel *c, /* Channel */
478 struct ast_app *app, /* Application */
479 void *data, /* Data for execution */
480 int newstack) /* Force stack increment */
482 /* This function is special. It saves the stack so that no matter
483 how many times it is called, it returns to the same place */
489 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
493 ast_cdr_setapp(c->cdr, app->name, data);
495 /* save channel values */
496 saved_c_appl= c->appl;
497 saved_c_data= c->data;
501 res = execute(c, data);
502 /* restore channel values */
503 c->appl= saved_c_appl;
504 c->data= saved_c_data;
507 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
512 /* Go no deeper than this through includes (not counting loops) */
513 #define AST_PBX_MAX_STACK 128
515 #define HELPER_EXISTS 0
516 #define HELPER_SPAWN 1
517 #define HELPER_EXEC 2
518 #define HELPER_CANMATCH 3
519 #define HELPER_MATCHMORE 4
520 #define HELPER_FINDLABEL 5
522 struct ast_app *pbx_findapp(const char *app)
526 if (ast_mutex_lock(&applock)) {
527 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
532 if (!strcasecmp(tmp->name, app))
536 ast_mutex_unlock(&applock);
540 static struct ast_switch *pbx_findswitch(const char *sw)
542 struct ast_switch *asw;
544 if (ast_mutex_lock(&switchlock)) {
545 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
550 if (!strcasecmp(asw->name, sw))
554 ast_mutex_unlock(&switchlock);
558 static inline int include_valid(struct ast_include *i)
563 return ast_check_timing(&(i->timing));
566 static void pbx_destroy(struct ast_pbx *p)
571 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
572 /* All patterns begin with _ */\
573 if (pattern[0] != '_') \
575 /* Start optimistic */\
578 while(match && *data && *pattern && (*pattern != '/')) {\
579 while (*data == '-' && (*(data+1) != '\0')) data++;\
580 switch(toupper(*pattern)) {\
587 where=strchr(pattern,']');\
589 border=(int)(where-pattern);\
590 if (!where || border > strlen(pattern)) {\
591 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
594 for (i=0; i<border; i++) {\
597 if (pattern[i+1]=='-') {\
598 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
605 if (res==1 || *data==pattern[i]) {\
614 if ((*data < '2') || (*data > '9'))\
618 if ((*data < '0') || (*data > '9'))\
622 if ((*data < '1') || (*data > '9'))\
630 /* Ignore these characters */\
634 if (*data != *pattern)\
642 int ast_extension_match(const char *pattern, const char *data)
645 /* If they're the same return */
646 if (!strcmp(pattern, data))
648 EXTENSION_MATCH_CORE(data,pattern,match);
649 /* Must be at the end of both */
650 if (*data || (*pattern && (*pattern != '/')))
655 int ast_extension_close(const char *pattern, const char *data, int needmore)
658 /* If "data" is longer, it can'be a subset of pattern unless
659 pattern is a pattern match */
660 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
663 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
664 (!needmore || (strlen(pattern) > strlen(data)))) {
667 EXTENSION_MATCH_CORE(data,pattern,match);
668 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
669 if (!needmore || *pattern) {
675 struct ast_context *ast_context_find(const char *name)
677 struct ast_context *tmp;
678 ast_mutex_lock(&conlock);
682 if (!strcasecmp(name, tmp->name))
688 ast_mutex_unlock(&conlock);
692 #define STATUS_NO_CONTEXT 1
693 #define STATUS_NO_EXTENSION 2
694 #define STATUS_NO_PRIORITY 3
695 #define STATUS_NO_LABEL 4
696 #define STATUS_SUCCESS 5
698 static int matchcid(const char *cidpattern, const char *callerid)
702 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
703 failing to get a number should count as a match, otherwise not */
706 if (!ast_strlen_zero(cidpattern))
714 return ast_extension_match(cidpattern, callerid);
717 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)
720 struct ast_context *tmp;
721 struct ast_exten *e, *eroot;
722 struct ast_include *i;
724 struct ast_switch *asw;
726 /* Initialize status if appropriate */
728 *status = STATUS_NO_CONTEXT;
732 /* Check for stack overflow */
733 if (*stacklen >= AST_PBX_MAX_STACK) {
734 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
737 /* Check first to see if we've already been checked */
738 for (x=0;x<*stacklen;x++) {
739 if (!strcasecmp(incstack[x], context))
748 if (bypass || !strcmp(tmp->name, context)) {
749 if (*status < STATUS_NO_EXTENSION)
750 *status = STATUS_NO_EXTENSION;
753 /* Match extension */
754 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
755 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
756 ((action == HELPER_MATCHMORE) && (ast_extension_close(eroot->exten, exten, 1)))) &&
757 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
759 if (*status < STATUS_NO_PRIORITY)
760 *status = STATUS_NO_PRIORITY;
763 if (action == HELPER_FINDLABEL) {
764 if (*status < STATUS_NO_LABEL)
765 *status = STATUS_NO_LABEL;
766 if (label && e->label && !strcmp(label, e->label)) {
767 *status = STATUS_SUCCESS;
768 *foundcontext = context;
771 } else if (e->priority == priority) {
772 *status = STATUS_SUCCESS;
773 *foundcontext = context;
781 /* Check alternative switches */
784 if ((asw = pbx_findswitch(sw->name))) {
785 /* Substitute variables now */
787 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
788 if (action == HELPER_CANMATCH)
789 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
790 else if (action == HELPER_MATCHMORE)
791 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
793 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
797 *data = sw->eval ? sw->tmpdata : sw->data;
798 *foundcontext = context;
802 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
806 /* Setup the stack */
807 incstack[*stacklen] = tmp->name;
809 /* Now try any includes we have in this context */
812 if (include_valid(i)) {
813 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
827 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
828 functions in the dialplan
830 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
833 char tmpvar[80] = "";
835 struct tm brokentime;
837 struct ast_var_t *variables;
842 if (c && c->cdr && !strncasecmp(var, "CDR(", 4)) { /* ${CDR(NEET)} */
845 if ((vtmp = ast_strdupa((char *) var + 4)) && (nt = strchr(vtmp, ')'))) {
847 ast_cdr_getvar(c->cdr, vtmp, ret, workspace, workspacelen, 1);
849 ast_log(LOG_WARNING, "Invalid CDR variable.\n");
851 } else if (!strncasecmp(var,"LEN(",4)) { /* ${LEN(<string>)} */
852 /* Now we have the variable name on cp3 */
855 if (strrchr(var,')')) {
857 strncpy(cp3, var, sizeof(cp3) - 1);
858 cp3[len-len_len-1]='\0';
859 sprintf(workspace,"%d",(int)strlen(cp3));
865 } else if ((first=strchr(var,':'))) { /* : Remove characters counting from end or start of string */
866 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
867 first = strchr(tmpvar, ':');
869 first = tmpvar + strlen(tmpvar);
871 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
874 offset=atoi(first+1); /* The number of characters,
875 positive: remove # of chars from start
876 negative: keep # of chars from end */
878 if ((second=strchr(first+1,':'))) {
880 offset2 = atoi(second+1); /* Number of chars to copy */
881 } else if (offset >= 0) {
882 offset2 = strlen(*ret)-offset; /* Rest of string */
884 offset2 = abs(offset);
887 if (abs(offset) > strlen(*ret)) { /* Offset beyond string */
891 offset=-strlen(*ret);
893 if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
895 offset2=strlen(*ret)-offset;
897 offset2=strlen(*ret)+offset;
902 *ret += strlen(*ret)+offset;
903 (*ret)[offset2] = '\0'; /* Cut at offset2 position */
904 } else if (c && !strncmp(var, "CALL", 4)) {
905 if (!strncmp(var + 4, "ER", 2)) {
906 if (!strncmp(var + 6, "ID", 2)) {
907 if (!var[8]) { /* CALLERID */
908 if (c->cid.cid_num) {
909 if (c->cid.cid_name) {
910 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
912 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
915 } else if (c->cid.cid_name) {
916 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
920 } else if (!strcmp(var + 8, "NUM")) {
922 if (c->cid.cid_num) {
923 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
927 } else if (!strcmp(var + 8, "NAME")) {
929 if (c->cid.cid_name) {
930 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
935 } else if (!strcmp(var + 6, "ANI")) {
937 if (c->cid.cid_ani) {
938 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
944 } else if (!strncmp(var + 4, "ING", 3)) {
945 if (!strcmp(var + 7, "PRES")) {
947 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
949 } else if (!strcmp(var + 7, "ANI2")) {
951 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
953 } else if (!strcmp(var + 7, "TON")) {
955 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
957 } else if (!strcmp(var + 7, "TNS")) {
959 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
965 } else if (c && !strcmp(var, "DNID")) {
966 if (c->cid.cid_dnid) {
967 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
971 } else if (c && !strcmp(var, "HINT")) {
972 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
976 } else if (c && !strcmp(var, "HINTNAME")) {
977 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
981 } else if (c && !strcmp(var, "EXTEN")) {
982 strncpy(workspace, c->exten, workspacelen - 1);
984 } else if (c && !strcmp(var, "RDNIS")) {
985 if (c->cid.cid_rdnis) {
986 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
990 } else if (c && !strcmp(var, "CONTEXT")) {
991 strncpy(workspace, c->context, workspacelen - 1);
993 } else if (c && !strcmp(var, "PRIORITY")) {
994 snprintf(workspace, workspacelen, "%d", c->priority);
996 } else if (c && !strcmp(var, "CHANNEL")) {
997 strncpy(workspace, c->name, workspacelen - 1);
999 } else if (!strcmp(var, "EPOCH")) {
1000 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1002 } else if (!strcmp(var, "DATETIME")) {
1003 thistime=time(NULL);
1004 localtime_r(&thistime, &brokentime);
1005 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
1007 brokentime.tm_mon+1,
1008 brokentime.tm_year+1900,
1014 } else if (!strcmp(var, "TIMESTAMP")) {
1015 thistime=time(NULL);
1016 localtime_r(&thistime, &brokentime);
1017 /* 20031130-150612 */
1018 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
1019 brokentime.tm_year+1900,
1020 brokentime.tm_mon+1,
1027 } else if (c && !strcmp(var, "UNIQUEID")) {
1028 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1030 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1031 snprintf(workspace, workspacelen, "%i", c->hangupcause);
1033 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1034 strncpy(workspace, c->accountcode, workspacelen - 1);
1036 } else if (c && !strcmp(var, "LANGUAGE")) {
1037 strncpy(workspace, c->language, workspacelen - 1);
1042 AST_LIST_TRAVERSE(headp,variables,entries) {
1044 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1046 if (strcasecmp(ast_var_name(variables),var)==0) {
1047 *ret=ast_var_value(variables);
1049 strncpy(workspace, *ret, workspacelen - 1);
1058 AST_LIST_TRAVERSE(&globals,variables,entries) {
1060 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1062 if (strcasecmp(ast_var_name(variables),var)==0) {
1063 *ret=ast_var_value(variables);
1065 strncpy(workspace, *ret, workspacelen - 1);
1072 int len=strlen(var);
1073 int len_env=strlen("ENV(");
1074 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1076 strncpy(cp3, var, sizeof(cp3) - 1);
1078 *ret=getenv(cp3+len_env);
1080 strncpy(workspace, *ret, workspacelen - 1);
1088 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1091 const char *tmp, *whereweare;
1093 char workspace[4096];
1094 char ltmp[4096], var[4096];
1095 char *nextvar, *nextexp;
1097 int pos, brackets, needsub, len;
1099 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1102 while(!ast_strlen_zero(whereweare) && count) {
1103 /* Assume we're copying the whole remaining string */
1104 pos = strlen(whereweare);
1106 /* Look for a variable */
1107 nextvar = strstr(whereweare, "${");
1109 /* Look for an expression */
1110 nextexp = strstr(whereweare, "$[");
1112 /* Pick the first one only */
1113 if (nextvar && nextexp) {
1114 if (nextvar < nextexp)
1120 /* If there is one, we only go that far */
1122 pos = nextvar - whereweare;
1124 pos = nextexp - whereweare;
1126 /* Can't copy more than 'count' bytes */
1130 /* Copy that many bytes */
1131 memcpy(cp2, whereweare, pos);
1138 /* We have a variable. Find the start and end, and determine
1139 if we are going to have to recursively call ourselves on the
1141 vars = vare = nextvar + 2;
1145 /* Find the end of it */
1146 while(brackets && *vare) {
1147 if ((vare[0] == '$') && (vare[1] == '{')) {
1150 } else if (vare[0] == '}') {
1152 } else if ((vare[0] == '$') && (vare[1] == '['))
1157 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1158 len = vare - vars - 1;
1160 /* Skip totally over variable name */
1161 whereweare += ( len + 3);
1163 /* Store variable name (and truncate) */
1164 memset(var, 0, sizeof(var));
1165 strncpy(var, vars, sizeof(var) - 1);
1168 /* Substitute if necessary */
1170 memset(ltmp, 0, sizeof(ltmp));
1171 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1177 /* Retrieve variable value */
1178 workspace[0] = '\0';
1179 pbx_retrieve_variable(c,vars,&cp4, workspace, sizeof(workspace), headp);
1181 length = strlen(cp4);
1184 memcpy(cp2, cp4, length);
1189 } else if (nextexp) {
1190 /* We have an expression. Find the start and end, and determine
1191 if we are going to have to recursively call ourselves on the
1193 vars = vare = nextexp + 2;
1197 /* Find the end of it */
1198 while(brackets && *vare) {
1199 if ((vare[0] == '$') && (vare[1] == '[')) {
1203 } else if (vare[0] == '[') {
1205 } else if (vare[0] == ']') {
1207 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1214 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1215 len = vare - vars - 1;
1217 /* Skip totally over variable name */
1218 whereweare += ( len + 3);
1220 /* Store variable name (and truncate) */
1221 memset(var, 0, sizeof(var));
1222 strncpy(var, vars, sizeof(var) - 1);
1225 /* Substitute if necessary */
1227 memset(ltmp, 0, sizeof(ltmp));
1228 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1234 /* Evaluate expression */
1235 cp4 = ast_expr(vars);
1237 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1240 length = strlen(cp4);
1243 memcpy(cp2, cp4, length);
1254 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1256 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1259 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1261 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1264 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1266 memset(passdata, 0, datalen);
1268 /* No variables or expressions in e->data, so why scan it? */
1269 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1270 strncpy(passdata, e->data, datalen - 1);
1271 passdata[datalen-1] = '\0';
1275 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1278 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)
1280 struct ast_exten *e;
1281 struct ast_app *app;
1282 struct ast_switch *sw;
1284 const char *foundcontext=NULL;
1288 char *incstack[AST_PBX_MAX_STACK];
1289 char passdata[EXT_DATA_SIZE];
1293 char tmp3[EXT_DATA_SIZE];
1295 char atmp2[EXT_DATA_SIZE+100];
1297 if (ast_mutex_lock(&conlock)) {
1298 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1299 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1304 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1307 case HELPER_CANMATCH:
1308 ast_mutex_unlock(&conlock);
1311 ast_mutex_unlock(&conlock);
1313 case HELPER_FINDLABEL:
1315 ast_mutex_unlock(&conlock);
1317 case HELPER_MATCHMORE:
1318 ast_mutex_unlock(&conlock);
1324 app = pbx_findapp(e->app);
1325 ast_mutex_unlock(&conlock);
1327 if (c->context != context)
1328 strncpy(c->context, context, sizeof(c->context)-1);
1329 if (c->exten != exten)
1330 strncpy(c->exten, exten, sizeof(c->exten)-1);
1331 c->priority = priority;
1332 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1334 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1335 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1336 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"));
1337 pbx_builtin_setvar_helper(c, atmp, atmp2);
1339 if (option_verbose > 2)
1340 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1341 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1342 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1343 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1344 (newstack ? "in new stack" : "in same stack"));
1345 manager_event(EVENT_FLAG_CALL, "Newexten",
1350 "Application: %s\r\n"
1353 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1354 res = pbx_exec(c, app, passdata, newstack);
1357 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1361 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1365 case HELPER_CANMATCH:
1366 ast_mutex_unlock(&conlock);
1369 ast_mutex_unlock(&conlock);
1371 case HELPER_MATCHMORE:
1372 ast_mutex_unlock(&conlock);
1374 case HELPER_FINDLABEL:
1375 ast_mutex_unlock(&conlock);
1381 ast_mutex_unlock(&conlock);
1383 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1385 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1390 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1394 ast_mutex_unlock(&conlock);
1396 case STATUS_NO_CONTEXT:
1397 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1398 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1400 case STATUS_NO_EXTENSION:
1401 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1402 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1404 case STATUS_NO_PRIORITY:
1405 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1406 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1408 case STATUS_NO_LABEL:
1410 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1413 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1416 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1424 /*--- ast_hint_extension: Find hint for given extension in context */
1425 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1427 struct ast_exten *e;
1428 struct ast_switch *sw;
1430 const char *foundcontext = NULL;
1432 char *incstack[AST_PBX_MAX_STACK];
1435 if (ast_mutex_lock(&conlock)) {
1436 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1439 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1440 ast_mutex_unlock(&conlock);
1444 static int ast_extension_state2(struct ast_exten *e)
1446 char hint[AST_MAX_EXTENSION] = "";
1449 int allunavailable = 1, allbusy = 1, allfree = 1;
1452 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1456 rest = strchr(cur, '&');
1462 res = ast_device_state(cur);
1464 case AST_DEVICE_NOT_INUSE:
1468 case AST_DEVICE_INUSE:
1469 return AST_EXTENSION_INUSE;
1470 case AST_DEVICE_BUSY:
1475 case AST_DEVICE_UNAVAILABLE:
1476 case AST_DEVICE_INVALID:
1489 return AST_EXTENSION_NOT_INUSE;
1491 return AST_EXTENSION_BUSY;
1493 return AST_EXTENSION_UNAVAILABLE;
1495 return AST_EXTENSION_INUSE;
1497 return AST_EXTENSION_NOT_INUSE;
1501 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1503 struct ast_exten *e;
1505 e = ast_hint_extension(c, context, exten);
1509 return ast_extension_state2(e);
1512 int ast_device_state_changed(const char *fmt, ...)
1514 struct ast_hint *list;
1515 struct ast_state_cb *cblist;
1516 struct ast_devstate_cb *devcb;
1517 char hint[AST_MAX_EXTENSION] = "";
1518 char device[AST_MAX_EXTENSION];
1525 vsnprintf(device, sizeof(device), fmt, ap);
1528 rest = strchr(device, '-');
1533 state = ast_device_state(device);
1535 ast_mutex_lock(&hintlock);
1539 if (devcb->callback)
1540 devcb->callback(device, state, devcb->data);
1541 devcb = devcb->next;
1547 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1550 rest = strchr(cur, '&');
1556 if (!strcmp(cur, device)) {
1557 /* Found extension execute callbacks */
1558 state = ast_extension_state2(list->exten);
1559 if ((state != -1) && (state != list->laststate)) {
1560 /* For general callbacks */
1563 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1564 cblist = cblist->next;
1567 /* For extension callbacks */
1568 cblist = list->callbacks;
1570 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1571 cblist = cblist->next;
1574 list->laststate = state;
1582 ast_mutex_unlock(&hintlock);
1586 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1588 struct ast_devstate_cb *devcb;
1589 devcb = malloc(sizeof(struct ast_devstate_cb));
1591 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1592 ast_mutex_lock(&hintlock);
1594 devcb->callback = callback;
1595 devcb->next = devcbs;
1597 ast_mutex_unlock(&hintlock);
1602 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1604 struct ast_devstate_cb *devcb, *prev = NULL, *next;
1605 ast_mutex_lock(&hintlock);
1609 if ((devcb->data == data) && (devcb->callback == callback)) {
1619 ast_mutex_unlock(&hintlock);
1622 int ast_extension_state_add(const char *context, const char *exten,
1623 ast_state_cb_type callback, void *data)
1625 struct ast_hint *list;
1626 struct ast_state_cb *cblist;
1627 struct ast_exten *e;
1629 /* No context and extension add callback to statecbs list */
1630 if (!context && !exten) {
1631 ast_mutex_lock(&hintlock);
1635 if (cblist->callback == callback) {
1636 cblist->data = data;
1637 ast_mutex_unlock(&hintlock);
1639 cblist = cblist->next;
1642 /* Now inserts the callback */
1643 cblist = malloc(sizeof(struct ast_state_cb));
1645 ast_mutex_unlock(&hintlock);
1648 memset(cblist, 0, sizeof(struct ast_state_cb));
1650 cblist->callback = callback;
1651 cblist->data = data;
1653 cblist->next = statecbs;
1656 ast_mutex_unlock(&hintlock);
1660 if (!context || !exten)
1663 /* This callback type is for only one hint */
1664 e = ast_hint_extension(NULL, context, exten);
1669 ast_mutex_lock(&hintlock);
1673 if (list->exten == e)
1679 ast_mutex_unlock(&hintlock);
1683 /* Now inserts the callback */
1684 cblist = malloc(sizeof(struct ast_state_cb));
1686 ast_mutex_unlock(&hintlock);
1689 memset(cblist, 0, sizeof(struct ast_state_cb));
1690 cblist->id = stateid++;
1691 cblist->callback = callback;
1692 cblist->data = data;
1694 cblist->next = list->callbacks;
1695 list->callbacks = cblist;
1697 ast_mutex_unlock(&hintlock);
1701 int ast_extension_state_del(int id, ast_state_cb_type callback)
1703 struct ast_hint *list;
1704 struct ast_state_cb *cblist, *cbprev;
1706 if (!id && !callback)
1709 ast_mutex_lock(&hintlock);
1711 /* id is zero is a callback without extension */
1716 if (cblist->callback == callback) {
1718 statecbs = cblist->next;
1720 cbprev->next = cblist->next;
1724 ast_mutex_unlock(&hintlock);
1728 cblist = cblist->next;
1731 ast_mutex_lock(&hintlock);
1735 /* id greater than zero is a callback with extension */
1738 cblist = list->callbacks;
1741 if (cblist->id==id) {
1743 list->callbacks = cblist->next;
1745 cbprev->next = cblist->next;
1749 ast_mutex_unlock(&hintlock);
1753 cblist = cblist->next;
1758 ast_mutex_unlock(&hintlock);
1762 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
1763 static int ast_add_hint(struct ast_exten *e)
1765 struct ast_hint *list;
1770 ast_mutex_lock(&hintlock);
1773 /* Search if hint exists, do nothing */
1775 if (list->exten == e) {
1776 ast_mutex_unlock(&hintlock);
1777 if (option_debug > 1)
1778 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1784 if (option_debug > 1)
1785 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1787 list = malloc(sizeof(struct ast_hint));
1789 ast_mutex_unlock(&hintlock);
1790 if (option_debug > 1)
1791 ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
1794 /* Initialize and insert new item at the top */
1795 memset(list, 0, sizeof(struct ast_hint));
1797 list->laststate = ast_extension_state2(e);
1801 ast_mutex_unlock(&hintlock);
1805 /*--- ast_change_hint: Change hint for an extension */
1806 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1808 struct ast_hint *list;
1810 ast_mutex_lock(&hintlock);
1814 if (list->exten == oe) {
1816 ast_mutex_unlock(&hintlock);
1821 ast_mutex_unlock(&hintlock);
1826 /*--- ast_remove_hint: Remove hint from extension */
1827 static int ast_remove_hint(struct ast_exten *e)
1829 /* Cleanup the Notifys if hint is removed */
1830 struct ast_hint *list, *prev = NULL;
1831 struct ast_state_cb *cblist, *cbprev;
1836 ast_mutex_lock(&hintlock);
1840 if (list->exten==e) {
1842 cblist = list->callbacks;
1844 /* Notify with -1 and remove all callbacks */
1846 cblist = cblist->next;
1847 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1850 list->callbacks = NULL;
1855 prev->next = list->next;
1858 ast_mutex_unlock(&hintlock);
1866 ast_mutex_unlock(&hintlock);
1871 /*--- ast_get_hint: Get hint for channel */
1872 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
1874 struct ast_exten *e;
1876 e = ast_hint_extension(c, context, exten);
1879 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1881 tmp = ast_get_extension_app_data(e);
1883 strncpy(name, (char *)tmp, namesize - 1);
1890 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1892 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1895 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1897 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1900 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1902 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1905 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1907 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1910 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1912 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1915 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1917 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1920 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1922 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1925 int ast_pbx_run(struct ast_channel *c)
1934 /* A little initial setup here */
1936 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1937 c->pbx = malloc(sizeof(struct ast_pbx));
1939 ast_log(LOG_ERROR, "Out of memory\n");
1944 c->cdr = ast_cdr_alloc();
1946 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1950 ast_cdr_init(c->cdr, c);
1953 memset(c->pbx, 0, sizeof(struct ast_pbx));
1954 /* Set reasonable defaults */
1955 c->pbx->rtimeout = 10;
1956 c->pbx->dtimeout = 5;
1958 /* Start by trying whatever the channel is set to */
1959 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1960 /* JK02: If not successfull fall back to 's' */
1961 if (option_verbose > 1)
1962 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);
1963 strncpy(c->exten, "s", sizeof(c->exten)-1);
1964 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1965 /* JK02: And finally back to default if everything else failed */
1966 if (option_verbose > 1)
1967 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);
1968 strncpy(c->context, "default", sizeof(c->context)-1);
1972 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1973 ast_cdr_start(c->cdr);
1977 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1978 memset(exten, 0, sizeof(exten));
1979 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1980 /* Something bad happened, or a hangup has been requested. */
1981 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1982 (res == '*') || (res == '#')) {
1983 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1984 memset(exten, 0, sizeof(exten));
1986 exten[pos++] = digit = res;
1990 case AST_PBX_KEEPALIVE:
1992 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1993 else if (option_verbose > 1)
1994 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1999 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2000 else if (option_verbose > 1)
2001 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2002 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2007 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2017 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2018 strncpy(c->exten,"T",sizeof(c->exten) - 1);
2019 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2020 c->whentohangup = 0;
2022 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2023 } else if (c->_softhangup) {
2024 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2025 c->exten, c->priority);
2031 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2032 /* It's not a valid extension anymore */
2033 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2034 if (option_verbose > 2)
2035 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2036 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2037 strncpy(c->exten, "i", sizeof(c->exten)-1);
2040 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2041 c->name, c->exten, c->context);
2044 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2045 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2048 /* Done, wait for an extension */
2051 waittime = c->pbx->dtimeout;
2052 else if (!autofallthrough)
2053 waittime = c->pbx->rtimeout;
2055 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2056 /* As long as we're willing to wait, and as long as it's not defined,
2057 keep reading digits until we can't possibly get a right answer anymore. */
2058 digit = ast_waitfordigit(c, waittime * 1000);
2059 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2066 /* Error, maybe a hangup */
2068 exten[pos++] = digit;
2069 waittime = c->pbx->dtimeout;
2072 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2073 /* Prepare the next cycle */
2074 strncpy(c->exten, exten, sizeof(c->exten)-1);
2077 /* No such extension */
2078 if (!ast_strlen_zero(exten)) {
2079 /* An invalid extension */
2080 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2081 if (option_verbose > 2)
2082 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2083 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2084 strncpy(c->exten, "i", sizeof(c->exten)-1);
2087 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2091 /* A simple timeout */
2092 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2093 if (option_verbose > 2)
2094 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2095 strncpy(c->exten, "t", sizeof(c->exten)-1);
2098 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2104 if (option_verbose > 2)
2105 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2109 if (option_verbose > 0) {
2111 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2114 if (option_verbose > 2)
2115 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2116 if (!strcasecmp(status, "CONGESTION"))
2117 res = pbx_builtin_congestion(c, "10");
2118 else if (!strcasecmp(status, "CHANUNAVAIL"))
2119 res = pbx_builtin_congestion(c, "10");
2120 else if (!strcasecmp(status, "BUSY"))
2121 res = pbx_builtin_busy(c, "10");
2128 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2130 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2134 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2135 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2136 /* Something bad happened, or a hangup has been requested. */
2138 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2139 else if (option_verbose > 1)
2140 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2147 pbx_destroy(c->pbx);
2149 if (res != AST_PBX_KEEPALIVE)
2154 static void *pbx_thread(void *data)
2156 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2157 answer this channel and get it going. The setjmp stuff is fairly
2158 confusing, but necessary to get smooth transitions between
2159 the execution of different applications (without the use of
2160 additional threads) */
2161 struct ast_channel *c = data;
2167 int ast_pbx_start(struct ast_channel *c)
2170 pthread_attr_t attr;
2172 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2176 /* Start a new thread, and get something handling this channel. */
2177 pthread_attr_init(&attr);
2178 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2179 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2180 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2186 int pbx_set_autofallthrough(int newval)
2189 oldval = autofallthrough;
2190 if (oldval != newval)
2191 autofallthrough = newval;
2196 * This function locks contexts list by &conlist, search for the right context
2197 * structure, leave context list locked and call ast_context_remove_include2
2198 * which removes include, unlock contexts list and return ...
2200 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2202 struct ast_context *c;
2204 if (ast_lock_contexts()) return -1;
2206 /* walk contexts and search for the right one ...*/
2207 c = ast_walk_contexts(NULL);
2209 /* we found one ... */
2210 if (!strcmp(ast_get_context_name(c), context)) {
2212 /* remove include from this context ... */
2213 ret = ast_context_remove_include2(c, include, registrar);
2215 ast_unlock_contexts();
2217 /* ... return results */
2220 c = ast_walk_contexts(c);
2223 /* we can't find the right one context */
2224 ast_unlock_contexts();
2229 * When we call this function, &conlock lock must be locked, because when
2230 * we giving *con argument, some process can remove/change this context
2231 * and after that there can be segfault.
2233 * This function locks given context, removes include, unlock context and
2236 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2238 struct ast_include *i, *pi = NULL;
2240 if (ast_mutex_lock(&con->lock)) return -1;
2245 /* find our include */
2246 if (!strcmp(i->name, include) &&
2247 (!registrar || !strcmp(i->registrar, registrar))) {
2248 /* remove from list */
2252 con->includes = i->next;
2253 /* free include and return */
2255 ast_mutex_unlock(&con->lock);
2262 /* we can't find the right include */
2263 ast_mutex_unlock(&con->lock);
2268 * This function locks contexts list by &conlist, search for the rigt context
2269 * structure, leave context list locked and call ast_context_remove_switch2
2270 * which removes switch, unlock contexts list and return ...
2272 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2274 struct ast_context *c;
2276 if (ast_lock_contexts()) return -1;
2278 /* walk contexts and search for the right one ...*/
2279 c = ast_walk_contexts(NULL);
2281 /* we found one ... */
2282 if (!strcmp(ast_get_context_name(c), context)) {
2284 /* remove switch from this context ... */
2285 ret = ast_context_remove_switch2(c, sw, data, registrar);
2287 ast_unlock_contexts();
2289 /* ... return results */
2292 c = ast_walk_contexts(c);
2295 /* we can't find the right one context */
2296 ast_unlock_contexts();
2301 * When we call this function, &conlock lock must be locked, because when
2302 * we giving *con argument, some process can remove/change this context
2303 * and after that there can be segfault.
2305 * This function locks given context, removes switch, unlock context and
2308 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2310 struct ast_sw *i, *pi = NULL;
2312 if (ast_mutex_lock(&con->lock)) return -1;
2317 /* find our switch */
2318 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2319 (!registrar || !strcmp(i->registrar, registrar))) {
2320 /* remove from list */
2324 con->alts = i->next;
2325 /* free switch and return */
2327 ast_mutex_unlock(&con->lock);
2334 /* we can't find the right switch */
2335 ast_mutex_unlock(&con->lock);
2340 * This functions lock contexts list, search for the right context,
2341 * call ast_context_remove_extension2, unlock contexts list and return.
2342 * In this function we are using
2344 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2346 struct ast_context *c;
2348 if (ast_lock_contexts()) return -1;
2350 /* walk contexts ... */
2351 c = ast_walk_contexts(NULL);
2353 /* ... search for the right one ... */
2354 if (!strcmp(ast_get_context_name(c), context)) {
2355 /* ... remove extension ... */
2356 int ret = ast_context_remove_extension2(c, extension, priority,
2358 /* ... unlock contexts list and return */
2359 ast_unlock_contexts();
2362 c = ast_walk_contexts(c);
2365 /* we can't find the right context */
2366 ast_unlock_contexts();
2371 * When do you want to call this function, make sure that &conlock is locked,
2372 * because some process can handle with your *con context before you lock
2375 * This functionc locks given context, search for the right extension and
2376 * fires out all peer in this extensions with given priority. If priority
2377 * is set to 0, all peers are removed. After that, unlock context and
2380 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2382 struct ast_exten *exten, *prev_exten = NULL;
2384 if (ast_mutex_lock(&con->lock)) return -1;
2386 /* go through all extensions in context and search the right one ... */
2390 /* look for right extension */
2391 if (!strcmp(exten->exten, extension) &&
2392 (!registrar || !strcmp(exten->registrar, registrar))) {
2393 struct ast_exten *peer;
2395 /* should we free all peers in this extension? (priority == 0)? */
2396 if (priority == 0) {
2397 /* remove this extension from context list */
2399 prev_exten->next = exten->next;
2401 con->root = exten->next;
2403 /* fire out all peers */
2408 if (!peer->priority==PRIORITY_HINT)
2409 ast_remove_hint(peer);
2411 peer->datad(peer->data);
2417 ast_mutex_unlock(&con->lock);
2420 /* remove only extension with exten->priority == priority */
2421 struct ast_exten *previous_peer = NULL;
2425 /* is this our extension? */
2426 if (peer->priority == priority &&
2427 (!registrar || !strcmp(peer->registrar, registrar) )) {
2428 /* we are first priority extension? */
2429 if (!previous_peer) {
2430 /* exists previous extension here? */
2432 /* yes, so we must change next pointer in
2433 * previous connection to next peer
2436 prev_exten->next = peer->peer;
2437 peer->peer->next = exten->next;
2439 prev_exten->next = exten->next;
2441 /* no previous extension, we are first
2442 * extension, so change con->root ...
2445 con->root = peer->peer;
2447 con->root = exten->next;
2450 /* we are not first priority in extension */
2451 previous_peer->peer = peer->peer;
2454 /* now, free whole priority extension */
2455 if (peer->priority==PRIORITY_HINT)
2456 ast_remove_hint(peer);
2457 peer->datad(peer->data);
2460 ast_mutex_unlock(&con->lock);
2463 /* this is not right extension, skip to next peer */
2464 previous_peer = peer;
2469 ast_mutex_unlock(&con->lock);
2475 exten = exten->next;
2478 /* we can't find right extension */
2479 ast_mutex_unlock(&con->lock);
2484 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2486 struct ast_app *tmp, *prev, *cur;
2489 length = sizeof(struct ast_app);
2490 length += strlen(app) + 1;
2491 if (ast_mutex_lock(&applock)) {
2492 ast_log(LOG_ERROR, "Unable to lock application list\n");
2497 if (!strcasecmp(app, tmp->name)) {
2498 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2499 ast_mutex_unlock(&applock);
2504 tmp = malloc(length);
2506 memset(tmp, 0, length);
2507 strcpy(tmp->name, app);
2508 tmp->execute = execute;
2509 tmp->synopsis = synopsis;
2510 tmp->description = description;
2511 /* Store in alphabetical order */
2515 if (strcasecmp(tmp->name, cur->name) < 0)
2521 tmp->next = prev->next;
2528 ast_log(LOG_ERROR, "Out of memory\n");
2529 ast_mutex_unlock(&applock);
2532 if (option_verbose > 1)
2533 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2534 ast_mutex_unlock(&applock);
2538 int ast_register_switch(struct ast_switch *sw)
2540 struct ast_switch *tmp, *prev=NULL;
2541 if (ast_mutex_lock(&switchlock)) {
2542 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2547 if (!strcasecmp(tmp->name, sw->name))
2553 ast_mutex_unlock(&switchlock);
2554 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2562 ast_mutex_unlock(&switchlock);
2566 void ast_unregister_switch(struct ast_switch *sw)
2568 struct ast_switch *tmp, *prev=NULL;
2569 if (ast_mutex_lock(&switchlock)) {
2570 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2577 prev->next = tmp->next;
2579 switches = tmp->next;
2586 ast_mutex_unlock(&switchlock);
2590 * Help for CLI commands ...
2592 static char show_application_help[] =
2593 "Usage: show application <application> [<application> [<application> [...]]]\n"
2594 " Describes a particular application.\n";
2596 static char show_applications_help[] =
2597 "Usage: show applications [{like|describing} <text>]\n"
2598 " List applications which are currently available.\n"
2599 " If 'like', <text> will be a substring of the app name\n"
2600 " If 'describing', <text> will be a substring of the description\n";
2602 static char show_dialplan_help[] =
2603 "Usage: show dialplan [exten@][context]\n"
2606 static char show_switches_help[] =
2607 "Usage: show switches\n"
2608 " Show registered switches\n";
2610 static char show_hints_help[] =
2611 "Usage: show hints\n"
2612 " Show registered hints\n";
2616 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2621 * 'show application' CLI command implementation functions ...
2625 * There is a possibility to show informations about more than one
2626 * application at one time. You can type 'show application Dial Echo' and
2627 * you will see informations about these two applications ...
2629 static char *complete_show_application(char *line, char *word,
2635 /* try to lock applications list ... */
2636 if (ast_mutex_lock(&applock)) {
2637 ast_log(LOG_ERROR, "Unable to lock application list\n");
2641 /* ... walk all applications ... */
2644 /* ... check if word matches this application ... */
2645 if (!strncasecmp(word, a->name, strlen(word))) {
2646 /* ... if this is right app serve it ... */
2647 if (++which > state) {
2648 char *ret = strdup(a->name);
2649 ast_mutex_unlock(&applock);
2656 /* no application match */
2657 ast_mutex_unlock(&applock);
2661 static int handle_show_application(int fd, int argc, char *argv[])
2664 int app, no_registered_app = 1;
2666 if (argc < 3) return RESULT_SHOWUSAGE;
2668 /* try to lock applications list ... */
2669 if (ast_mutex_lock(&applock)) {
2670 ast_log(LOG_ERROR, "Unable to lock application list\n");
2674 /* ... go through all applications ... */
2677 /* ... compare this application name with all arguments given
2678 * to 'show application' command ... */
2679 for (app = 2; app < argc; app++) {
2680 if (!strcasecmp(a->name, argv[app])) {
2681 /* Maximum number of characters added by terminal coloring is 22 */
2682 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2683 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2684 int synopsis_size, description_size;
2686 no_registered_app = 0;
2689 synopsis_size = strlen(a->synopsis) + 23;
2691 synopsis_size = strlen("Not available") + 23;
2692 synopsis = alloca(synopsis_size);
2695 description_size = strlen(a->description) + 23;
2697 description_size = strlen("Not available") + 23;
2698 description = alloca(description_size);
2700 if (synopsis && description) {
2701 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2702 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2703 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2704 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2705 term_color(synopsis,
2706 a->synopsis ? a->synopsis : "Not available",
2707 COLOR_CYAN, 0, synopsis_size);
2708 term_color(description,
2709 a->description ? a->description : "Not available",
2710 COLOR_CYAN, 0, description_size);
2712 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2714 /* ... one of our applications, show info ...*/
2715 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2716 "[Synopsis]:\n %s\n\n"
2717 "[Description]:\n%s\n",
2719 a->synopsis ? a->synopsis : "Not available",
2720 a->description ? a->description : "Not available");
2727 ast_mutex_unlock(&applock);
2729 /* we found at least one app? no? */
2730 if (no_registered_app) {
2731 ast_cli(fd, "Your application(s) is (are) not registered\n");
2732 return RESULT_FAILURE;
2735 return RESULT_SUCCESS;
2738 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
2739 static int handle_show_hints(int fd, int argc, char *argv[])
2741 struct ast_hint *hint;
2745 ast_cli(fd, "There are no registered dialplan hints\n");
2746 return RESULT_SUCCESS;
2748 /* ... we have hints ... */
2749 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2750 if (ast_mutex_lock(&hintlock)) {
2751 ast_log(LOG_ERROR, "Unable to lock hints\n");
2756 ast_cli(fd, " %-20.20s: %-20.20s State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
2760 ast_cli(fd, "----------------\n");
2761 ast_cli(fd, "- %d hints registred\n", num);
2762 ast_mutex_unlock(&hintlock);
2763 return RESULT_SUCCESS;
2766 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
2767 static int handle_show_switches(int fd, int argc, char *argv[])
2769 struct ast_switch *sw;
2771 ast_cli(fd, "There are no registered alternative switches\n");
2772 return RESULT_SUCCESS;
2774 /* ... we have applications ... */
2775 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2776 if (ast_mutex_lock(&switchlock)) {
2777 ast_log(LOG_ERROR, "Unable to lock switches\n");
2782 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2785 ast_mutex_unlock(&switchlock);
2786 return RESULT_SUCCESS;
2790 * 'show applications' CLI command implementation functions ...
2792 static int handle_show_applications(int fd, int argc, char *argv[])
2795 int like=0, describing=0;
2796 int total_match = 0; /* Number of matches in like clause */
2797 int total_apps = 0; /* Number of apps registered */
2799 /* try to lock applications list ... */
2800 if (ast_mutex_lock(&applock)) {
2801 ast_log(LOG_ERROR, "Unable to lock application list\n");
2805 /* ... have we got at least one application (first)? no? */
2807 ast_cli(fd, "There are no registered applications\n");
2808 ast_mutex_unlock(&applock);
2812 /* show applications like <keyword> */
2813 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2815 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2819 /* show applications describing <keyword1> [<keyword2>] [...] */
2820 if ((!like) && (!describing)) {
2821 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2823 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2826 /* ... go through all applications ... */
2827 for (a = apps; a; a = a->next) {
2828 /* ... show informations about applications ... */
2832 if (ast_strcasestr(a->name, argv[3])) {
2836 } else if (describing) {
2837 if (a->description) {
2838 /* Match all words on command line */
2841 for (i=3;i<argc;i++) {
2842 if (! ast_strcasestr(a->description, argv[i])) {
2854 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2857 if ((!like) && (!describing)) {
2858 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
2860 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
2863 /* ... unlock and return */
2864 ast_mutex_unlock(&applock);
2866 return RESULT_SUCCESS;
2869 static char *complete_show_applications(char *line, char *word, int pos, int state)
2872 if (ast_strlen_zero(word)) {
2875 return strdup("like");
2877 return strdup("describing");
2881 } else if (! strncasecmp(word, "like", strlen(word))) {
2883 return strdup("like");
2887 } else if (! strncasecmp(word, "describing", strlen(word))) {
2889 return strdup("describing");
2899 * 'show dialplan' CLI command implementation functions ...
2901 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2904 struct ast_context *c;
2907 /* we are do completion of [exten@]context on second position only */
2908 if (pos != 2) return NULL;
2910 /* try to lock contexts list ... */
2911 if (ast_lock_contexts()) {
2912 ast_log(LOG_ERROR, "Unable to lock context list\n");
2916 /* ... walk through all contexts ... */
2917 c = ast_walk_contexts(NULL);
2919 /* ... word matches context name? yes? ... */
2920 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2921 /* ... for serve? ... */
2922 if (++which > state) {
2923 /* ... yes, serve this context name ... */
2924 char *ret = strdup(ast_get_context_name(c));
2925 ast_unlock_contexts();
2929 c = ast_walk_contexts(c);
2932 /* ... unlock and return */
2933 ast_unlock_contexts();
2937 struct dialplan_counters {
2941 int context_existence;
2942 int extension_existence;
2945 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
2947 struct ast_context *c;
2948 int res=0, old_total_exten = dpc->total_exten;
2950 /* try to lock contexts */
2951 if (ast_lock_contexts()) {
2952 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2956 /* walk all contexts ... */
2957 for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
2958 /* show this context? */
2960 !strcmp(ast_get_context_name(c), context)) {
2961 dpc->context_existence = 1;
2963 /* try to lock context before walking in ... */
2964 if (!ast_lock_context(c)) {
2965 struct ast_exten *e;
2966 struct ast_include *i;
2967 struct ast_ignorepat *ip;
2969 char buf[256], buf2[256];
2970 int context_info_printed = 0;
2972 /* are we looking for exten too? if yes, we print context
2973 * if we our extension only
2976 dpc->total_context++;
2977 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2978 ast_get_context_name(c), ast_get_context_registrar(c));
2979 context_info_printed = 1;
2982 /* walk extensions ... */
2983 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
2984 struct ast_exten *p;
2987 /* looking for extension? is this our extension? */
2989 !ast_extension_match(ast_get_extension_name(e), exten))