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;
139 struct ast_exten *exten;
141 struct ast_state_cb *callbacks;
142 struct ast_hint *next;
145 int ast_pbx_outgoing_cdr_failed(void);
147 static int pbx_builtin_prefix(struct ast_channel *, void *);
148 static int pbx_builtin_suffix(struct ast_channel *, void *);
149 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
150 static int pbx_builtin_answer(struct ast_channel *, void *);
151 static int pbx_builtin_goto(struct ast_channel *, void *);
152 static int pbx_builtin_hangup(struct ast_channel *, void *);
153 static int pbx_builtin_background(struct ast_channel *, void *);
154 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
155 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
156 static int pbx_builtin_atimeout(struct ast_channel *, void *);
157 static int pbx_builtin_wait(struct ast_channel *, void *);
158 static int pbx_builtin_waitexten(struct ast_channel *, void *);
159 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
160 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
161 static int pbx_builtin_setaccount(struct ast_channel *, void *);
162 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
163 static int pbx_builtin_ringing(struct ast_channel *, void *);
164 static int pbx_builtin_progress(struct ast_channel *, void *);
165 static int pbx_builtin_congestion(struct ast_channel *, void *);
166 static int pbx_builtin_busy(struct ast_channel *, void *);
167 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
168 static int pbx_builtin_noop(struct ast_channel *, void *);
169 static int pbx_builtin_gotoif(struct ast_channel *, void *);
170 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
171 static int pbx_builtin_saynumber(struct ast_channel *, void *);
172 static int pbx_builtin_saydigits(struct ast_channel *, void *);
173 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
174 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
175 int pbx_builtin_setvar(struct ast_channel *, void *);
176 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
177 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
179 static struct varshead globals;
181 static int autofallthrough = 0;
183 static struct pbx_builtin {
184 char name[AST_MAX_APP];
185 int (*execute)(struct ast_channel *chan, void *data);
190 /* These applications are built into the PBX core and do not
191 need separate modules
195 { "AbsoluteTimeout", pbx_builtin_atimeout,
196 "Set absolute maximum time of call",
197 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
198 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
201 { "Answer", pbx_builtin_answer,
202 "Answer a channel if ringing",
203 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
204 "Returns 0 unless it tries to answer the channel and fails.\n"
207 { "BackGround", pbx_builtin_background,
208 "Play a file while awaiting extension",
209 " Background(filename[|options[|langoverride]]): Plays a given file, while simultaneously\n"
210 "waiting for the user to begin typing an extension. The timeouts do not\n"
211 "count until the last BackGround application has ended.\n"
212 "Options may also be included following a pipe symbol. The 'skip'\n"
213 "option causes the playback of the message to be skipped if the channel\n"
214 "is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
215 "specified, the application will return immediately should the channel not be\n"
216 "off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
217 "be answered before the sound is played. Not all channels support playing\n"
218 "messages while still hook. The 'langoverride' may be a language to use for\n"
219 "playing the prompt which differs from the current language of the channel\n"
220 "Returns -1 if the channel was hung up, or if the file does not exist. \n"
221 "Returns 0 otherwise.\n"
224 { "Busy", pbx_builtin_busy,
225 "Indicate busy condition and stop",
226 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
227 "then waits for the user to hang up or the optional timeout to expire.\n"
231 { "Congestion", pbx_builtin_congestion,
232 "Indicate congestion and stop",
233 " Congestion([timeout]): Requests that the channel indicate congestion\n"
234 "and then waits for the user to hang up or for the optional timeout to\n"
235 "expire. Always returns -1."
238 { "DigitTimeout", pbx_builtin_dtimeout,
239 "Set maximum timeout between digits",
240 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
241 "digits when the user is typing in an extension. When this timeout expires,\n"
242 "after the user has started to type in an extension, the extension will be\n"
243 "considered complete, and will be interpreted. Note that if an extension\n"
244 "typed in is valid, it will not have to timeout to be tested, so typically\n"
245 "at the expiry of this timeout, the extension will be considered invalid\n"
246 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
247 "exist the call would be terminated). Always returns 0.\n"
250 { "Goto", pbx_builtin_goto,
251 "Goto a particular priority, extension, or context",
252 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
253 "value, optionally setting the extension and optionally the context as well.\n"
254 "The extension BYEXTENSION is special in that it uses the current extension,\n"
255 "thus permitting you to go to a different context, without specifying a\n"
256 "specific extension. Always returns 0, even if the given context, extension,\n"
257 "or priority is invalid.\n"
260 { "GotoIf", pbx_builtin_gotoif,
262 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
263 "true, to label2 if condition is false. Either label1 or label2 may be\n"
264 "omitted (in that case, we just don't take the particular branch) but not\n"
265 "both. Look for the condition syntax in examples or documentation."
268 { "GotoIfTime", pbx_builtin_gotoiftime,
269 "Conditional goto on current time",
270 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
271 "If the current time matches the specified time, then branch to the specified\n"
272 "extension. Each of the elements may be specified either as '*' (for always)\n"
273 "or as a range. See the 'include' syntax for details."
276 { "Hangup", pbx_builtin_hangup,
277 "Unconditional hangup",
278 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
281 { "NoOp", pbx_builtin_noop,
283 " NoOp(): No-operation; Does nothing."
286 { "Prefix", pbx_builtin_prefix,
287 "Prepend leading digits",
288 " Prefix(digits): Prepends the digit string specified by digits to the\n"
289 "channel's associated extension. For example, the number 1212 when prefixed\n"
290 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
291 "continue processing at the next priority for the *new* extension.\n"
292 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
293 "executed will be priority 4 of 5551212. If you switch into an extension\n"
294 "which has no first step, the PBX will treat it as though the user dialed an\n"
295 "invalid extension.\n"
298 { "Progress", pbx_builtin_progress,
300 " Progress(): Request that the channel indicate in-band progress is \n"
301 "available to the user.\nAlways returns 0.\n"
304 { "ResetCDR", pbx_builtin_resetcdr,
305 "Resets the Call Data Record",
306 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
307 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
308 "record WILL be stored.\nAlways returns 0.\n"
311 { "ResponseTimeout", pbx_builtin_rtimeout,
312 "Set maximum timeout awaiting response",
313 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
314 "falling through a series of priorities for a channel in which the user may\n"
315 "begin typing an extension. If the user does not type an extension in this\n"
316 "amount of time, control will pass to the 't' extension if it exists, and\n"
317 "if not the call would be terminated.\nAlways returns 0.\n"
320 { "Ringing", pbx_builtin_ringing,
321 "Indicate ringing tone",
322 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
323 "Always returns 0.\n"
326 { "SayNumber", pbx_builtin_saynumber,
328 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
329 "the current language setting for the channel. (See app SetLanguage).\n"
332 { "SayDigits", pbx_builtin_saydigits,
334 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
335 "current language setting for the channel. (See app setLanguage)\n"
338 { "SayAlpha", pbx_builtin_saycharacters,
340 " SayAlpha(string): Spells the passed string\n"
343 { "SayPhonetic", pbx_builtin_sayphonetic,
345 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
348 { "SetAccount", pbx_builtin_setaccount,
350 " SetAccount([account]): Set the channel account code for billing\n"
351 "purposes. Always returns 0.\n"
354 { "SetAMAFlags", pbx_builtin_setamaflags,
356 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
357 "purposes. Always returns 0.\n"
360 { "SetGlobalVar", pbx_builtin_setglobalvar,
361 "Set global variable to value",
362 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
363 "variable are available across channels.\n"
366 { "SetLanguage", pbx_builtin_setlanguage,
367 "Sets user language",
368 " SetLanguage(language): Set the channel language to 'language'. This\n"
369 "information is used for the syntax in generation of numbers, and to choose\n"
370 "a natural language file when available.\n"
371 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
372 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
373 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
374 "Always returns 0.\n"
377 { "SetVar", pbx_builtin_setvar,
378 "Set variable to value",
379 " SetVar(#n=value): Sets variable n to value. If prefixed with _, single\n"
380 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
382 { "StripMSD", pbx_builtin_stripmsd,
383 "Strip leading digits",
384 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
385 "associated extension. For example, the number 5551212 when stripped with a\n"
386 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
387 "will continue processing at the next priority for the *new* extension.\n"
388 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
389 "executed will be priority 4 of 1212. If you switch into an extension which\n"
390 "has no first step, the PBX will treat it as though the user dialed an\n"
391 "invalid extension.\n"
394 { "Suffix", pbx_builtin_suffix,
395 "Append trailing digits",
396 " Suffix(digits): Appends the digit string specified by digits to the\n"
397 "channel's associated extension. For example, the number 555 when suffixed\n"
398 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
399 "continue processing at the next priority for the *new* extension.\n"
400 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
401 "executed will be priority 4 of 5551212. If you switch into an extension\n"
402 "which has no first step, the PBX will treat it as though the user dialed an\n"
403 "invalid extension.\n"
406 { "Wait", pbx_builtin_wait,
407 "Waits for some time",
408 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
409 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
412 { "WaitExten", pbx_builtin_waitexten,
413 "Waits for some time",
414 " Wait([seconds]): Waits for the user to enter a new extension for the \n"
415 "specified number of seconds, then returns 0. Seconds can be passed with\n"
416 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
417 "default extension timeout will be used.\n"
422 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
423 static struct ast_context *contexts = NULL;
424 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
425 static struct ast_app *apps = NULL;
427 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
428 struct ast_switch *switches = NULL;
430 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
431 static int stateid = 1;
432 struct ast_hint *hints = NULL;
433 struct ast_state_cb *statecbs = NULL;
435 int pbx_exec(struct ast_channel *c, /* Channel */
436 struct ast_app *app, /* Application */
437 void *data, /* Data for execution */
438 int newstack) /* Force stack increment */
440 /* This function is special. It saves the stack so that no matter
441 how many times it is called, it returns to the same place */
447 int stack = c->stack;
448 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
450 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
451 /* Don't allow us to go over the max number of stacks we
453 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
456 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
457 /* Okay, here's where it gets weird. If newstack is non-zero,
458 then we increase the stack increment, but setjmp is not going
459 to return until longjmp is called -- when the application
460 exec'd is finished running. */
463 if (c->stack != stack + 1)
464 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
465 else if (c->app[c->stack])
466 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
471 ast_cdr_setapp(c->cdr, app->name, data);
473 /* save channel values */
474 saved_c_appl= c->appl;
475 saved_c_data= c->data;
479 res = execute(c, data);
480 /* restore channel values */
481 c->appl= saved_c_appl;
482 c->data= saved_c_data;
484 /* Any application that returns, we longjmp back, just in case. */
485 if (c->stack != stack + 1)
486 ast_log(LOG_WARNING, "Stack is not at expected value\n");
487 longjmp(c->jmp[stack+1], res);
493 /* Go no deeper than this through includes (not counting loops) */
494 #define AST_PBX_MAX_STACK 64
496 #define HELPER_EXISTS 0
497 #define HELPER_SPAWN 1
498 #define HELPER_EXEC 2
499 #define HELPER_CANMATCH 3
500 #define HELPER_MATCHMORE 4
501 #define HELPER_FINDLABEL 5
503 struct ast_app *pbx_findapp(const char *app)
507 if (ast_mutex_lock(&applock)) {
508 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
513 if (!strcasecmp(tmp->name, app))
517 ast_mutex_unlock(&applock);
521 static struct ast_switch *pbx_findswitch(const char *sw)
523 struct ast_switch *asw;
525 if (ast_mutex_lock(&switchlock)) {
526 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
531 if (!strcasecmp(asw->name, sw))
535 ast_mutex_unlock(&switchlock);
539 static inline int include_valid(struct ast_include *i)
544 return ast_check_timing(&(i->timing));
547 static void pbx_destroy(struct ast_pbx *p)
552 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
553 /* All patterns begin with _ */\
554 if (pattern[0] != '_') \
556 /* Start optimistic */\
559 while(match && *data && *pattern && (*pattern != '/')) {\
560 switch(toupper(*pattern)) {\
567 where=strchr(pattern,']');\
569 border=(int)(where-pattern);\
570 if (!where || border > strlen(pattern)) {\
571 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
574 for (i=0; i<border; i++) {\
577 if (pattern[i+1]=='-') {\
578 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
585 if (res==1 || *data==pattern[i]) {\
594 if ((*data < '2') || (*data > '9'))\
598 if ((*data < '0') || (*data > '9'))\
602 if ((*data < '1') || (*data > '9'))\
610 /* Ignore these characters */\
614 if (*data != *pattern)\
622 int ast_extension_match(const char *pattern, const char *data)
625 /* If they're the same return */
626 if (!strcmp(pattern, data))
628 EXTENSION_MATCH_CORE(data,pattern,match);
629 /* Must be at the end of both */
630 if (*data || (*pattern && (*pattern != '/')))
635 static int extension_close(const char *pattern, const char *data, int needmore)
638 /* If "data" is longer, it can'be a subset of pattern unless
639 pattern is a pattern match */
640 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
643 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
644 (!needmore || (strlen(pattern) > strlen(data)))) {
647 EXTENSION_MATCH_CORE(data,pattern,match);
648 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
649 if (!needmore || *pattern) {
655 struct ast_context *ast_context_find(const char *name)
657 struct ast_context *tmp;
658 ast_mutex_lock(&conlock);
662 if (!strcasecmp(name, tmp->name))
668 ast_mutex_unlock(&conlock);
672 #define STATUS_NO_CONTEXT 1
673 #define STATUS_NO_EXTENSION 2
674 #define STATUS_NO_PRIORITY 3
675 #define STATUS_NO_LABEL 4
676 #define STATUS_SUCCESS 5
678 static int matchcid(const char *cidpattern, const char *callerid)
682 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
683 failing to get a number should count as a match, otherwise not */
686 if (!ast_strlen_zero(cidpattern))
694 return ast_extension_match(cidpattern, callerid);
697 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)
700 struct ast_context *tmp;
701 struct ast_exten *e, *eroot;
702 struct ast_include *i;
704 struct ast_switch *asw;
706 /* Initialize status if appropriate */
708 *status = STATUS_NO_CONTEXT;
712 /* Check for stack overflow */
713 if (*stacklen >= AST_PBX_MAX_STACK) {
714 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
717 /* Check first to see if we've already been checked */
718 for (x=0;x<*stacklen;x++) {
719 if (!strcasecmp(incstack[x], context))
728 if (bypass || !strcmp(tmp->name, context)) {
729 if (*status < STATUS_NO_EXTENSION)
730 *status = STATUS_NO_EXTENSION;
733 /* Match extension */
734 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
735 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
736 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
737 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
739 if (*status < STATUS_NO_PRIORITY)
740 *status = STATUS_NO_PRIORITY;
743 if (action == HELPER_FINDLABEL) {
744 if (*status < STATUS_NO_LABEL)
745 *status = STATUS_NO_LABEL;
746 if (label && e->label && !strcmp(label, e->label)) {
747 *status = STATUS_SUCCESS;
750 } else if (e->priority == priority) {
751 *status = STATUS_SUCCESS;
759 /* Check alternative switches */
762 if ((asw = pbx_findswitch(sw->name))) {
763 if (action == HELPER_CANMATCH)
764 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
765 else if (action == HELPER_MATCHMORE)
766 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
768 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
776 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
780 /* Setup the stack */
781 incstack[*stacklen] = tmp->name;
783 /* Now try any includes we have in this context */
786 if (include_valid(i)) {
787 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data)))
801 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
804 char tmpvar[80] = "";
806 struct tm brokentime;
808 struct ast_var_t *variables;
813 /* Now we have the variable name on cp3 */
814 if (!strncasecmp(var,"LEN(",4)) {
817 if (strrchr(var,')')) {
819 strncpy(cp3, var, sizeof(cp3) - 1);
820 cp3[len-len_len-1]='\0';
821 sprintf(workspace,"%d",(int)strlen(cp3));
827 } else if ((first=strchr(var,':'))) {
828 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
829 first = strchr(tmpvar, ':');
831 first = tmpvar + strlen(tmpvar);
833 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1, headp);
835 offset=atoi(first+1);
836 if ((second=strchr(first+1,':'))) {
838 offset2=atoi(second+1);
840 offset2=strlen(*ret)-offset;
841 if (abs(offset)>strlen(*ret)) {
845 offset=-strlen(*ret);
847 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
849 offset2=strlen(*ret)-offset;
851 offset2=strlen(*ret)+offset;
856 *ret+=strlen(*ret)+offset;
857 (*ret)[offset2] = '\0';
858 } else if (c && !strcmp(var, "CALLERIDNUM")) {
859 if (c->cid.cid_num) {
860 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
864 } else if (c && !strcmp(var, "CALLERANI")) {
865 if (c->cid.cid_ani) {
866 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
870 } else if (c && !strcmp(var, "CALLERIDNAME")) {
871 if (c->cid.cid_name) {
872 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
876 } else if (c && !strcmp(var, "CALLERID")) {
877 if (c->cid.cid_num) {
878 if (c->cid.cid_name) {
879 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
881 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
884 } else if (c->cid.cid_name) {
885 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
889 } else if (c && !strcmp(var, "DNID")) {
890 if (c->cid.cid_dnid) {
891 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
895 } else if (c && !strcmp(var, "HINT")) {
896 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
900 } else if (c && !strcmp(var, "EXTEN")) {
901 strncpy(workspace, c->exten, workspacelen - 1);
903 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
904 /* XXX Remove me eventually */
905 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
908 if (offset > strlen(c->exten))
909 offset = strlen(c->exten);
910 strncpy(workspace, c->exten + offset, workspacelen - 1);
912 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
913 } else if (c && !strcmp(var, "RDNIS")) {
914 if (c->cid.cid_rdnis) {
915 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
919 } else if (c && !strcmp(var, "CONTEXT")) {
920 strncpy(workspace, c->context, workspacelen - 1);
922 } else if (c && !strcmp(var, "PRIORITY")) {
923 snprintf(workspace, workspacelen, "%d", c->priority);
925 } else if (c && !strcmp(var, "CALLINGPRES")) {
926 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
928 } else if (c && !strcmp(var, "CALLINGANI2")) {
929 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
931 } else if (c && !strcmp(var, "CALLINGTON")) {
932 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
934 } else if (c && !strcmp(var, "CALLINGTNS")) {
935 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
937 } else if (c && !strcmp(var, "CHANNEL")) {
938 strncpy(workspace, c->name, workspacelen - 1);
940 } else if (c && !strcmp(var, "EPOCH")) {
941 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
943 } else if (c && !strcmp(var, "DATETIME")) {
945 localtime_r(&thistime, &brokentime);
946 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
949 brokentime.tm_year+1900,
955 } else if (c && !strcmp(var, "TIMESTAMP")) {
957 localtime_r(&thistime, &brokentime);
958 /* 20031130-150612 */
959 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
960 brokentime.tm_year+1900,
968 } else if (c && !strcmp(var, "UNIQUEID")) {
969 snprintf(workspace, workspacelen, "%s", c->uniqueid);
971 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
972 snprintf(workspace, workspacelen, "%i", c->hangupcause);
974 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
975 strncpy(workspace, c->accountcode, workspacelen - 1);
977 } else if (c && !strcmp(var, "LANGUAGE")) {
978 strncpy(workspace, c->language, workspacelen - 1);
982 AST_LIST_TRAVERSE(headp,variables,entries) {
984 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
986 if (strcasecmp(ast_var_name(variables),var)==0) {
987 *ret=ast_var_value(variables);
989 strncpy(workspace, *ret, workspacelen - 1);
998 AST_LIST_TRAVERSE(&globals,variables,entries) {
1000 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1002 if (strcasecmp(ast_var_name(variables),var)==0) {
1003 *ret=ast_var_value(variables);
1005 strncpy(workspace, *ret, workspacelen - 1);
1012 int len=strlen(var);
1013 int len_env=strlen("ENV(");
1014 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1016 strncpy(cp3, var, sizeof(cp3) - 1);
1018 *ret=getenv(cp3+len_env);
1020 strncpy(workspace, *ret, workspacelen - 1);
1028 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1031 const char *tmp, *whereweare;
1033 char workspace[4096];
1034 char ltmp[4096], var[4096];
1035 char *nextvar, *nextexp;
1037 int pos, brackets, needsub, len;
1039 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1042 while(!ast_strlen_zero(whereweare) && count) {
1043 /* Assume we're copying the whole remaining string */
1044 pos = strlen(whereweare);
1046 /* Look for a variable */
1047 nextvar = strstr(whereweare, "${");
1049 /* Look for an expression */
1050 nextexp = strstr(whereweare, "$[");
1052 /* Pick the first one only */
1053 if (nextvar && nextexp) {
1054 if (nextvar < nextexp)
1060 /* If there is one, we only go that far */
1062 pos = nextvar - whereweare;
1064 pos = nextexp - whereweare;
1066 /* Can't copy more than 'count' bytes */
1070 /* Copy that many bytes */
1071 memcpy(cp2, whereweare, pos);
1078 /* We have a variable. Find the start and end, and determine
1079 if we are going to have to recursively call ourselves on the
1081 vars = vare = nextvar + 2;
1085 /* Find the end of it */
1086 while(brackets && *vare) {
1087 if ((vare[0] == '$') && (vare[1] == '{')) {
1090 } else if (vare[0] == '}') {
1092 } else if ((vare[0] == '$') && (vare[1] == '['))
1097 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1098 len = vare - vars - 1;
1100 /* Skip totally over variable name */
1101 whereweare += ( len + 3);
1103 /* Store variable name (and truncate) */
1104 memset(var, 0, sizeof(var));
1105 strncpy(var, vars, sizeof(var) - 1);
1108 /* Substitute if necessary */
1110 memset(ltmp, 0, sizeof(ltmp));
1111 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1117 /* Retrieve variable value */
1118 workspace[0] = '\0';
1119 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace), headp);
1121 length = strlen(cp4);
1124 memcpy(cp2, cp4, length);
1129 } else if (nextexp) {
1130 /* We have an expression. Find the start and end, and determine
1131 if we are going to have to recursively call ourselves on the
1133 vars = vare = nextexp + 2;
1137 /* Find the end of it */
1138 while(brackets && *vare) {
1139 if ((vare[0] == '$') && (vare[1] == '[')) {
1143 } else if (vare[0] == '[') {
1145 } else if (vare[0] == ']') {
1147 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1154 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1155 len = vare - vars - 1;
1157 /* Skip totally over variable name */
1158 whereweare += ( len + 3);
1160 /* Store variable name (and truncate) */
1161 memset(var, 0, sizeof(var));
1162 strncpy(var, vars, sizeof(var) - 1);
1165 /* Substitute if necessary */
1167 memset(ltmp, 0, sizeof(ltmp));
1168 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1174 /* Evaluate expression */
1175 cp4 = ast_expr(vars);
1177 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1180 length = strlen(cp4);
1183 memcpy(cp2, cp4, length);
1194 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1196 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1199 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1201 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1204 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1206 memset(passdata, 0, datalen);
1208 /* No variables or expressions in e->data, so why scan it? */
1209 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1210 strncpy(passdata, e->data, datalen - 1);
1211 passdata[datalen-1] = '\0';
1215 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1218 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)
1220 struct ast_exten *e;
1221 struct ast_app *app;
1222 struct ast_switch *sw;
1227 char *incstack[AST_PBX_MAX_STACK];
1228 char passdata[EXT_DATA_SIZE];
1232 char tmp3[EXT_DATA_SIZE];
1234 if (ast_mutex_lock(&conlock)) {
1235 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1236 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1241 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data);
1244 case HELPER_CANMATCH:
1245 ast_mutex_unlock(&conlock);
1248 ast_mutex_unlock(&conlock);
1250 case HELPER_FINDLABEL:
1252 ast_mutex_unlock(&conlock);
1254 case HELPER_MATCHMORE:
1255 ast_mutex_unlock(&conlock);
1261 app = pbx_findapp(e->app);
1262 ast_mutex_unlock(&conlock);
1264 if (c->context != context)
1265 strncpy(c->context, context, sizeof(c->context)-1);
1266 if (c->exten != exten)
1267 strncpy(c->exten, exten, sizeof(c->exten)-1);
1268 c->priority = priority;
1269 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1271 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1272 if (option_verbose > 2)
1273 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1274 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1275 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1276 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1277 (newstack ? "in new stack" : "in same stack"));
1278 manager_event(EVENT_FLAG_CALL, "Newexten",
1283 "Application: %s\r\n"
1286 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1287 res = pbx_exec(c, app, passdata, newstack);
1290 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1294 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1298 case HELPER_CANMATCH:
1299 ast_mutex_unlock(&conlock);
1302 ast_mutex_unlock(&conlock);
1304 case HELPER_MATCHMORE:
1305 ast_mutex_unlock(&conlock);
1307 case HELPER_FINDLABEL:
1308 ast_mutex_unlock(&conlock);
1314 ast_mutex_unlock(&conlock);
1316 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1318 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1323 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1327 ast_mutex_unlock(&conlock);
1329 case STATUS_NO_CONTEXT:
1330 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1331 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1333 case STATUS_NO_EXTENSION:
1334 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1335 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1337 case STATUS_NO_PRIORITY:
1338 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1339 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1341 case STATUS_NO_LABEL:
1343 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1346 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1349 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1357 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1359 struct ast_exten *e;
1360 struct ast_switch *sw;
1363 char *incstack[AST_PBX_MAX_STACK];
1366 if (ast_mutex_lock(&conlock)) {
1367 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1370 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1371 ast_mutex_unlock(&conlock);
1375 static int ast_extension_state2(struct ast_exten *e)
1377 char hint[AST_MAX_EXTENSION] = "";
1380 int allunavailable = 1, allbusy = 1, allfree = 1;
1383 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1387 rest = strchr(cur, '&');
1393 res = ast_device_state(cur);
1395 case AST_DEVICE_NOT_INUSE:
1399 case AST_DEVICE_INUSE:
1400 return AST_EXTENSION_INUSE;
1401 case AST_DEVICE_BUSY:
1406 case AST_DEVICE_UNAVAILABLE:
1407 case AST_DEVICE_INVALID:
1420 return AST_EXTENSION_NOT_INUSE;
1422 return AST_EXTENSION_BUSY;
1424 return AST_EXTENSION_UNAVAILABLE;
1426 return AST_EXTENSION_INUSE;
1428 return AST_EXTENSION_NOT_INUSE;
1432 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1434 struct ast_exten *e;
1436 e = ast_hint_extension(c, context, exten);
1440 return ast_extension_state2(e);
1443 int ast_device_state_changed(const char *fmt, ...)
1445 struct ast_hint *list;
1446 struct ast_state_cb *cblist;
1447 char hint[AST_MAX_EXTENSION] = "";
1448 char device[AST_MAX_EXTENSION];
1455 vsnprintf(device, sizeof(device), fmt, ap);
1458 rest = strchr(device, '-');
1463 ast_mutex_lock(&hintlock);
1469 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1472 rest = strchr(cur, '&');
1478 if (!strcmp(cur, device)) {
1479 /* Found extension execute callbacks */
1480 state = ast_extension_state2(list->exten);
1481 if ((state != -1) && (state != list->laststate)) {
1482 /* For general callbacks */
1485 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1486 cblist = cblist->next;
1489 /* For extension callbacks */
1490 cblist = list->callbacks;
1492 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1493 cblist = cblist->next;
1496 list->laststate = state;
1504 ast_mutex_unlock(&hintlock);
1508 int ast_extension_state_add(const char *context, const char *exten,
1509 ast_state_cb_type callback, void *data)
1511 struct ast_hint *list;
1512 struct ast_state_cb *cblist;
1513 struct ast_exten *e;
1515 /* No context and extension add callback to statecbs list */
1516 if (!context && !exten) {
1517 ast_mutex_lock(&hintlock);
1521 if (cblist->callback == callback) {
1522 cblist->data = data;
1523 ast_mutex_unlock(&hintlock);
1525 cblist = cblist->next;
1528 /* Now inserts the callback */
1529 cblist = malloc(sizeof(struct ast_state_cb));
1531 ast_mutex_unlock(&hintlock);
1534 memset(cblist, 0, sizeof(struct ast_state_cb));
1536 cblist->callback = callback;
1537 cblist->data = data;
1539 cblist->next = statecbs;
1542 ast_mutex_unlock(&hintlock);
1546 if (!context || !exten)
1549 /* This callback type is for only one hint */
1550 e = ast_hint_extension(NULL, context, exten);
1555 ast_mutex_lock(&hintlock);
1559 if (list->exten == e)
1565 ast_mutex_unlock(&hintlock);
1569 /* Now inserts the callback */
1570 cblist = malloc(sizeof(struct ast_state_cb));
1572 ast_mutex_unlock(&hintlock);
1575 memset(cblist, 0, sizeof(struct ast_state_cb));
1576 cblist->id = stateid++;
1577 cblist->callback = callback;
1578 cblist->data = data;
1580 cblist->next = list->callbacks;
1581 list->callbacks = cblist;
1583 ast_mutex_unlock(&hintlock);
1587 int ast_extension_state_del(int id, ast_state_cb_type callback)
1589 struct ast_hint *list;
1590 struct ast_state_cb *cblist, *cbprev;
1592 if (!id && !callback)
1595 ast_mutex_lock(&hintlock);
1597 /* id is zero is a callback without extension */
1602 if (cblist->callback == callback) {
1604 statecbs = cblist->next;
1606 cbprev->next = cblist->next;
1610 ast_mutex_unlock(&hintlock);
1614 cblist = cblist->next;
1617 ast_mutex_lock(&hintlock);
1621 /* id greater than zero is a callback with extension */
1624 cblist = list->callbacks;
1627 if (cblist->id==id) {
1629 list->callbacks = cblist->next;
1631 cbprev->next = cblist->next;
1635 ast_mutex_unlock(&hintlock);
1639 cblist = cblist->next;
1644 ast_mutex_unlock(&hintlock);
1648 static int ast_add_hint(struct ast_exten *e)
1650 struct ast_hint *list;
1655 ast_mutex_lock(&hintlock);
1658 /* Search if hint exists, do nothing */
1660 if (list->exten == e) {
1661 ast_mutex_unlock(&hintlock);
1667 list = malloc(sizeof(struct ast_hint));
1669 ast_mutex_unlock(&hintlock);
1672 /* Initialize and insert new item */
1673 memset(list, 0, sizeof(struct ast_hint));
1675 list->laststate = ast_extension_state2(e);
1679 ast_mutex_unlock(&hintlock);
1683 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1685 struct ast_hint *list;
1687 ast_mutex_lock(&hintlock);
1691 if (list->exten == oe) {
1693 ast_mutex_unlock(&hintlock);
1698 ast_mutex_unlock(&hintlock);
1703 static int ast_remove_hint(struct ast_exten *e)
1705 /* Cleanup the Notifys if hint is removed */
1706 struct ast_hint *list, *prev = NULL;
1707 struct ast_state_cb *cblist, *cbprev;
1712 ast_mutex_lock(&hintlock);
1716 if (list->exten==e) {
1718 cblist = list->callbacks;
1720 /* Notify with -1 and remove all callbacks */
1722 cblist = cblist->next;
1723 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1726 list->callbacks = NULL;
1731 prev->next = list->next;
1734 ast_mutex_unlock(&hintlock);
1742 ast_mutex_unlock(&hintlock);
1747 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1749 struct ast_exten *e;
1750 e = ast_hint_extension(c, context, exten);
1752 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1758 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1760 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1763 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1765 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1768 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1770 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1773 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1775 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1778 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1780 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1783 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1785 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1788 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1790 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1793 int ast_pbx_run(struct ast_channel *c)
1802 /* A little initial setup here */
1804 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1805 c->pbx = malloc(sizeof(struct ast_pbx));
1807 ast_log(LOG_ERROR, "Out of memory\n");
1812 c->cdr = ast_cdr_alloc();
1814 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1818 ast_cdr_init(c->cdr, c);
1821 memset(c->pbx, 0, sizeof(struct ast_pbx));
1822 /* Set reasonable defaults */
1823 c->pbx->rtimeout = 10;
1824 c->pbx->dtimeout = 5;
1826 /* Start by trying whatever the channel is set to */
1827 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1828 /* JK02: If not successfull fall back to 's' */
1829 if (option_verbose > 1)
1830 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);
1831 strncpy(c->exten, "s", sizeof(c->exten)-1);
1832 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1833 /* JK02: And finally back to default if everything else failed */
1834 if (option_verbose > 1)
1835 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);
1836 strncpy(c->context, "default", sizeof(c->context)-1);
1840 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1841 ast_cdr_start(c->cdr);
1845 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1846 memset(exten, 0, sizeof(exten));
1847 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1848 /* Something bad happened, or a hangup has been requested. */
1849 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1850 (res == '*') || (res == '#')) {
1851 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1852 memset(exten, 0, sizeof(exten));
1854 exten[pos++] = digit = res;
1858 case AST_PBX_KEEPALIVE:
1860 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1861 else if (option_verbose > 1)
1862 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1867 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1868 else if (option_verbose > 1)
1869 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1870 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1875 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1885 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1886 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1887 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1888 c->whentohangup = 0;
1890 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1891 } else if (c->_softhangup) {
1892 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1893 c->exten, c->priority);
1899 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1900 /* It's not a valid extension anymore */
1901 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1902 if (option_verbose > 2)
1903 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1904 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1905 strncpy(c->exten, "i", sizeof(c->exten)-1);
1908 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1909 c->name, c->exten, c->context);
1912 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1913 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1916 /* Done, wait for an extension */
1919 waittime = c->pbx->dtimeout;
1920 else if (!autofallthrough)
1921 waittime = c->pbx->rtimeout;
1923 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1924 /* As long as we're willing to wait, and as long as it's not defined,
1925 keep reading digits until we can't possibly get a right answer anymore. */
1926 digit = ast_waitfordigit(c, waittime * 1000);
1927 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1934 /* Error, maybe a hangup */
1936 exten[pos++] = digit;
1937 waittime = c->pbx->dtimeout;
1940 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1941 /* Prepare the next cycle */
1942 strncpy(c->exten, exten, sizeof(c->exten)-1);
1945 /* No such extension */
1946 if (!ast_strlen_zero(exten)) {
1947 /* An invalid extension */
1948 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1949 if (option_verbose > 2)
1950 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1951 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1952 strncpy(c->exten, "i", sizeof(c->exten)-1);
1955 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
1959 /* A simple timeout */
1960 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
1961 if (option_verbose > 2)
1962 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1963 strncpy(c->exten, "t", sizeof(c->exten)-1);
1966 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1972 if (option_verbose > 2)
1973 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1977 if (option_verbose > 0) {
1979 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
1982 if (option_verbose > 2)
1983 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
1984 if (!strcasecmp(status, "CONGESTION"))
1985 res = pbx_builtin_congestion(c, "10");
1986 else if (!strcasecmp(status, "CHANUNAVAIL"))
1987 res = pbx_builtin_congestion(c, "10");
1988 else if (!strcasecmp(status, "BUSY"))
1989 res = pbx_builtin_busy(c, "10");
1996 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1998 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2002 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2003 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2004 /* Something bad happened, or a hangup has been requested. */
2006 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2007 else if (option_verbose > 1)
2008 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2015 pbx_destroy(c->pbx);
2017 if (res != AST_PBX_KEEPALIVE)
2022 static void *pbx_thread(void *data)
2024 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2025 answer this channel and get it going. The setjmp stuff is fairly
2026 confusing, but necessary to get smooth transitions between
2027 the execution of different applications (without the use of
2028 additional threads) */
2029 struct ast_channel *c = data;
2035 int ast_pbx_start(struct ast_channel *c)
2038 pthread_attr_t attr;
2040 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2044 /* Start a new thread, and get something handling this channel. */
2045 pthread_attr_init(&attr);
2046 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2047 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2048 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2054 int pbx_set_autofallthrough(int newval)
2057 oldval = autofallthrough;
2058 if (oldval != newval)
2059 autofallthrough = newval;
2064 * This function locks contexts list by &conlist, search for the right context
2065 * structure, leave context list locked and call ast_context_remove_include2
2066 * which removes include, unlock contexts list and return ...
2068 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2070 struct ast_context *c;
2072 if (ast_lock_contexts()) return -1;
2074 /* walk contexts and search for the right one ...*/
2075 c = ast_walk_contexts(NULL);
2077 /* we found one ... */
2078 if (!strcmp(ast_get_context_name(c), context)) {
2080 /* remove include from this context ... */
2081 ret = ast_context_remove_include2(c, include, registrar);
2083 ast_unlock_contexts();
2085 /* ... return results */
2088 c = ast_walk_contexts(c);
2091 /* we can't find the right one context */
2092 ast_unlock_contexts();
2097 * When we call this function, &conlock lock must be locked, because when
2098 * we giving *con argument, some process can remove/change this context
2099 * and after that there can be segfault.
2101 * This function locks given context, removes include, unlock context and
2104 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2106 struct ast_include *i, *pi = NULL;
2108 if (ast_mutex_lock(&con->lock)) return -1;
2113 /* find our include */
2114 if (!strcmp(i->name, include) &&
2115 (!registrar || !strcmp(i->registrar, registrar))) {
2116 /* remove from list */
2120 con->includes = i->next;
2121 /* free include and return */
2123 ast_mutex_unlock(&con->lock);
2130 /* we can't find the right include */
2131 ast_mutex_unlock(&con->lock);
2136 * This function locks contexts list by &conlist, search for the rigt context
2137 * structure, leave context list locked and call ast_context_remove_switch2
2138 * which removes switch, unlock contexts list and return ...
2140 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2142 struct ast_context *c;
2144 if (ast_lock_contexts()) return -1;
2146 /* walk contexts and search for the right one ...*/
2147 c = ast_walk_contexts(NULL);
2149 /* we found one ... */
2150 if (!strcmp(ast_get_context_name(c), context)) {
2152 /* remove switch from this context ... */
2153 ret = ast_context_remove_switch2(c, sw, data, registrar);
2155 ast_unlock_contexts();
2157 /* ... return results */
2160 c = ast_walk_contexts(c);
2163 /* we can't find the right one context */
2164 ast_unlock_contexts();
2169 * When we call this function, &conlock lock must be locked, because when
2170 * we giving *con argument, some process can remove/change this context
2171 * and after that there can be segfault.
2173 * This function locks given context, removes switch, unlock context and
2176 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2178 struct ast_sw *i, *pi = NULL;
2180 if (ast_mutex_lock(&con->lock)) return -1;
2185 /* find our switch */
2186 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2187 (!registrar || !strcmp(i->registrar, registrar))) {
2188 /* remove from list */
2192 con->alts = i->next;
2193 /* free switch and return */
2195 ast_mutex_unlock(&con->lock);
2202 /* we can't find the right switch */
2203 ast_mutex_unlock(&con->lock);
2208 * This functions lock contexts list, search for the right context,
2209 * call ast_context_remove_extension2, unlock contexts list and return.
2210 * In this function we are using
2212 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2214 struct ast_context *c;
2216 if (ast_lock_contexts()) return -1;
2218 /* walk contexts ... */
2219 c = ast_walk_contexts(NULL);
2221 /* ... search for the right one ... */
2222 if (!strcmp(ast_get_context_name(c), context)) {
2223 /* ... remove extension ... */
2224 int ret = ast_context_remove_extension2(c, extension, priority,
2226 /* ... unlock contexts list and return */
2227 ast_unlock_contexts();
2230 c = ast_walk_contexts(c);
2233 /* we can't find the right context */
2234 ast_unlock_contexts();
2239 * When do you want to call this function, make sure that &conlock is locked,
2240 * because some process can handle with your *con context before you lock
2243 * This functionc locks given context, search for the right extension and
2244 * fires out all peer in this extensions with given priority. If priority
2245 * is set to 0, all peers are removed. After that, unlock context and
2248 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2250 struct ast_exten *exten, *prev_exten = NULL;
2252 if (ast_mutex_lock(&con->lock)) return -1;
2254 /* go through all extensions in context and search the right one ... */
2258 /* look for right extension */
2259 if (!strcmp(exten->exten, extension) &&
2260 (!registrar || !strcmp(exten->registrar, registrar))) {
2261 struct ast_exten *peer;
2263 /* should we free all peers in this extension? (priority == 0)? */
2264 if (priority == 0) {
2265 /* remove this extension from context list */
2267 prev_exten->next = exten->next;
2269 con->root = exten->next;
2271 /* fire out all peers */
2276 if (!peer->priority==PRIORITY_HINT)
2277 ast_remove_hint(peer);
2279 peer->datad(peer->data);
2285 ast_mutex_unlock(&con->lock);
2288 /* remove only extension with exten->priority == priority */
2289 struct ast_exten *previous_peer = NULL;
2293 /* is this our extension? */
2294 if (peer->priority == priority &&
2295 (!registrar || !strcmp(peer->registrar, registrar) )) {
2296 /* we are first priority extension? */
2297 if (!previous_peer) {
2298 /* exists previous extension here? */
2300 /* yes, so we must change next pointer in
2301 * previous connection to next peer
2304 prev_exten->next = peer->peer;
2305 peer->peer->next = exten->next;
2307 prev_exten->next = exten->next;
2309 /* no previous extension, we are first
2310 * extension, so change con->root ...
2313 con->root = peer->peer;
2315 con->root = exten->next;
2318 /* we are not first priority in extension */
2319 previous_peer->peer = peer->peer;
2322 /* now, free whole priority extension */
2323 if (peer->priority==PRIORITY_HINT)
2324 ast_remove_hint(peer);
2325 peer->datad(peer->data);
2328 ast_mutex_unlock(&con->lock);
2331 /* this is not right extension, skip to next peer */
2332 previous_peer = peer;
2337 ast_mutex_unlock(&con->lock);
2343 exten = exten->next;
2346 /* we can't find right extension */
2347 ast_mutex_unlock(&con->lock);
2352 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2354 struct ast_app *tmp, *prev, *cur;
2357 length = sizeof(struct ast_app);
2358 length += strlen(app) + 1;
2359 if (ast_mutex_lock(&applock)) {
2360 ast_log(LOG_ERROR, "Unable to lock application list\n");
2365 if (!strcasecmp(app, tmp->name)) {
2366 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2367 ast_mutex_unlock(&applock);
2372 tmp = malloc(length);
2374 memset(tmp, 0, length);
2375 strcpy(tmp->name, app);
2376 tmp->execute = execute;
2377 tmp->synopsis = synopsis;
2378 tmp->description = description;
2379 /* Store in alphabetical order */
2383 if (strcasecmp(tmp->name, cur->name) < 0)
2389 tmp->next = prev->next;
2396 ast_log(LOG_ERROR, "Out of memory\n");
2397 ast_mutex_unlock(&applock);
2400 if (option_verbose > 1)
2401 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2402 ast_mutex_unlock(&applock);
2406 int ast_register_switch(struct ast_switch *sw)
2408 struct ast_switch *tmp, *prev=NULL;
2409 if (ast_mutex_lock(&switchlock)) {
2410 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2415 if (!strcasecmp(tmp->name, sw->name))
2421 ast_mutex_unlock(&switchlock);
2422 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2430 ast_mutex_unlock(&switchlock);
2434 void ast_unregister_switch(struct ast_switch *sw)
2436 struct ast_switch *tmp, *prev=NULL;
2437 if (ast_mutex_lock(&switchlock)) {
2438 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2445 prev->next = tmp->next;
2447 switches = tmp->next;
2454 ast_mutex_unlock(&switchlock);
2458 * Help for CLI commands ...
2460 static char show_application_help[] =
2461 "Usage: show application <application> [<application> [<application> [...]]]\n"
2462 " Describes a particular application.\n";
2464 static char show_applications_help[] =
2465 "Usage: show applications [{like|describing} <text>]\n"
2466 " List applications which are currently available.\n"
2467 " If 'like', <text> will be a substring of the app name\n"
2468 " If 'describing', <text> will be a substring of the description\n";
2470 static char show_dialplan_help[] =
2471 "Usage: show dialplan [exten@][context]\n"
2474 static char show_switches_help[] =
2475 "Usage: show switches\n"
2476 " Show registered switches\n";
2479 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2484 * 'show application' CLI command implementation functions ...
2488 * There is a possibility to show informations about more than one
2489 * application at one time. You can type 'show application Dial Echo' and
2490 * you will see informations about these two applications ...
2492 static char *complete_show_application(char *line, char *word,
2498 /* try to lock applications list ... */
2499 if (ast_mutex_lock(&applock)) {
2500 ast_log(LOG_ERROR, "Unable to lock application list\n");
2504 /* ... walk all applications ... */
2507 /* ... check if word matches this application ... */
2508 if (!strncasecmp(word, a->name, strlen(word))) {
2509 /* ... if this is right app serve it ... */
2510 if (++which > state) {
2511 char *ret = strdup(a->name);
2512 ast_mutex_unlock(&applock);
2519 /* no application match */
2520 ast_mutex_unlock(&applock);
2524 static int handle_show_application(int fd, int argc, char *argv[])
2527 int app, no_registered_app = 1;
2529 if (argc < 3) return RESULT_SHOWUSAGE;
2531 /* try to lock applications list ... */
2532 if (ast_mutex_lock(&applock)) {
2533 ast_log(LOG_ERROR, "Unable to lock application list\n");
2537 /* ... go through all applications ... */
2540 /* ... compare this application name with all arguments given
2541 * to 'show application' command ... */
2542 for (app = 2; app < argc; app++) {
2543 if (!strcasecmp(a->name, argv[app])) {
2544 /* Maximum number of characters added by terminal coloring is 22 */
2545 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2546 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2547 int synopsis_size, description_size;
2549 no_registered_app = 0;
2552 synopsis_size = strlen(a->synopsis) + 23;
2554 synopsis_size = strlen("Not available") + 23;
2555 synopsis = alloca(synopsis_size);
2558 description_size = strlen(a->description) + 23;
2560 description_size = strlen("Not available") + 23;
2561 description = alloca(description_size);
2563 if (synopsis && description) {
2564 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2565 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2566 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2567 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2568 term_color(synopsis,
2569 a->synopsis ? a->synopsis : "Not available",
2570 COLOR_CYAN, 0, synopsis_size);
2571 term_color(description,
2572 a->description ? a->description : "Not available",
2573 COLOR_CYAN, 0, description_size);
2575 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2577 /* ... one of our applications, show info ...*/
2578 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2579 "[Synopsis]:\n %s\n\n"
2580 "[Description]:\n%s\n",
2582 a->synopsis ? a->synopsis : "Not available",
2583 a->description ? a->description : "Not available");
2590 ast_mutex_unlock(&applock);
2592 /* we found at least one app? no? */
2593 if (no_registered_app) {
2594 ast_cli(fd, "Your application(s) is (are) not registered\n");
2595 return RESULT_FAILURE;
2598 return RESULT_SUCCESS;
2601 static int handle_show_switches(int fd, int argc, char *argv[])
2603 struct ast_switch *sw;
2605 ast_cli(fd, "There are no registered alternative switches\n");
2606 return RESULT_SUCCESS;
2608 /* ... we have applications ... */
2609 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2610 if (ast_mutex_lock(&switchlock)) {
2611 ast_log(LOG_ERROR, "Unable to lock switches\n");
2616 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2619 ast_mutex_unlock(&switchlock);
2620 return RESULT_SUCCESS;
2624 * 'show applications' CLI command implementation functions ...
2626 static int handle_show_applications(int fd, int argc, char *argv[])
2629 int like=0, describing=0;
2631 /* try to lock applications list ... */
2632 if (ast_mutex_lock(&applock)) {
2633 ast_log(LOG_ERROR, "Unable to lock application list\n");
2637 /* ... have we got at least one application (first)? no? */
2639 ast_cli(fd, "There are no registered applications\n");
2640 ast_mutex_unlock(&applock);
2644 /* show applications like <keyword> */
2645 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2647 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2651 /* show applications describing <keyword1> [<keyword2>] [...] */
2652 if ((!like) && (!describing)) {
2653 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2655 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2658 /* ... go through all applications ... */
2659 for (a = apps; a; a = a->next) {
2660 /* ... show informations about applications ... */
2664 if (ast_strcasestr(a->name, argv[3])) {
2667 } else if (describing) {
2668 if (a->description) {
2669 /* Match all words on command line */
2672 for (i=3;i<argc;i++) {
2673 if (! ast_strcasestr(a->description, argv[i])) {
2683 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2687 /* ... unlock and return */
2688 ast_mutex_unlock(&applock);
2690 return RESULT_SUCCESS;
2693 static char *complete_show_applications(char *line, char *word, int pos, int state)
2696 if (ast_strlen_zero(word)) {
2699 return strdup("like");
2701 return strdup("describing");
2705 } else if (! strncasecmp(word, "like", strlen(word))) {
2707 return strdup("like");
2711 } else if (! strncasecmp(word, "describing", strlen(word))) {
2713 return strdup("describing");
2723 * 'show dialplan' CLI command implementation functions ...
2725 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2728 struct ast_context *c;
2731 /* we are do completion of [exten@]context on second position only */
2732 if (pos != 2) return NULL;
2734 /* try to lock contexts list ... */
2735 if (ast_lock_contexts()) {
2736 ast_log(LOG_ERROR, "Unable to lock context list\n");
2740 /* ... walk through all contexts ... */
2741 c = ast_walk_contexts(NULL);
2743 /* ... word matches context name? yes? ... */
2744 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2745 /* ... for serve? ... */
2746 if (++which > state) {
2747 /* ... yes, serve this context name ... */
2748 char *ret = strdup(ast_get_context_name(c));
2749 ast_unlock_contexts();
2753 c = ast_walk_contexts(c);
2756 /* ... unlock and return */
2757 ast_unlock_contexts();
2761 static int handle_show_dialplan(int fd, int argc, char *argv[])
2763 struct ast_context *c;
2764 char *exten = NULL, *context = NULL;
2765 int context_existence = 0, extension_existence = 0;
2767 if (argc != 3 && argc != 2) return -1;
2769 /* we obtain [exten@]context? if yes, split them ... */
2771 char *splitter = argv[2];
2772 /* is there a '@' character? */
2773 if (strchr(argv[2], '@')) {
2774 /* yes, split into exten & context ... */
2775 exten = strsep(&splitter, "@");
2778 /* check for length and change to NULL if ast_strlen_zero() */
2779 if (ast_strlen_zero(exten)) exten = NULL;
2780 if (ast_strlen_zero(context)) context = NULL;
2783 /* no '@' char, only context given */
2785 if (ast_strlen_zero(context)) context = NULL;
2789 /* try to lock contexts */
2790 if (ast_lock_contexts()) {
2791 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2792 return RESULT_FAILURE;
2795 /* walk all contexts ... */
2796 c = ast_walk_contexts(NULL);
2798 /* show this context? */
2800 !strcmp(ast_get_context_name(c), context)) {
2801 context_existence = 1;
2803 /* try to lock context before walking in ... */
2804 if (!ast_lock_context(c)) {
2805 struct ast_exten *e;
2806 struct ast_include *i;
2807 struct ast_ignorepat *ip;
2809 char buf[256], buf2[256];
2810 int context_info_printed = 0;
2812 /* are we looking for exten too? if yes, we print context
2813 * if we our extension only
2816 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2817 ast_get_context_name(c), ast_get_context_registrar(c));
2818 context_info_printed = 1;
2821 /* walk extensions ... */
2822 e = ast_walk_context_extensions(c, NULL);
2824 struct ast_exten *p;
2826 /* looking for extension? is this our extension? */
2828 strcmp(ast_get_extension_name(e), exten))
2830 /* we are looking for extension and it's not our
2831 * extension, so skip to next extension */
2832 e = ast_walk_context_extensions(c, e);
2836 extension_existence = 1;
2838 /* may we print context info? */
2839 if (!context_info_printed) {
2840 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2841 ast_get_context_name(c),
2842 ast_get_context_registrar(c));
2843 context_info_printed = 1;
2846 /* write extension name and first peer */
2847 bzero(buf, sizeof(buf));
2848 snprintf(buf, sizeof(buf), "'%s' =>",
2849 ast_get_extension_name(e));
2851 snprintf(buf2, sizeof(buf2),
2853 ast_get_extension_priority(e),
2854 ast_get_extension_app(e),
2855 (char *)ast_get_extension_app_data(e));
2857 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2858 ast_get_extension_registrar(e));
2860 /* walk next extension peers */
2861 p = ast_walk_extension_priorities(e, e);
2863 bzero((void *)buf2, sizeof(buf2));
2864 bzero((void *)buf, sizeof(buf));
2865 if (ast_get_extension_label(p))
2866 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
2867 snprintf(buf2, sizeof(buf2),
2869 ast_get_extension_priority(p),
2870 ast_get_extension_app(p),
2871 (char *)ast_get_extension_app_data(p));
2873 ast_cli(fd," %-17s %-45s [%s]\n",
2875 ast_get_extension_registrar(p));
2877 p = ast_walk_extension_priorities(e, p);
2879 e = ast_walk_context_extensions(c, e);
2882 /* include & ignorepat we all printing if we are not
2883 * looking for exact extension
2886 if (ast_walk_context_extensions(c, NULL))
2889 /* walk included and write info ... */
2890 i = ast_walk_context_includes(c, NULL);
2892 bzero(buf, sizeof(buf));
2893 snprintf(buf, sizeof(buf), "'%s'",
2894 ast_get_include_name(i));
2895 ast_cli(fd, " Include => %-45s [%s]\n",
2896 buf, ast_get_include_registrar(i));
2897 i = ast_walk_context_includes(c, i);
2900 /* walk ignore patterns and write info ... */
2901 ip = ast_walk_context_ignorepats(c, NULL);
2903 bzero(buf, sizeof(buf));
2904 snprintf(buf, sizeof(buf), "'%s'",
2905 ast_get_ignorepat_name(ip));
2906 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2907 buf, ast_get_ignorepat_registrar(ip));
2908 ip = ast_walk_context_ignorepats(c, ip);
2910 sw = ast_walk_context_switches(c, NULL);
2912 bzero(buf, sizeof(buf));
2913 snprintf(buf, sizeof(buf), "'%s/%s'",
2914 ast_get_switch_name(sw),
2915 ast_get_switch_data(sw));
2916 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2917 buf, ast_get_switch_registrar(sw));
2918 sw = ast_walk_context_switches(c, sw);
2922 ast_unlock_context(c);
2924 /* if we print something in context, make an empty line */
2925 if (context_info_printed) ast_cli(fd, "\n");
2928 c = ast_walk_contexts(c);
2930 ast_unlock_contexts();
2932 /* check for input failure and throw some error messages */
2933 if (context && !context_existence) {
2934 ast_cli(fd, "There is no existence of '%s' context\n",
2936 return RESULT_FAILURE;
2939 if (exten && !extension_existence) {
2941 ast_cli(fd, "There is no existence of %s@%s extension\n",
2945 "There is no existence of '%s' extension in all contexts\n",
2947 return RESULT_FAILURE;
2951 return RESULT_SUCCESS;
2955 * CLI entries for upper commands ...
2957 static struct ast_cli_entry show_applications_cli =
2958 { { "show", "applications", NULL },
2959 handle_show_applications, "Shows registered applications",
2960 show_applications_help, complete_show_applications };
2962 static struct ast_cli_entry show_application_cli =
2963 { { "show", "application", NULL },
2964 handle_show_application, "Describe a specific application",
2965 show_application_help, complete_show_application };
2967 static struct ast_cli_entry show_dialplan_cli =
2968 { { "show", "dialplan", NULL },
2969 handle_show_dialplan, "Show dialplan",
2970 show_dialplan_help, complete_show_dialplan_context };