2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999-2004, 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
60 #define VAR_SOFTTRAN 2
61 #define VAR_HARDTRAN 3
65 /* ast_exten: An extension */
67 char *exten; /* Extension name */
68 int matchcid; /* Match caller id ? */
69 char *cidmatch; /* Caller id to match for this extension */
70 int priority; /* Priority */
71 char *label; /* Label */
72 struct ast_context *parent; /* An extension */
73 char *app; /* Application to execute */
74 void *data; /* Data to use */
75 void (*datad)(void *); /* Data destructor */
76 struct ast_exten *peer; /* Next higher priority with our extension */
77 const char *registrar; /* Registrar */
78 struct ast_exten *next; /* Extension with a greater ID */
82 /* ast_include: include= support in extensions.conf */
85 char *rname; /* Context to include */
86 const char *registrar; /* Registrar */
87 int hastime; /* If time construct exists */
88 struct ast_timing timing; /* time construct */
89 struct ast_include *next; /* Link them together */
93 /* ast_sw: Switch statement in extensions.conf */
96 const char *registrar; /* Registrar */
97 char *data; /* Data load */
98 struct ast_sw *next; /* Link them together */
102 struct ast_ignorepat {
103 const char *registrar;
104 struct ast_ignorepat *next;
108 /* ast_context: An extension context */
110 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
111 struct ast_exten *root; /* The root of the list of extensions */
112 struct ast_context *next; /* Link them together */
113 struct ast_include *includes; /* Include other contexts */
114 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
115 const char *registrar; /* Registrar */
116 struct ast_sw *alts; /* Alternative switches */
117 char name[0]; /* Name of the context */
121 /* ast_app: An application */
123 int (*execute)(struct ast_channel *chan, void *data);
124 const char *synopsis; /* Synopsis text for 'show applications' */
125 const char *description; /* Description (help text) for 'show application <name>' */
126 struct ast_app *next; /* Next app in list */
127 char name[0]; /* Name of the application */
130 /* ast_state_cb: An extension state notify */
131 struct ast_state_cb {
134 ast_state_cb_type callback;
135 struct ast_state_cb *next;
138 /* ast_state_cb: An extension state notify */
139 struct ast_devstate_cb {
141 ast_devstate_cb_type callback;
142 struct ast_devstate_cb *next;
145 static struct ast_devstate_cb *devcbs;
148 struct ast_exten *exten;
150 struct ast_state_cb *callbacks;
151 struct ast_hint *next;
154 int ast_pbx_outgoing_cdr_failed(void);
156 static int pbx_builtin_prefix(struct ast_channel *, void *);
157 static int pbx_builtin_suffix(struct ast_channel *, void *);
158 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
159 static int pbx_builtin_answer(struct ast_channel *, void *);
160 static int pbx_builtin_goto(struct ast_channel *, void *);
161 static int pbx_builtin_hangup(struct ast_channel *, void *);
162 static int pbx_builtin_background(struct ast_channel *, void *);
163 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
164 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
165 static int pbx_builtin_atimeout(struct ast_channel *, void *);
166 static int pbx_builtin_wait(struct ast_channel *, void *);
167 static int pbx_builtin_waitexten(struct ast_channel *, void *);
168 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
169 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
170 static int pbx_builtin_setaccount(struct ast_channel *, void *);
171 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
172 static int pbx_builtin_ringing(struct ast_channel *, void *);
173 static int pbx_builtin_progress(struct ast_channel *, void *);
174 static int pbx_builtin_congestion(struct ast_channel *, void *);
175 static int pbx_builtin_busy(struct ast_channel *, void *);
176 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
177 static int pbx_builtin_noop(struct ast_channel *, void *);
178 static int pbx_builtin_gotoif(struct ast_channel *, void *);
179 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
180 static int pbx_builtin_saynumber(struct ast_channel *, void *);
181 static int pbx_builtin_saydigits(struct ast_channel *, void *);
182 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
183 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
184 int pbx_builtin_setvar(struct ast_channel *, void *);
185 static int pbx_builtin_importvar(struct ast_channel *, void *);
186 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
187 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
189 static struct varshead globals;
191 static int autofallthrough = 0;
193 static struct pbx_builtin {
194 char name[AST_MAX_APP];
195 int (*execute)(struct ast_channel *chan, void *data);
200 /* These applications are built into the PBX core and do not
201 need separate modules
205 { "AbsoluteTimeout", pbx_builtin_atimeout,
206 "Set absolute maximum time of call",
207 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
208 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
211 { "Answer", pbx_builtin_answer,
212 "Answer a channel if ringing",
213 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
214 "Returns 0 unless it tries to answer the channel and fails.\n"
217 { "BackGround", pbx_builtin_background,
218 "Play a file while awaiting extension",
219 " Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
220 "given files, while simultaneously waiting for the user to begin typing\n"
221 "an extension. The timeouts do not count until the last BackGround\n"
222 "application has ended. Options may also be included following a pipe \n"
223 "symbol. The 'skip' option causes the playback of the message to be \n"
224 "skipped if the channel is not in the 'up' state (i.e. it hasn't been\n"
225 "answered yet. If 'skip' is specified, the application will return\n"
226 "immediately should the channel not be off hook. Otherwise, unless \n"
227 "'noanswer' is specified, the channel channel will be answered before the\n"
228 "sound is played. Not all channels support playing messages while still\n"
229 "hook. The 'langoverride' may be a language to use for playing the prompt\n"
230 "which differs from the current language of the channel. Returns -1 if \n"
231 "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n"
234 { "Busy", pbx_builtin_busy,
235 "Indicate busy condition and stop",
236 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
237 "then waits for the user to hang up or the optional timeout to expire.\n"
241 { "Congestion", pbx_builtin_congestion,
242 "Indicate congestion and stop",
243 " Congestion([timeout]): Requests that the channel indicate congestion\n"
244 "and then waits for the user to hang up or for the optional timeout to\n"
245 "expire. Always returns -1."
248 { "DigitTimeout", pbx_builtin_dtimeout,
249 "Set maximum timeout between digits",
250 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
251 "digits when the user is typing in an extension. When this timeout expires,\n"
252 "after the user has started to type in an extension, the extension will be\n"
253 "considered complete, and will be interpreted. Note that if an extension\n"
254 "typed in is valid, it will not have to timeout to be tested, so typically\n"
255 "at the expiry of this timeout, the extension will be considered invalid\n"
256 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
257 "exist the call would be terminated). Always returns 0.\n"
260 { "Goto", pbx_builtin_goto,
261 "Goto a particular priority, extension, or context",
262 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
263 "value, optionally setting the extension and optionally the context as well.\n"
264 "The extension BYEXTENSION is special in that it uses the current extension,\n"
265 "thus permitting you to go to a different context, without specifying a\n"
266 "specific extension. Always returns 0, even if the given context, extension,\n"
267 "or priority is invalid.\n"
270 { "GotoIf", pbx_builtin_gotoif,
272 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
273 "true, to label2 if condition is false. Either label1 or label2 may be\n"
274 "omitted (in that case, we just don't take the particular branch) but not\n"
275 "both. Look for the condition syntax in examples or documentation."
278 { "GotoIfTime", pbx_builtin_gotoiftime,
279 "Conditional goto on current time",
280 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
281 "If the current time matches the specified time, then branch to the specified\n"
282 "extension. Each of the elements may be specified either as '*' (for always)\n"
283 "or as a range. See the 'include' syntax for details."
286 { "Hangup", pbx_builtin_hangup,
287 "Unconditional hangup",
288 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
291 { "NoOp", pbx_builtin_noop,
293 " NoOp(): No-operation; Does nothing."
296 { "Prefix", pbx_builtin_prefix,
297 "Prepend leading digits",
298 " Prefix(digits): Prepends the digit string specified by digits to the\n"
299 "channel's associated extension. For example, the number 1212 when prefixed\n"
300 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
301 "continue processing at the next priority for the *new* extension.\n"
302 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
303 "executed will be priority 4 of 5551212. If you switch into an extension\n"
304 "which has no first step, the PBX will treat it as though the user dialed an\n"
305 "invalid extension.\n"
308 { "Progress", pbx_builtin_progress,
310 " Progress(): Request that the channel indicate in-band progress is \n"
311 "available to the user.\nAlways returns 0.\n"
314 { "ResetCDR", pbx_builtin_resetcdr,
315 "Resets the Call Data Record",
316 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
317 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
318 "record WILL be stored.\nAlways returns 0.\n"
321 { "ResponseTimeout", pbx_builtin_rtimeout,
322 "Set maximum timeout awaiting response",
323 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
324 "falling through a series of priorities for a channel in which the user may\n"
325 "begin typing an extension. If the user does not type an extension in this\n"
326 "amount of time, control will pass to the 't' extension if it exists, and\n"
327 "if not the call would be terminated.\nAlways returns 0.\n"
330 { "Ringing", pbx_builtin_ringing,
331 "Indicate ringing tone",
332 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
333 "Always returns 0.\n"
336 { "SayNumber", pbx_builtin_saynumber,
338 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
339 "the current language setting for the channel. (See app SetLanguage).\n"
342 { "SayDigits", pbx_builtin_saydigits,
344 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
345 "current language setting for the channel. (See app setLanguage)\n"
348 { "SayAlpha", pbx_builtin_saycharacters,
350 " SayAlpha(string): Spells the passed string\n"
353 { "SayPhonetic", pbx_builtin_sayphonetic,
355 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
358 { "SetAccount", pbx_builtin_setaccount,
360 " SetAccount([account]): Set the channel account code for billing\n"
361 "purposes. Always returns 0.\n"
364 { "SetAMAFlags", pbx_builtin_setamaflags,
366 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
367 "purposes. Always returns 0.\n"
370 { "SetGlobalVar", pbx_builtin_setglobalvar,
371 "Set global variable to value",
372 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
373 "variable are available across channels.\n"
376 { "SetLanguage", pbx_builtin_setlanguage,
377 "Sets user language",
378 " SetLanguage(language): Set the channel language to 'language'. This\n"
379 "information is used for the syntax in generation of numbers, and to choose\n"
380 "a natural language file when available.\n"
381 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
382 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
383 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
384 "Always returns 0.\n"
387 { "SetVar", pbx_builtin_setvar,
388 "Set variable to value",
389 " SetVar(#n=value): Sets variable n to value. If prefixed with _, single\n"
390 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
392 { "ImportVar", pbx_builtin_importvar,
393 "Set variable to value",
394 " ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on\n"
395 "the specified channel (instead of current). If prefixed with _, single\n"
396 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
398 { "StripMSD", pbx_builtin_stripmsd,
399 "Strip leading digits",
400 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
401 "associated extension. For example, the number 5551212 when stripped with a\n"
402 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
403 "will continue processing at the next priority for the *new* extension.\n"
404 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
405 "executed will be priority 4 of 1212. If you switch into an extension which\n"
406 "has no first step, the PBX will treat it as though the user dialed an\n"
407 "invalid extension.\n"
410 { "Suffix", pbx_builtin_suffix,
411 "Append trailing digits",
412 " Suffix(digits): Appends the digit string specified by digits to the\n"
413 "channel's associated extension. For example, the number 555 when suffixed\n"
414 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
415 "continue processing at the next priority for the *new* extension.\n"
416 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
417 "executed will be priority 4 of 5551212. If you switch into an extension\n"
418 "which has no first step, the PBX will treat it as though the user dialed an\n"
419 "invalid extension.\n"
422 { "Wait", pbx_builtin_wait,
423 "Waits for some time",
424 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
425 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
428 { "WaitExten", pbx_builtin_waitexten,
429 "Waits for an extension to be entered",
430 " WaitExten([seconds]): Waits for the user to enter a new extension for the \n"
431 "specified number of seconds, then returns 0. Seconds can be passed with\n"
432 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
433 "default extension timeout will be used.\n"
438 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
439 static struct ast_context *contexts = NULL;
440 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
441 static struct ast_app *apps = NULL;
443 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
444 struct ast_switch *switches = NULL;
446 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
447 static int stateid = 1;
448 struct ast_hint *hints = NULL;
449 struct ast_state_cb *statecbs = NULL;
451 int pbx_exec(struct ast_channel *c, /* Channel */
452 struct ast_app *app, /* Application */
453 void *data, /* Data for execution */
454 int newstack) /* Force stack increment */
456 /* This function is special. It saves the stack so that no matter
457 how many times it is called, it returns to the same place */
463 int stack = c->stack;
464 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
466 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
467 /* Don't allow us to go over the max number of stacks we
469 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
472 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
473 /* Okay, here's where it gets weird. If newstack is non-zero,
474 then we increase the stack increment, but setjmp is not going
475 to return until longjmp is called -- when the application
476 exec'd is finished running. */
479 if (c->stack != stack + 1)
480 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
481 else if (c->app[c->stack])
482 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
487 ast_cdr_setapp(c->cdr, app->name, data);
489 /* save channel values */
490 saved_c_appl= c->appl;
491 saved_c_data= c->data;
495 res = execute(c, data);
496 /* restore channel values */
497 c->appl= saved_c_appl;
498 c->data= saved_c_data;
500 /* Any application that returns, we longjmp back, just in case. */
501 if (c->stack != stack + 1)
502 ast_log(LOG_WARNING, "Stack is not at expected value\n");
503 longjmp(c->jmp[stack+1], res);
509 /* Go no deeper than this through includes (not counting loops) */
510 #define AST_PBX_MAX_STACK 64
512 #define HELPER_EXISTS 0
513 #define HELPER_SPAWN 1
514 #define HELPER_EXEC 2
515 #define HELPER_CANMATCH 3
516 #define HELPER_MATCHMORE 4
517 #define HELPER_FINDLABEL 5
519 struct ast_app *pbx_findapp(const char *app)
523 if (ast_mutex_lock(&applock)) {
524 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
529 if (!strcasecmp(tmp->name, app))
533 ast_mutex_unlock(&applock);
537 static struct ast_switch *pbx_findswitch(const char *sw)
539 struct ast_switch *asw;
541 if (ast_mutex_lock(&switchlock)) {
542 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
547 if (!strcasecmp(asw->name, sw))
551 ast_mutex_unlock(&switchlock);
555 static inline int include_valid(struct ast_include *i)
560 return ast_check_timing(&(i->timing));
563 static void pbx_destroy(struct ast_pbx *p)
568 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
569 /* All patterns begin with _ */\
570 if (pattern[0] != '_') \
572 /* Start optimistic */\
575 while(match && *data && *pattern && (*pattern != '/')) {\
576 while (*data == '-' && (*(data+1) != '\0')) data++;\
577 switch(toupper(*pattern)) {\
584 where=strchr(pattern,']');\
586 border=(int)(where-pattern);\
587 if (!where || border > strlen(pattern)) {\
588 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
591 for (i=0; i<border; i++) {\
594 if (pattern[i+1]=='-') {\
595 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
602 if (res==1 || *data==pattern[i]) {\
611 if ((*data < '2') || (*data > '9'))\
615 if ((*data < '0') || (*data > '9'))\
619 if ((*data < '1') || (*data > '9'))\
627 /* Ignore these characters */\
631 if (*data != *pattern)\
639 int ast_extension_match(const char *pattern, const char *data)
642 /* If they're the same return */
643 if (!strcmp(pattern, data))
645 EXTENSION_MATCH_CORE(data,pattern,match);
646 /* Must be at the end of both */
647 if (*data || (*pattern && (*pattern != '/')))
652 int ast_extension_close(const char *pattern, const char *data, int needmore)
655 /* If "data" is longer, it can'be a subset of pattern unless
656 pattern is a pattern match */
657 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
660 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
661 (!needmore || (strlen(pattern) > strlen(data)))) {
664 EXTENSION_MATCH_CORE(data,pattern,match);
665 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
666 if (!needmore || *pattern) {
672 struct ast_context *ast_context_find(const char *name)
674 struct ast_context *tmp;
675 ast_mutex_lock(&conlock);
679 if (!strcasecmp(name, tmp->name))
685 ast_mutex_unlock(&conlock);
689 #define STATUS_NO_CONTEXT 1
690 #define STATUS_NO_EXTENSION 2
691 #define STATUS_NO_PRIORITY 3
692 #define STATUS_NO_LABEL 4
693 #define STATUS_SUCCESS 5
695 static int matchcid(const char *cidpattern, const char *callerid)
699 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
700 failing to get a number should count as a match, otherwise not */
703 if (!ast_strlen_zero(cidpattern))
711 return ast_extension_match(cidpattern, callerid);
714 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)
717 struct ast_context *tmp;
718 struct ast_exten *e, *eroot;
719 struct ast_include *i;
721 struct ast_switch *asw;
723 /* Initialize status if appropriate */
725 *status = STATUS_NO_CONTEXT;
729 /* Check for stack overflow */
730 if (*stacklen >= AST_PBX_MAX_STACK) {
731 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
734 /* Check first to see if we've already been checked */
735 for (x=0;x<*stacklen;x++) {
736 if (!strcasecmp(incstack[x], context))
745 if (bypass || !strcmp(tmp->name, context)) {
746 if (*status < STATUS_NO_EXTENSION)
747 *status = STATUS_NO_EXTENSION;
750 /* Match extension */
751 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
752 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
753 ((action == HELPER_MATCHMORE) && (ast_extension_close(eroot->exten, exten, 1)))) &&
754 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
756 if (*status < STATUS_NO_PRIORITY)
757 *status = STATUS_NO_PRIORITY;
760 if (action == HELPER_FINDLABEL) {
761 if (*status < STATUS_NO_LABEL)
762 *status = STATUS_NO_LABEL;
763 if (label && e->label && !strcmp(label, e->label)) {
764 *status = STATUS_SUCCESS;
767 } else if (e->priority == priority) {
768 *status = STATUS_SUCCESS;
776 /* Check alternative switches */
779 if ((asw = pbx_findswitch(sw->name))) {
780 if (action == HELPER_CANMATCH)
781 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
782 else if (action == HELPER_MATCHMORE)
783 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
785 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
793 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
797 /* Setup the stack */
798 incstack[*stacklen] = tmp->name;
800 /* Now try any includes we have in this context */
803 if (include_valid(i)) {
804 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data)))
818 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
821 char tmpvar[80] = "";
823 struct tm brokentime;
825 struct ast_var_t *variables;
830 /* Now we have the variable name on cp3 */
831 if (!strncasecmp(var,"LEN(",4)) {
834 if (strrchr(var,')')) {
836 strncpy(cp3, var, sizeof(cp3) - 1);
837 cp3[len-len_len-1]='\0';
838 sprintf(workspace,"%d",(int)strlen(cp3));
844 } else if ((first=strchr(var,':'))) {
845 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
846 first = strchr(tmpvar, ':');
848 first = tmpvar + strlen(tmpvar);
850 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1, headp);
852 offset=atoi(first+1);
853 if ((second=strchr(first+1,':'))) {
855 offset2=atoi(second+1);
857 offset2=strlen(*ret)-offset;
858 if (abs(offset)>strlen(*ret)) {
862 offset=-strlen(*ret);
864 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
866 offset2=strlen(*ret)-offset;
868 offset2=strlen(*ret)+offset;
873 *ret+=strlen(*ret)+offset;
874 (*ret)[offset2] = '\0';
875 } else if (c && !strcmp(var, "CALLERIDNUM")) {
876 if (c->cid.cid_num) {
877 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
881 } else if (c && !strcmp(var, "CALLERANI")) {
882 if (c->cid.cid_ani) {
883 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
887 } else if (c && !strcmp(var, "CALLERIDNAME")) {
888 if (c->cid.cid_name) {
889 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
893 } else if (c && !strcmp(var, "CALLERID")) {
894 if (c->cid.cid_num) {
895 if (c->cid.cid_name) {
896 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
898 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
901 } else if (c->cid.cid_name) {
902 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
906 } else if (c && !strcmp(var, "DNID")) {
907 if (c->cid.cid_dnid) {
908 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
912 } else if (c && !strcmp(var, "HINT")) {
913 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
917 } else if (c && !strcmp(var, "EXTEN")) {
918 strncpy(workspace, c->exten, workspacelen - 1);
920 } else if (c && !strcmp(var, "RDNIS")) {
921 if (c->cid.cid_rdnis) {
922 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
926 } else if (c && !strcmp(var, "CONTEXT")) {
927 strncpy(workspace, c->context, workspacelen - 1);
929 } else if (c && !strcmp(var, "PRIORITY")) {
930 snprintf(workspace, workspacelen, "%d", c->priority);
932 } else if (c && !strcmp(var, "CALLINGPRES")) {
933 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
935 } else if (c && !strcmp(var, "CALLINGANI2")) {
936 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
938 } else if (c && !strcmp(var, "CALLINGTON")) {
939 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
941 } else if (c && !strcmp(var, "CALLINGTNS")) {
942 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
944 } else if (c && !strcmp(var, "CHANNEL")) {
945 strncpy(workspace, c->name, workspacelen - 1);
947 } else if (c && !strcmp(var, "EPOCH")) {
948 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
950 } else if (c && !strcmp(var, "DATETIME")) {
952 localtime_r(&thistime, &brokentime);
953 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
956 brokentime.tm_year+1900,
962 } else if (c && !strcmp(var, "TIMESTAMP")) {
964 localtime_r(&thistime, &brokentime);
965 /* 20031130-150612 */
966 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
967 brokentime.tm_year+1900,
975 } else if (c && !strcmp(var, "UNIQUEID")) {
976 snprintf(workspace, workspacelen, "%s", c->uniqueid);
978 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
979 snprintf(workspace, workspacelen, "%i", c->hangupcause);
981 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
982 strncpy(workspace, c->accountcode, workspacelen - 1);
984 } else if (c && !strcmp(var, "LANGUAGE")) {
985 strncpy(workspace, c->language, workspacelen - 1);
989 AST_LIST_TRAVERSE(headp,variables,entries) {
991 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
993 if (strcasecmp(ast_var_name(variables),var)==0) {
994 *ret=ast_var_value(variables);
996 strncpy(workspace, *ret, workspacelen - 1);
1005 AST_LIST_TRAVERSE(&globals,variables,entries) {
1007 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1009 if (strcasecmp(ast_var_name(variables),var)==0) {
1010 *ret=ast_var_value(variables);
1012 strncpy(workspace, *ret, workspacelen - 1);
1019 int len=strlen(var);
1020 int len_env=strlen("ENV(");
1021 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1023 strncpy(cp3, var, sizeof(cp3) - 1);
1025 *ret=getenv(cp3+len_env);
1027 strncpy(workspace, *ret, workspacelen - 1);
1035 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1038 const char *tmp, *whereweare;
1040 char workspace[4096];
1041 char ltmp[4096], var[4096];
1042 char *nextvar, *nextexp;
1044 int pos, brackets, needsub, len;
1046 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1049 while(!ast_strlen_zero(whereweare) && count) {
1050 /* Assume we're copying the whole remaining string */
1051 pos = strlen(whereweare);
1053 /* Look for a variable */
1054 nextvar = strstr(whereweare, "${");
1056 /* Look for an expression */
1057 nextexp = strstr(whereweare, "$[");
1059 /* Pick the first one only */
1060 if (nextvar && nextexp) {
1061 if (nextvar < nextexp)
1067 /* If there is one, we only go that far */
1069 pos = nextvar - whereweare;
1071 pos = nextexp - whereweare;
1073 /* Can't copy more than 'count' bytes */
1077 /* Copy that many bytes */
1078 memcpy(cp2, whereweare, pos);
1085 /* We have a variable. Find the start and end, and determine
1086 if we are going to have to recursively call ourselves on the
1088 vars = vare = nextvar + 2;
1092 /* Find the end of it */
1093 while(brackets && *vare) {
1094 if ((vare[0] == '$') && (vare[1] == '{')) {
1097 } else if (vare[0] == '}') {
1099 } else if ((vare[0] == '$') && (vare[1] == '['))
1104 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1105 len = vare - vars - 1;
1107 /* Skip totally over variable name */
1108 whereweare += ( len + 3);
1110 /* Store variable name (and truncate) */
1111 memset(var, 0, sizeof(var));
1112 strncpy(var, vars, sizeof(var) - 1);
1115 /* Substitute if necessary */
1117 memset(ltmp, 0, sizeof(ltmp));
1118 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1124 /* Retrieve variable value */
1125 workspace[0] = '\0';
1126 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace), headp);
1128 length = strlen(cp4);
1131 memcpy(cp2, cp4, length);
1136 } else if (nextexp) {
1137 /* We have an expression. Find the start and end, and determine
1138 if we are going to have to recursively call ourselves on the
1140 vars = vare = nextexp + 2;
1144 /* Find the end of it */
1145 while(brackets && *vare) {
1146 if ((vare[0] == '$') && (vare[1] == '[')) {
1150 } else if (vare[0] == '[') {
1152 } else if (vare[0] == ']') {
1154 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1161 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1162 len = vare - vars - 1;
1164 /* Skip totally over variable name */
1165 whereweare += ( len + 3);
1167 /* Store variable name (and truncate) */
1168 memset(var, 0, sizeof(var));
1169 strncpy(var, vars, sizeof(var) - 1);
1172 /* Substitute if necessary */
1174 memset(ltmp, 0, sizeof(ltmp));
1175 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1181 /* Evaluate expression */
1182 cp4 = ast_expr(vars);
1184 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1187 length = strlen(cp4);
1190 memcpy(cp2, cp4, length);
1201 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1203 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1206 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1208 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1211 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1213 memset(passdata, 0, datalen);
1215 /* No variables or expressions in e->data, so why scan it? */
1216 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1217 strncpy(passdata, e->data, datalen - 1);
1218 passdata[datalen-1] = '\0';
1222 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1225 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)
1227 struct ast_exten *e;
1228 struct ast_app *app;
1229 struct ast_switch *sw;
1234 char *incstack[AST_PBX_MAX_STACK];
1235 char passdata[EXT_DATA_SIZE];
1239 char tmp3[EXT_DATA_SIZE];
1241 if (ast_mutex_lock(&conlock)) {
1242 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1243 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1248 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data);
1251 case HELPER_CANMATCH:
1252 ast_mutex_unlock(&conlock);
1255 ast_mutex_unlock(&conlock);
1257 case HELPER_FINDLABEL:
1259 ast_mutex_unlock(&conlock);
1261 case HELPER_MATCHMORE:
1262 ast_mutex_unlock(&conlock);
1268 app = pbx_findapp(e->app);
1269 ast_mutex_unlock(&conlock);
1271 if (c->context != context)
1272 strncpy(c->context, context, sizeof(c->context)-1);
1273 if (c->exten != exten)
1274 strncpy(c->exten, exten, sizeof(c->exten)-1);
1275 c->priority = priority;
1276 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1278 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1279 if (option_verbose > 2)
1280 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1281 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1282 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1283 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1284 (newstack ? "in new stack" : "in same stack"));
1285 manager_event(EVENT_FLAG_CALL, "Newexten",
1290 "Application: %s\r\n"
1293 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1294 res = pbx_exec(c, app, passdata, newstack);
1297 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1301 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1305 case HELPER_CANMATCH:
1306 ast_mutex_unlock(&conlock);
1309 ast_mutex_unlock(&conlock);
1311 case HELPER_MATCHMORE:
1312 ast_mutex_unlock(&conlock);
1314 case HELPER_FINDLABEL:
1315 ast_mutex_unlock(&conlock);
1321 ast_mutex_unlock(&conlock);
1323 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1325 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1330 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1334 ast_mutex_unlock(&conlock);
1336 case STATUS_NO_CONTEXT:
1337 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1338 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1340 case STATUS_NO_EXTENSION:
1341 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1342 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1344 case STATUS_NO_PRIORITY:
1345 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1346 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1348 case STATUS_NO_LABEL:
1350 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1353 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1356 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1364 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1366 struct ast_exten *e;
1367 struct ast_switch *sw;
1370 char *incstack[AST_PBX_MAX_STACK];
1373 if (ast_mutex_lock(&conlock)) {
1374 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1377 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1378 ast_mutex_unlock(&conlock);
1382 static int ast_extension_state2(struct ast_exten *e)
1384 char hint[AST_MAX_EXTENSION] = "";
1387 int allunavailable = 1, allbusy = 1, allfree = 1;
1390 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1394 rest = strchr(cur, '&');
1400 res = ast_device_state(cur);
1402 case AST_DEVICE_NOT_INUSE:
1406 case AST_DEVICE_INUSE:
1407 return AST_EXTENSION_INUSE;
1408 case AST_DEVICE_BUSY:
1413 case AST_DEVICE_UNAVAILABLE:
1414 case AST_DEVICE_INVALID:
1427 return AST_EXTENSION_NOT_INUSE;
1429 return AST_EXTENSION_BUSY;
1431 return AST_EXTENSION_UNAVAILABLE;
1433 return AST_EXTENSION_INUSE;
1435 return AST_EXTENSION_NOT_INUSE;
1439 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1441 struct ast_exten *e;
1443 e = ast_hint_extension(c, context, exten);
1447 return ast_extension_state2(e);
1450 int ast_device_state_changed(const char *fmt, ...)
1452 struct ast_hint *list;
1453 struct ast_state_cb *cblist;
1454 struct ast_devstate_cb *devcb;
1455 char hint[AST_MAX_EXTENSION] = "";
1456 char device[AST_MAX_EXTENSION];
1463 vsnprintf(device, sizeof(device), fmt, ap);
1466 rest = strchr(device, '-');
1471 state = ast_device_state(device);
1473 ast_mutex_lock(&hintlock);
1477 if (devcb->callback)
1478 devcb->callback(device, state, devcb->data);
1479 devcb = devcb->next;
1485 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1488 rest = strchr(cur, '&');
1494 if (!strcmp(cur, device)) {
1495 /* Found extension execute callbacks */
1496 state = ast_extension_state2(list->exten);
1497 if ((state != -1) && (state != list->laststate)) {
1498 /* For general callbacks */
1501 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1502 cblist = cblist->next;
1505 /* For extension callbacks */
1506 cblist = list->callbacks;
1508 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1509 cblist = cblist->next;
1512 list->laststate = state;
1520 ast_mutex_unlock(&hintlock);
1524 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1526 struct ast_devstate_cb *devcb;
1527 devcb = malloc(sizeof(struct ast_devstate_cb));
1529 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1530 ast_mutex_lock(&hintlock);
1532 devcb->callback = callback;
1533 devcb->next = devcbs;
1535 ast_mutex_unlock(&hintlock);
1540 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1542 struct ast_devstate_cb *devcb, *prev = NULL, *next;
1543 ast_mutex_lock(&hintlock);
1547 if ((devcb->data == data) && (devcb->callback == callback)) {
1557 ast_mutex_unlock(&hintlock);
1560 int ast_extension_state_add(const char *context, const char *exten,
1561 ast_state_cb_type callback, void *data)
1563 struct ast_hint *list;
1564 struct ast_state_cb *cblist;
1565 struct ast_exten *e;
1567 /* No context and extension add callback to statecbs list */
1568 if (!context && !exten) {
1569 ast_mutex_lock(&hintlock);
1573 if (cblist->callback == callback) {
1574 cblist->data = data;
1575 ast_mutex_unlock(&hintlock);
1577 cblist = cblist->next;
1580 /* Now inserts the callback */
1581 cblist = malloc(sizeof(struct ast_state_cb));
1583 ast_mutex_unlock(&hintlock);
1586 memset(cblist, 0, sizeof(struct ast_state_cb));
1588 cblist->callback = callback;
1589 cblist->data = data;
1591 cblist->next = statecbs;
1594 ast_mutex_unlock(&hintlock);
1598 if (!context || !exten)
1601 /* This callback type is for only one hint */
1602 e = ast_hint_extension(NULL, context, exten);
1607 ast_mutex_lock(&hintlock);
1611 if (list->exten == e)
1617 ast_mutex_unlock(&hintlock);
1621 /* Now inserts the callback */
1622 cblist = malloc(sizeof(struct ast_state_cb));
1624 ast_mutex_unlock(&hintlock);
1627 memset(cblist, 0, sizeof(struct ast_state_cb));
1628 cblist->id = stateid++;
1629 cblist->callback = callback;
1630 cblist->data = data;
1632 cblist->next = list->callbacks;
1633 list->callbacks = cblist;
1635 ast_mutex_unlock(&hintlock);
1639 int ast_extension_state_del(int id, ast_state_cb_type callback)
1641 struct ast_hint *list;
1642 struct ast_state_cb *cblist, *cbprev;
1644 if (!id && !callback)
1647 ast_mutex_lock(&hintlock);
1649 /* id is zero is a callback without extension */
1654 if (cblist->callback == callback) {
1656 statecbs = cblist->next;
1658 cbprev->next = cblist->next;
1662 ast_mutex_unlock(&hintlock);
1666 cblist = cblist->next;
1669 ast_mutex_lock(&hintlock);
1673 /* id greater than zero is a callback with extension */
1676 cblist = list->callbacks;
1679 if (cblist->id==id) {
1681 list->callbacks = cblist->next;
1683 cbprev->next = cblist->next;
1687 ast_mutex_unlock(&hintlock);
1691 cblist = cblist->next;
1696 ast_mutex_unlock(&hintlock);
1700 static int ast_add_hint(struct ast_exten *e)
1702 struct ast_hint *list;
1707 ast_mutex_lock(&hintlock);
1710 /* Search if hint exists, do nothing */
1712 if (list->exten == e) {
1713 ast_mutex_unlock(&hintlock);
1719 list = malloc(sizeof(struct ast_hint));
1721 ast_mutex_unlock(&hintlock);
1724 /* Initialize and insert new item */
1725 memset(list, 0, sizeof(struct ast_hint));
1727 list->laststate = ast_extension_state2(e);
1731 ast_mutex_unlock(&hintlock);
1735 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1737 struct ast_hint *list;
1739 ast_mutex_lock(&hintlock);
1743 if (list->exten == oe) {
1745 ast_mutex_unlock(&hintlock);
1750 ast_mutex_unlock(&hintlock);
1755 static int ast_remove_hint(struct ast_exten *e)
1757 /* Cleanup the Notifys if hint is removed */
1758 struct ast_hint *list, *prev = NULL;
1759 struct ast_state_cb *cblist, *cbprev;
1764 ast_mutex_lock(&hintlock);
1768 if (list->exten==e) {
1770 cblist = list->callbacks;
1772 /* Notify with -1 and remove all callbacks */
1774 cblist = cblist->next;
1775 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1778 list->callbacks = NULL;
1783 prev->next = list->next;
1786 ast_mutex_unlock(&hintlock);
1794 ast_mutex_unlock(&hintlock);
1799 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1801 struct ast_exten *e;
1802 e = ast_hint_extension(c, context, exten);
1804 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1810 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1812 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1815 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1817 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1820 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1822 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1825 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1827 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1830 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1832 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1835 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1837 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1840 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1842 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1845 int ast_pbx_run(struct ast_channel *c)
1854 /* A little initial setup here */
1856 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1857 c->pbx = malloc(sizeof(struct ast_pbx));
1859 ast_log(LOG_ERROR, "Out of memory\n");
1864 c->cdr = ast_cdr_alloc();
1866 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1870 ast_cdr_init(c->cdr, c);
1873 memset(c->pbx, 0, sizeof(struct ast_pbx));
1874 /* Set reasonable defaults */
1875 c->pbx->rtimeout = 10;
1876 c->pbx->dtimeout = 5;
1878 /* Start by trying whatever the channel is set to */
1879 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1880 /* JK02: If not successfull fall back to 's' */
1881 if (option_verbose > 1)
1882 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);
1883 strncpy(c->exten, "s", sizeof(c->exten)-1);
1884 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1885 /* JK02: And finally back to default if everything else failed */
1886 if (option_verbose > 1)
1887 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);
1888 strncpy(c->context, "default", sizeof(c->context)-1);
1892 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1893 ast_cdr_start(c->cdr);
1897 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1898 memset(exten, 0, sizeof(exten));
1899 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1900 /* Something bad happened, or a hangup has been requested. */
1901 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1902 (res == '*') || (res == '#')) {
1903 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1904 memset(exten, 0, sizeof(exten));
1906 exten[pos++] = digit = res;
1910 case AST_PBX_KEEPALIVE:
1912 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1913 else if (option_verbose > 1)
1914 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1919 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1920 else if (option_verbose > 1)
1921 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1922 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1927 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1937 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1938 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1939 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1940 c->whentohangup = 0;
1942 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1943 } else if (c->_softhangup) {
1944 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1945 c->exten, c->priority);
1951 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1952 /* It's not a valid extension anymore */
1953 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1954 if (option_verbose > 2)
1955 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1956 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1957 strncpy(c->exten, "i", sizeof(c->exten)-1);
1960 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1961 c->name, c->exten, c->context);
1964 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1965 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1968 /* Done, wait for an extension */
1971 waittime = c->pbx->dtimeout;
1972 else if (!autofallthrough)
1973 waittime = c->pbx->rtimeout;
1975 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1976 /* As long as we're willing to wait, and as long as it's not defined,
1977 keep reading digits until we can't possibly get a right answer anymore. */
1978 digit = ast_waitfordigit(c, waittime * 1000);
1979 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1986 /* Error, maybe a hangup */
1988 exten[pos++] = digit;
1989 waittime = c->pbx->dtimeout;
1992 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1993 /* Prepare the next cycle */
1994 strncpy(c->exten, exten, sizeof(c->exten)-1);
1997 /* No such extension */
1998 if (!ast_strlen_zero(exten)) {
1999 /* An invalid extension */
2000 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2001 if (option_verbose > 2)
2002 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2003 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2004 strncpy(c->exten, "i", sizeof(c->exten)-1);
2007 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2011 /* A simple timeout */
2012 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2013 if (option_verbose > 2)
2014 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2015 strncpy(c->exten, "t", sizeof(c->exten)-1);
2018 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2024 if (option_verbose > 2)
2025 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2029 if (option_verbose > 0) {
2031 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2034 if (option_verbose > 2)
2035 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2036 if (!strcasecmp(status, "CONGESTION"))
2037 res = pbx_builtin_congestion(c, "10");
2038 else if (!strcasecmp(status, "CHANUNAVAIL"))
2039 res = pbx_builtin_congestion(c, "10");
2040 else if (!strcasecmp(status, "BUSY"))
2041 res = pbx_builtin_busy(c, "10");
2048 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2050 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2054 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2055 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2056 /* Something bad happened, or a hangup has been requested. */
2058 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2059 else if (option_verbose > 1)
2060 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2067 pbx_destroy(c->pbx);
2069 if (res != AST_PBX_KEEPALIVE)
2074 static void *pbx_thread(void *data)
2076 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2077 answer this channel and get it going. The setjmp stuff is fairly
2078 confusing, but necessary to get smooth transitions between
2079 the execution of different applications (without the use of
2080 additional threads) */
2081 struct ast_channel *c = data;
2087 int ast_pbx_start(struct ast_channel *c)
2090 pthread_attr_t attr;
2092 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2096 /* Start a new thread, and get something handling this channel. */
2097 pthread_attr_init(&attr);
2098 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2099 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2100 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2106 int pbx_set_autofallthrough(int newval)
2109 oldval = autofallthrough;
2110 if (oldval != newval)
2111 autofallthrough = newval;
2116 * This function locks contexts list by &conlist, search for the right context
2117 * structure, leave context list locked and call ast_context_remove_include2
2118 * which removes include, unlock contexts list and return ...
2120 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2122 struct ast_context *c;
2124 if (ast_lock_contexts()) return -1;
2126 /* walk contexts and search for the right one ...*/
2127 c = ast_walk_contexts(NULL);
2129 /* we found one ... */
2130 if (!strcmp(ast_get_context_name(c), context)) {
2132 /* remove include from this context ... */
2133 ret = ast_context_remove_include2(c, include, registrar);
2135 ast_unlock_contexts();
2137 /* ... return results */
2140 c = ast_walk_contexts(c);
2143 /* we can't find the right one context */
2144 ast_unlock_contexts();
2149 * When we call this function, &conlock lock must be locked, because when
2150 * we giving *con argument, some process can remove/change this context
2151 * and after that there can be segfault.
2153 * This function locks given context, removes include, unlock context and
2156 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2158 struct ast_include *i, *pi = NULL;
2160 if (ast_mutex_lock(&con->lock)) return -1;
2165 /* find our include */
2166 if (!strcmp(i->name, include) &&
2167 (!registrar || !strcmp(i->registrar, registrar))) {
2168 /* remove from list */
2172 con->includes = i->next;
2173 /* free include and return */
2175 ast_mutex_unlock(&con->lock);
2182 /* we can't find the right include */
2183 ast_mutex_unlock(&con->lock);
2188 * This function locks contexts list by &conlist, search for the rigt context
2189 * structure, leave context list locked and call ast_context_remove_switch2
2190 * which removes switch, unlock contexts list and return ...
2192 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2194 struct ast_context *c;
2196 if (ast_lock_contexts()) return -1;
2198 /* walk contexts and search for the right one ...*/
2199 c = ast_walk_contexts(NULL);
2201 /* we found one ... */
2202 if (!strcmp(ast_get_context_name(c), context)) {
2204 /* remove switch from this context ... */
2205 ret = ast_context_remove_switch2(c, sw, data, registrar);
2207 ast_unlock_contexts();
2209 /* ... return results */
2212 c = ast_walk_contexts(c);
2215 /* we can't find the right one context */
2216 ast_unlock_contexts();
2221 * When we call this function, &conlock lock must be locked, because when
2222 * we giving *con argument, some process can remove/change this context
2223 * and after that there can be segfault.
2225 * This function locks given context, removes switch, unlock context and
2228 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2230 struct ast_sw *i, *pi = NULL;
2232 if (ast_mutex_lock(&con->lock)) return -1;
2237 /* find our switch */
2238 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2239 (!registrar || !strcmp(i->registrar, registrar))) {
2240 /* remove from list */
2244 con->alts = i->next;
2245 /* free switch and return */
2247 ast_mutex_unlock(&con->lock);
2254 /* we can't find the right switch */
2255 ast_mutex_unlock(&con->lock);
2260 * This functions lock contexts list, search for the right context,
2261 * call ast_context_remove_extension2, unlock contexts list and return.
2262 * In this function we are using
2264 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2266 struct ast_context *c;
2268 if (ast_lock_contexts()) return -1;
2270 /* walk contexts ... */
2271 c = ast_walk_contexts(NULL);
2273 /* ... search for the right one ... */
2274 if (!strcmp(ast_get_context_name(c), context)) {
2275 /* ... remove extension ... */
2276 int ret = ast_context_remove_extension2(c, extension, priority,
2278 /* ... unlock contexts list and return */
2279 ast_unlock_contexts();
2282 c = ast_walk_contexts(c);
2285 /* we can't find the right context */
2286 ast_unlock_contexts();
2291 * When do you want to call this function, make sure that &conlock is locked,
2292 * because some process can handle with your *con context before you lock
2295 * This functionc locks given context, search for the right extension and
2296 * fires out all peer in this extensions with given priority. If priority
2297 * is set to 0, all peers are removed. After that, unlock context and
2300 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2302 struct ast_exten *exten, *prev_exten = NULL;
2304 if (ast_mutex_lock(&con->lock)) return -1;
2306 /* go through all extensions in context and search the right one ... */
2310 /* look for right extension */
2311 if (!strcmp(exten->exten, extension) &&
2312 (!registrar || !strcmp(exten->registrar, registrar))) {
2313 struct ast_exten *peer;
2315 /* should we free all peers in this extension? (priority == 0)? */
2316 if (priority == 0) {
2317 /* remove this extension from context list */
2319 prev_exten->next = exten->next;
2321 con->root = exten->next;
2323 /* fire out all peers */
2328 if (!peer->priority==PRIORITY_HINT)
2329 ast_remove_hint(peer);
2331 peer->datad(peer->data);
2337 ast_mutex_unlock(&con->lock);
2340 /* remove only extension with exten->priority == priority */
2341 struct ast_exten *previous_peer = NULL;
2345 /* is this our extension? */
2346 if (peer->priority == priority &&
2347 (!registrar || !strcmp(peer->registrar, registrar) )) {
2348 /* we are first priority extension? */
2349 if (!previous_peer) {
2350 /* exists previous extension here? */
2352 /* yes, so we must change next pointer in
2353 * previous connection to next peer
2356 prev_exten->next = peer->peer;
2357 peer->peer->next = exten->next;
2359 prev_exten->next = exten->next;
2361 /* no previous extension, we are first
2362 * extension, so change con->root ...
2365 con->root = peer->peer;
2367 con->root = exten->next;
2370 /* we are not first priority in extension */
2371 previous_peer->peer = peer->peer;
2374 /* now, free whole priority extension */
2375 if (peer->priority==PRIORITY_HINT)
2376 ast_remove_hint(peer);
2377 peer->datad(peer->data);
2380 ast_mutex_unlock(&con->lock);
2383 /* this is not right extension, skip to next peer */
2384 previous_peer = peer;
2389 ast_mutex_unlock(&con->lock);
2395 exten = exten->next;
2398 /* we can't find right extension */
2399 ast_mutex_unlock(&con->lock);
2404 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2406 struct ast_app *tmp, *prev, *cur;
2409 length = sizeof(struct ast_app);
2410 length += strlen(app) + 1;
2411 if (ast_mutex_lock(&applock)) {
2412 ast_log(LOG_ERROR, "Unable to lock application list\n");
2417 if (!strcasecmp(app, tmp->name)) {
2418 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2419 ast_mutex_unlock(&applock);
2424 tmp = malloc(length);
2426 memset(tmp, 0, length);
2427 strcpy(tmp->name, app);
2428 tmp->execute = execute;
2429 tmp->synopsis = synopsis;
2430 tmp->description = description;
2431 /* Store in alphabetical order */
2435 if (strcasecmp(tmp->name, cur->name) < 0)
2441 tmp->next = prev->next;
2448 ast_log(LOG_ERROR, "Out of memory\n");
2449 ast_mutex_unlock(&applock);
2452 if (option_verbose > 1)
2453 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2454 ast_mutex_unlock(&applock);
2458 int ast_register_switch(struct ast_switch *sw)
2460 struct ast_switch *tmp, *prev=NULL;
2461 if (ast_mutex_lock(&switchlock)) {
2462 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2467 if (!strcasecmp(tmp->name, sw->name))
2473 ast_mutex_unlock(&switchlock);
2474 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2482 ast_mutex_unlock(&switchlock);
2486 void ast_unregister_switch(struct ast_switch *sw)
2488 struct ast_switch *tmp, *prev=NULL;
2489 if (ast_mutex_lock(&switchlock)) {
2490 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2497 prev->next = tmp->next;
2499 switches = tmp->next;
2506 ast_mutex_unlock(&switchlock);
2510 * Help for CLI commands ...
2512 static char show_application_help[] =
2513 "Usage: show application <application> [<application> [<application> [...]]]\n"
2514 " Describes a particular application.\n";
2516 static char show_applications_help[] =
2517 "Usage: show applications [{like|describing} <text>]\n"
2518 " List applications which are currently available.\n"
2519 " If 'like', <text> will be a substring of the app name\n"
2520 " If 'describing', <text> will be a substring of the description\n";
2522 static char show_dialplan_help[] =
2523 "Usage: show dialplan [exten@][context]\n"
2526 static char show_switches_help[] =
2527 "Usage: show switches\n"
2528 " Show registered switches\n";
2531 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2536 * 'show application' CLI command implementation functions ...
2540 * There is a possibility to show informations about more than one
2541 * application at one time. You can type 'show application Dial Echo' and
2542 * you will see informations about these two applications ...
2544 static char *complete_show_application(char *line, char *word,
2550 /* try to lock applications list ... */
2551 if (ast_mutex_lock(&applock)) {
2552 ast_log(LOG_ERROR, "Unable to lock application list\n");
2556 /* ... walk all applications ... */
2559 /* ... check if word matches this application ... */
2560 if (!strncasecmp(word, a->name, strlen(word))) {
2561 /* ... if this is right app serve it ... */
2562 if (++which > state) {
2563 char *ret = strdup(a->name);
2564 ast_mutex_unlock(&applock);
2571 /* no application match */
2572 ast_mutex_unlock(&applock);
2576 static int handle_show_application(int fd, int argc, char *argv[])
2579 int app, no_registered_app = 1;
2581 if (argc < 3) return RESULT_SHOWUSAGE;
2583 /* try to lock applications list ... */
2584 if (ast_mutex_lock(&applock)) {
2585 ast_log(LOG_ERROR, "Unable to lock application list\n");
2589 /* ... go through all applications ... */
2592 /* ... compare this application name with all arguments given
2593 * to 'show application' command ... */
2594 for (app = 2; app < argc; app++) {
2595 if (!strcasecmp(a->name, argv[app])) {
2596 /* Maximum number of characters added by terminal coloring is 22 */
2597 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2598 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2599 int synopsis_size, description_size;
2601 no_registered_app = 0;
2604 synopsis_size = strlen(a->synopsis) + 23;
2606 synopsis_size = strlen("Not available") + 23;
2607 synopsis = alloca(synopsis_size);
2610 description_size = strlen(a->description) + 23;
2612 description_size = strlen("Not available") + 23;
2613 description = alloca(description_size);
2615 if (synopsis && description) {
2616 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2617 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2618 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2619 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2620 term_color(synopsis,
2621 a->synopsis ? a->synopsis : "Not available",
2622 COLOR_CYAN, 0, synopsis_size);
2623 term_color(description,
2624 a->description ? a->description : "Not available",
2625 COLOR_CYAN, 0, description_size);
2627 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2629 /* ... one of our applications, show info ...*/
2630 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2631 "[Synopsis]:\n %s\n\n"
2632 "[Description]:\n%s\n",
2634 a->synopsis ? a->synopsis : "Not available",
2635 a->description ? a->description : "Not available");
2642 ast_mutex_unlock(&applock);
2644 /* we found at least one app? no? */
2645 if (no_registered_app) {
2646 ast_cli(fd, "Your application(s) is (are) not registered\n");
2647 return RESULT_FAILURE;
2650 return RESULT_SUCCESS;
2653 static int handle_show_switches(int fd, int argc, char *argv[])
2655 struct ast_switch *sw;
2657 ast_cli(fd, "There are no registered alternative switches\n");
2658 return RESULT_SUCCESS;
2660 /* ... we have applications ... */
2661 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2662 if (ast_mutex_lock(&switchlock)) {
2663 ast_log(LOG_ERROR, "Unable to lock switches\n");
2668 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2671 ast_mutex_unlock(&switchlock);
2672 return RESULT_SUCCESS;
2676 * 'show applications' CLI command implementation functions ...
2678 static int handle_show_applications(int fd, int argc, char *argv[])
2681 int like=0, describing=0;
2682 int total_match = 0; /* Number of matches in like clause */
2683 int total_apps = 0; /* Number of apps registered */
2685 /* try to lock applications list ... */
2686 if (ast_mutex_lock(&applock)) {
2687 ast_log(LOG_ERROR, "Unable to lock application list\n");
2691 /* ... have we got at least one application (first)? no? */
2693 ast_cli(fd, "There are no registered applications\n");
2694 ast_mutex_unlock(&applock);
2698 /* show applications like <keyword> */
2699 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2701 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2705 /* show applications describing <keyword1> [<keyword2>] [...] */
2706 if ((!like) && (!describing)) {
2707 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2709 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2712 /* ... go through all applications ... */
2713 for (a = apps; a; a = a->next) {
2714 /* ... show informations about applications ... */
2718 if (ast_strcasestr(a->name, argv[3])) {
2722 } else if (describing) {
2723 if (a->description) {
2724 /* Match all words on command line */
2727 for (i=3;i<argc;i++) {
2728 if (! ast_strcasestr(a->description, argv[i])) {
2740 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2743 if ((!like) && (!describing)) {
2744 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
2746 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
2749 /* ... unlock and return */
2750 ast_mutex_unlock(&applock);
2752 return RESULT_SUCCESS;
2755 static char *complete_show_applications(char *line, char *word, int pos, int state)
2758 if (ast_strlen_zero(word)) {
2761 return strdup("like");
2763 return strdup("describing");
2767 } else if (! strncasecmp(word, "like", strlen(word))) {
2769 return strdup("like");
2773 } else if (! strncasecmp(word, "describing", strlen(word))) {
2775 return strdup("describing");
2785 * 'show dialplan' CLI command implementation functions ...
2787 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2790 struct ast_context *c;
2793 /* we are do completion of [exten@]context on second position only */
2794 if (pos != 2) return NULL;
2796 /* try to lock contexts list ... */
2797 if (ast_lock_contexts()) {
2798 ast_log(LOG_ERROR, "Unable to lock context list\n");
2802 /* ... walk through all contexts ... */
2803 c = ast_walk_contexts(NULL);
2805 /* ... word matches context name? yes? ... */
2806 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2807 /* ... for serve? ... */
2808 if (++which > state) {
2809 /* ... yes, serve this context name ... */
2810 char *ret = strdup(ast_get_context_name(c));
2811 ast_unlock_contexts();
2815 c = ast_walk_contexts(c);
2818 /* ... unlock and return */
2819 ast_unlock_contexts();
2823 static int handle_show_dialplan(int fd, int argc, char *argv[])
2825 struct ast_context *c;
2826 char *exten = NULL, *context = NULL;
2827 int context_existence = 0, extension_existence = 0;
2829 if (argc != 3 && argc != 2) return -1;
2831 /* we obtain [exten@]context? if yes, split them ... */
2833 char *splitter = argv[2];
2834 /* is there a '@' character? */
2835 if (strchr(argv[2], '@')) {
2836 /* yes, split into exten & context ... */
2837 exten = strsep(&splitter, "@");
2840 /* check for length and change to NULL if ast_strlen_zero() */
2841 if (ast_strlen_zero(exten)) exten = NULL;
2842 if (ast_strlen_zero(context)) context = NULL;
2845 /* no '@' char, only context given */
2847 if (ast_strlen_zero(context)) context = NULL;
2851 /* try to lock contexts */
2852 if (ast_lock_contexts()) {
2853 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2854 return RESULT_FAILURE;
2857 /* walk all contexts ... */
2858 c = ast_walk_contexts(NULL);
2860 /* show this context? */
2862 !strcmp(ast_get_context_name(c), context)) {
2863 context_existence = 1;
2865 /* try to lock context before walking in ... */
2866 if (!ast_lock_context(c)) {
2867 struct ast_exten *e;
2868 struct ast_include *i;
2869 struct ast_ignorepat *ip;
2871 char buf[256], buf2[256];
2872 int context_info_printed = 0;
2874 /* are we looking for exten too? if yes, we print context
2875 * if we our extension only
2878 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2879 ast_get_context_name(c), ast_get_context_registrar(c));
2880 context_info_printed = 1;
2883 /* walk extensions ... */
2884 e = ast_walk_context_extensions(c, NULL);
2886 struct ast_exten *p;
2888 /* looking for extension? is this our extension? */
2890 strcmp(ast_get_extension_name(e), exten))
2892 /* we are looking for extension and it's not our
2893 * extension, so skip to next extension */
2894 e = ast_walk_context_extensions(c, e);
2898 extension_existence = 1;
2900 /* may we print context info? */
2901 if (!context_info_printed) {
2902 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2903 ast_get_context_name(c),
2904 ast_get_context_registrar(c));
2905 context_info_printed = 1;
2908 /* write extension name and first peer */
2909 bzero(buf, sizeof(buf));
2910 snprintf(buf, sizeof(buf), "'%s' =>",
2911 ast_get_extension_name(e));
2913 snprintf(buf2, sizeof(buf2),
2915 ast_get_extension_priority(e),
2916 ast_get_extension_app(e),
2917 (char *)ast_get_extension_app_data(e));
2919 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2920 ast_get_extension_registrar(e));
2922 /* walk next extension peers */
2923 p = ast_walk_extension_priorities(e, e);
2925 bzero((void *)buf2, sizeof(buf2));
2926 bzero((void *)buf, sizeof(buf));
2927 if (ast_get_extension_label(p))
2928 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
2929 snprintf(buf2, sizeof(buf2),
2931 ast_get_extension_priority(p),
2932 ast_get_extension_app(p),
2933 (char *)ast_get_extension_app_data(p));
2935 ast_cli(fd," %-17s %-45s [%s]\n",
2937 ast_get_extension_registrar(p));
2939 p = ast_walk_extension_priorities(e, p);
2941 e = ast_walk_context_extensions(c, e);
2944 /* include & ignorepat we all printing if we are not
2945 * looking for exact extension
2948 if (ast_walk_context_extensions(c, NULL))
2951 /* walk included and write info ... */
2952 i = ast_walk_context_includes(c, NULL);
2954 bzero(buf, sizeof(buf));
2955 snprintf(buf, sizeof(buf), "'%s'",
2956 ast_get_include_name(i));
2957 ast_cli(fd, " Include => %-45s [%s]\n",
2958 buf, ast_get_include_registrar(i));
2959 i = ast_walk_context_includes(c, i);
2962 /* walk ignore patterns and write info ... */
2963 ip = ast_walk_context_ignorepats(c, NULL);
2965 bzero(buf, sizeof(buf));
2966 snprintf(buf, sizeof(buf), "'%s'",
2967 ast_get_ignorepat_name(ip));
2968 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2969 buf, ast_get_ignorepat_registrar(ip));
2970 ip = ast_walk_context_ignorepats(c, ip);
2972 sw = ast_walk_context_switches(c, NULL);
2974 bzero(buf, sizeof(buf));
2975 snprintf(buf, sizeof(buf), "'%s/%s'",
2976 ast_get_switch_name(sw),