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 unsigned int monthmask; /* Mask for month */
89 unsigned int daymask; /* Mask for date */
90 unsigned int dowmask; /* Mask for day of week (mon-sun) */
91 unsigned int minmask[24]; /* Mask for minute */
92 struct ast_include *next; /* Link them together */
96 /* ast_sw: Switch statement in extensions.conf */
99 const char *registrar; /* Registrar */
100 char *data; /* Data load */
101 struct ast_sw *next; /* Link them together */
105 struct ast_ignorepat {
106 const char *registrar;
107 struct ast_ignorepat *next;
111 /* ast_context: An extension context */
113 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
114 struct ast_exten *root; /* The root of the list of extensions */
115 struct ast_context *next; /* Link them together */
116 struct ast_include *includes; /* Include other contexts */
117 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
118 const char *registrar; /* Registrar */
119 struct ast_sw *alts; /* Alternative switches */
120 char name[0]; /* Name of the context */
124 /* ast_app: An application */
126 int (*execute)(struct ast_channel *chan, void *data);
127 const char *synopsis; /* Synopsis text for 'show applications' */
128 const char *description; /* Description (help text) for 'show application <name>' */
129 struct ast_app *next; /* Next app in list */
130 char name[0]; /* Name of the application */
133 /* ast_state_cb: An extension state notify */
134 struct ast_state_cb {
137 ast_state_cb_type callback;
138 struct ast_state_cb *next;
142 struct ast_exten *exten;
144 struct ast_state_cb *callbacks;
145 struct ast_hint *next;
148 int ast_pbx_outgoing_cdr_failed(void);
150 static int pbx_builtin_prefix(struct ast_channel *, void *);
151 static int pbx_builtin_suffix(struct ast_channel *, void *);
152 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
153 static int pbx_builtin_answer(struct ast_channel *, void *);
154 static int pbx_builtin_goto(struct ast_channel *, void *);
155 static int pbx_builtin_hangup(struct ast_channel *, void *);
156 static int pbx_builtin_background(struct ast_channel *, void *);
157 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
158 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
159 static int pbx_builtin_atimeout(struct ast_channel *, void *);
160 static int pbx_builtin_wait(struct ast_channel *, void *);
161 static int pbx_builtin_waitexten(struct ast_channel *, void *);
162 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
163 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
164 static int pbx_builtin_setaccount(struct ast_channel *, void *);
165 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
166 static int pbx_builtin_ringing(struct ast_channel *, void *);
167 static int pbx_builtin_progress(struct ast_channel *, void *);
168 static int pbx_builtin_congestion(struct ast_channel *, void *);
169 static int pbx_builtin_busy(struct ast_channel *, void *);
170 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
171 static int pbx_builtin_noop(struct ast_channel *, void *);
172 static int pbx_builtin_gotoif(struct ast_channel *, void *);
173 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
174 static int pbx_builtin_saynumber(struct ast_channel *, void *);
175 static int pbx_builtin_saydigits(struct ast_channel *, void *);
176 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
177 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
178 int pbx_builtin_setvar(struct ast_channel *, void *);
179 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
180 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
182 static struct varshead globals;
184 static int autofallthrough = 0;
186 static struct pbx_builtin {
187 char name[AST_MAX_APP];
188 int (*execute)(struct ast_channel *chan, void *data);
193 /* These applications are built into the PBX core and do not
194 need separate modules
198 { "AbsoluteTimeout", pbx_builtin_atimeout,
199 "Set absolute maximum time of call",
200 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
201 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
204 { "Answer", pbx_builtin_answer,
205 "Answer a channel if ringing",
206 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
207 "Returns 0 unless it tries to answer the channel and fails.\n"
210 { "BackGround", pbx_builtin_background,
211 "Play a file while awaiting extension",
212 " Background(filename[|options[|langoverride]]): Plays a given file, while simultaneously\n"
213 "waiting for the user to begin typing an extension. The timeouts do not\n"
214 "count until the last BackGround application has ended.\n"
215 "Options may also be included following a pipe symbol. The 'skip'\n"
216 "option causes the playback of the message to be skipped if the channel\n"
217 "is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
218 "specified, the application will return immediately should the channel not be\n"
219 "off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
220 "be answered before the sound is played. Not all channels support playing\n"
221 "messages while still hook. The 'langoverride' may be a language to use for\n"
222 "playing the prompt which differs from the current language of the channel\n"
223 "Returns -1 if the channel was hung up, or if the file does not exist. \n"
224 "Returns 0 otherwise.\n"
227 { "Busy", pbx_builtin_busy,
228 "Indicate busy condition and stop",
229 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
230 "then waits for the user to hang up or the optional timeout to expire.\n"
234 { "Congestion", pbx_builtin_congestion,
235 "Indicate congestion and stop",
236 " Congestion([timeout]): Requests that the channel indicate congestion\n"
237 "and then waits for the user to hang up or for the optional timeout to\n"
238 "expire. Always returns -1."
241 { "DigitTimeout", pbx_builtin_dtimeout,
242 "Set maximum timeout between digits",
243 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
244 "digits when the user is typing in an extension. When this timeout expires,\n"
245 "after the user has started to type in an extension, the extension will be\n"
246 "considered complete, and will be interpreted. Note that if an extension\n"
247 "typed in is valid, it will not have to timeout to be tested, so typically\n"
248 "at the expiry of this timeout, the extension will be considered invalid\n"
249 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
250 "exist the call would be terminated). Always returns 0.\n"
253 { "Goto", pbx_builtin_goto,
254 "Goto a particular priority, extension, or context",
255 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
256 "value, optionally setting the extension and optionally the context as well.\n"
257 "The extension BYEXTENSION is special in that it uses the current extension,\n"
258 "thus permitting you to go to a different context, without specifying a\n"
259 "specific extension. Always returns 0, even if the given context, extension,\n"
260 "or priority is invalid.\n"
263 { "GotoIf", pbx_builtin_gotoif,
265 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
266 "true, to label2 if condition is false. Either label1 or label2 may be\n"
267 "omitted (in that case, we just don't take the particular branch) but not\n"
268 "both. Look for the condition syntax in examples or documentation."
271 { "GotoIfTime", pbx_builtin_gotoiftime,
272 "Conditional goto on current time",
273 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
274 "If the current time matches the specified time, then branch to the specified\n"
275 "extension. Each of the elements may be specified either as '*' (for always)\n"
276 "or as a range. See the 'include' syntax for details."
279 { "Hangup", pbx_builtin_hangup,
280 "Unconditional hangup",
281 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
284 { "NoOp", pbx_builtin_noop,
286 " NoOp(): No-operation; Does nothing."
289 { "Prefix", pbx_builtin_prefix,
290 "Prepend leading digits",
291 " Prefix(digits): Prepends the digit string specified by digits to the\n"
292 "channel's associated extension. For example, the number 1212 when prefixed\n"
293 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
294 "continue processing at the next priority for the *new* extension.\n"
295 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
296 "executed will be priority 4 of 5551212. If you switch into an extension\n"
297 "which has no first step, the PBX will treat it as though the user dialed an\n"
298 "invalid extension.\n"
301 { "Progress", pbx_builtin_progress,
303 " Progress(): Request that the channel indicate in-band progress is \n"
304 "available to the user.\nAlways returns 0.\n"
307 { "ResetCDR", pbx_builtin_resetcdr,
308 "Resets the Call Data Record",
309 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
310 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
311 "record WILL be stored.\nAlways returns 0.\n"
314 { "ResponseTimeout", pbx_builtin_rtimeout,
315 "Set maximum timeout awaiting response",
316 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
317 "falling through a series of priorities for a channel in which the user may\n"
318 "begin typing an extension. If the user does not type an extension in this\n"
319 "amount of time, control will pass to the 't' extension if it exists, and\n"
320 "if not the call would be terminated.\nAlways returns 0.\n"
323 { "Ringing", pbx_builtin_ringing,
324 "Indicate ringing tone",
325 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
326 "Always returns 0.\n"
329 { "SayNumber", pbx_builtin_saynumber,
331 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
332 "the current language setting for the channel. (See app SetLanguage).\n"
335 { "SayDigits", pbx_builtin_saydigits,
337 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
338 "current language setting for the channel. (See app setLanguage)\n"
341 { "SayAlpha", pbx_builtin_saycharacters,
343 " SayAlpha(string): Spells the passed string\n"
346 { "SayPhonetic", pbx_builtin_sayphonetic,
348 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
351 { "SetAccount", pbx_builtin_setaccount,
353 " SetAccount([account]): Set the channel account code for billing\n"
354 "purposes. Always returns 0.\n"
357 { "SetAMAFlags", pbx_builtin_setamaflags,
359 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
360 "purposes. Always returns 0.\n"
363 { "SetGlobalVar", pbx_builtin_setglobalvar,
364 "Set global variable to value",
365 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
366 "variable are available across channels.\n"
369 { "SetLanguage", pbx_builtin_setlanguage,
370 "Sets user language",
371 " SetLanguage(language): Set the channel language to 'language'. This\n"
372 "information is used for the syntax in generation of numbers, and to choose\n"
373 "a natural language file when available.\n"
374 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
375 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
376 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
377 "Always returns 0.\n"
380 { "SetVar", pbx_builtin_setvar,
381 "Set variable to value",
382 " SetVar(#n=value): Sets variable n to value. If prefixed with _, single\n"
383 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
385 { "StripMSD", pbx_builtin_stripmsd,
386 "Strip leading digits",
387 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
388 "associated extension. For example, the number 5551212 when stripped with a\n"
389 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
390 "will continue processing at the next priority for the *new* extension.\n"
391 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
392 "executed will be priority 4 of 1212. If you switch into an extension which\n"
393 "has no first step, the PBX will treat it as though the user dialed an\n"
394 "invalid extension.\n"
397 { "Suffix", pbx_builtin_suffix,
398 "Append trailing digits",
399 " Suffix(digits): Appends the digit string specified by digits to the\n"
400 "channel's associated extension. For example, the number 555 when suffixed\n"
401 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
402 "continue processing at the next priority for the *new* extension.\n"
403 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
404 "executed will be priority 4 of 5551212. If you switch into an extension\n"
405 "which has no first step, the PBX will treat it as though the user dialed an\n"
406 "invalid extension.\n"
409 { "Wait", pbx_builtin_wait,
410 "Waits for some time",
411 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
412 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
415 { "WaitExten", pbx_builtin_waitexten,
416 "Waits for some time",
417 " Wait([seconds]): Waits for the user to enter a new extension for the \n"
418 "specified number of seconds, then returns 0. Seconds can be passed with\n"
419 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
420 "default extension timeout will be used.\n"
425 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
426 static struct ast_context *contexts = NULL;
427 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
428 static struct ast_app *apps = NULL;
430 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
431 struct ast_switch *switches = NULL;
433 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
434 static int stateid = 1;
435 struct ast_hint *hints = NULL;
436 struct ast_state_cb *statecbs = NULL;
438 int pbx_exec(struct ast_channel *c, /* Channel */
439 struct ast_app *app, /* Application */
440 void *data, /* Data for execution */
441 int newstack) /* Force stack increment */
443 /* This function is special. It saves the stack so that no matter
444 how many times it is called, it returns to the same place */
450 int stack = c->stack;
451 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
453 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
454 /* Don't allow us to go over the max number of stacks we
456 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
459 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
460 /* Okay, here's where it gets weird. If newstack is non-zero,
461 then we increase the stack increment, but setjmp is not going
462 to return until longjmp is called -- when the application
463 exec'd is finished running. */
466 if (c->stack != stack + 1)
467 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
468 else if (c->app[c->stack])
469 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
474 ast_cdr_setapp(c->cdr, app->name, data);
476 /* save channel values */
477 saved_c_appl= c->appl;
478 saved_c_data= c->data;
482 res = execute(c, data);
483 /* restore channel values */
484 c->appl= saved_c_appl;
485 c->data= saved_c_data;
487 /* Any application that returns, we longjmp back, just in case. */
488 if (c->stack != stack + 1)
489 ast_log(LOG_WARNING, "Stack is not at expected value\n");
490 longjmp(c->jmp[stack+1], res);
496 /* Go no deeper than this through includes (not counting loops) */
497 #define AST_PBX_MAX_STACK 64
499 #define HELPER_EXISTS 0
500 #define HELPER_SPAWN 1
501 #define HELPER_EXEC 2
502 #define HELPER_CANMATCH 3
503 #define HELPER_MATCHMORE 4
504 #define HELPER_FINDLABEL 5
506 struct ast_app *pbx_findapp(const char *app)
510 if (ast_mutex_lock(&applock)) {
511 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
516 if (!strcasecmp(tmp->name, app))
520 ast_mutex_unlock(&applock);
524 static struct ast_switch *pbx_findswitch(const char *sw)
526 struct ast_switch *asw;
528 if (ast_mutex_lock(&switchlock)) {
529 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
534 if (!strcasecmp(asw->name, sw))
538 ast_mutex_unlock(&switchlock);
542 static inline int include_valid(struct ast_include *i)
552 /* If it's not the right month, return */
553 if (!(i->monthmask & (1 << tm.tm_mon))) {
557 /* If it's not that time of the month.... */
558 /* Warning, tm_mday has range 1..31! */
559 if (!(i->daymask & (1 << (tm.tm_mday-1))))
562 /* If it's not the right day of the week */
563 if (!(i->dowmask & (1 << tm.tm_wday)))
566 /* Sanity check the hour just to be safe */
567 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
568 ast_log(LOG_WARNING, "Insane time...\n");
572 /* Now the tough part, we calculate if it fits
573 in the right time based on min/hour */
574 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
577 /* If we got this far, then we're good */
581 static void pbx_destroy(struct ast_pbx *p)
586 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
587 /* All patterns begin with _ */\
588 if (pattern[0] != '_') \
590 /* Start optimistic */\
593 while(match && *data && *pattern && (*pattern != '/')) {\
594 switch(toupper(*pattern)) {\
601 where=strchr(pattern,']');\
603 border=(int)(where-pattern);\
604 if (!where || border > strlen(pattern)) {\
605 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
608 for (i=0; i<border; i++) {\
611 if (pattern[i+1]=='-') {\
612 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
619 if (res==1 || *data==pattern[i]) {\
628 if ((*data < '2') || (*data > '9'))\
632 if ((*data < '0') || (*data > '9'))\
636 if ((*data < '1') || (*data > '9'))\
644 /* Ignore these characters */\
648 if (*data != *pattern)\
656 int ast_extension_match(const char *pattern, const char *data)
659 /* If they're the same return */
660 if (!strcmp(pattern, data))
662 EXTENSION_MATCH_CORE(data,pattern,match);
663 /* Must be at the end of both */
664 if (*data || (*pattern && (*pattern != '/')))
669 static int extension_close(const char *pattern, const char *data, int needmore)
672 /* If "data" is longer, it can'be a subset of pattern unless
673 pattern is a pattern match */
674 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
677 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
678 (!needmore || (strlen(pattern) > strlen(data)))) {
681 EXTENSION_MATCH_CORE(data,pattern,match);
682 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
683 if (!needmore || *pattern) {
689 struct ast_context *ast_context_find(const char *name)
691 struct ast_context *tmp;
692 ast_mutex_lock(&conlock);
696 if (!strcasecmp(name, tmp->name))
702 ast_mutex_unlock(&conlock);
706 #define STATUS_NO_CONTEXT 1
707 #define STATUS_NO_EXTENSION 2
708 #define STATUS_NO_PRIORITY 3
709 #define STATUS_NO_LABEL 4
710 #define STATUS_SUCCESS 5
712 static int matchcid(const char *cidpattern, const char *callerid)
716 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
717 failing to get a number should count as a match, otherwise not */
720 if (!ast_strlen_zero(cidpattern))
728 return ast_extension_match(cidpattern, callerid);
731 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)
734 struct ast_context *tmp;
735 struct ast_exten *e, *eroot;
736 struct ast_include *i;
738 struct ast_switch *asw;
740 /* Initialize status if appropriate */
742 *status = STATUS_NO_CONTEXT;
746 /* Check for stack overflow */
747 if (*stacklen >= AST_PBX_MAX_STACK) {
748 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
751 /* Check first to see if we've already been checked */
752 for (x=0;x<*stacklen;x++) {
753 if (!strcasecmp(incstack[x], context))
762 if (bypass || !strcmp(tmp->name, context)) {
763 if (*status < STATUS_NO_EXTENSION)
764 *status = STATUS_NO_EXTENSION;
767 /* Match extension */
768 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
769 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
770 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
771 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
773 if (*status < STATUS_NO_PRIORITY)
774 *status = STATUS_NO_PRIORITY;
777 if (action == HELPER_FINDLABEL) {
778 if (*status < STATUS_NO_LABEL)
779 *status = STATUS_NO_LABEL;
780 if (label && e->label && !strcmp(label, e->label)) {
781 *status = STATUS_SUCCESS;
784 } else if (e->priority == priority) {
785 *status = STATUS_SUCCESS;
793 /* Check alternative switches */
796 if ((asw = pbx_findswitch(sw->name))) {
797 if (action == HELPER_CANMATCH)
798 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
799 else if (action == HELPER_MATCHMORE)
800 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
802 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
810 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
814 /* Setup the stack */
815 incstack[*stacklen] = tmp->name;
817 /* Now try any includes we have in this context */
820 if (include_valid(i)) {
821 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data)))
835 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
838 char tmpvar[80] = "";
840 struct tm brokentime;
842 struct ast_var_t *variables;
847 /* Now we have the variable name on cp3 */
848 if (!strncasecmp(var,"LEN(",4)) {
851 if (strrchr(var,')')) {
853 strncpy(cp3, var, sizeof(cp3) - 1);
854 cp3[len-len_len-1]='\0';
855 sprintf(workspace,"%d",(int)strlen(cp3));
861 } else if ((first=strchr(var,':'))) {
862 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
863 first = strchr(tmpvar, ':');
865 first = tmpvar + strlen(tmpvar);
867 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1, headp);
869 offset=atoi(first+1);
870 if ((second=strchr(first+1,':'))) {
872 offset2=atoi(second+1);
874 offset2=strlen(*ret)-offset;
875 if (abs(offset)>strlen(*ret)) {
879 offset=-strlen(*ret);
881 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
883 offset2=strlen(*ret)-offset;
885 offset2=strlen(*ret)+offset;
890 *ret+=strlen(*ret)+offset;
891 (*ret)[offset2] = '\0';
892 } else if (c && !strcmp(var, "CALLERIDNUM")) {
893 if (c->cid.cid_num) {
894 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
898 } else if (c && !strcmp(var, "CALLERANI")) {
899 if (c->cid.cid_ani) {
900 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
904 } else if (c && !strcmp(var, "CALLERIDNAME")) {
905 if (c->cid.cid_name) {
906 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
910 } else if (c && !strcmp(var, "CALLERID")) {
911 if (c->cid.cid_num) {
912 if (c->cid.cid_name) {
913 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
915 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
918 } else if (c->cid.cid_name) {
919 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
923 } else if (c && !strcmp(var, "DNID")) {
924 if (c->cid.cid_dnid) {
925 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
929 } else if (c && !strcmp(var, "HINT")) {
930 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
934 } else if (c && !strcmp(var, "EXTEN")) {
935 strncpy(workspace, c->exten, workspacelen - 1);
937 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
938 /* XXX Remove me eventually */
939 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
942 if (offset > strlen(c->exten))
943 offset = strlen(c->exten);
944 strncpy(workspace, c->exten + offset, workspacelen - 1);
946 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
947 } else if (c && !strcmp(var, "RDNIS")) {
948 if (c->cid.cid_rdnis) {
949 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
953 } else if (c && !strcmp(var, "CONTEXT")) {
954 strncpy(workspace, c->context, workspacelen - 1);
956 } else if (c && !strcmp(var, "PRIORITY")) {
957 snprintf(workspace, workspacelen, "%d", c->priority);
959 } else if (c && !strcmp(var, "CALLINGPRES")) {
960 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
962 } else if (c && !strcmp(var, "CALLINGANI2")) {
963 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
965 } else if (c && !strcmp(var, "CALLINGTON")) {
966 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
968 } else if (c && !strcmp(var, "CALLINGTNS")) {
969 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
971 } else if (c && !strcmp(var, "CHANNEL")) {
972 strncpy(workspace, c->name, workspacelen - 1);
974 } else if (c && !strcmp(var, "EPOCH")) {
975 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
977 } else if (c && !strcmp(var, "DATETIME")) {
979 localtime_r(&thistime, &brokentime);
980 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
983 brokentime.tm_year+1900,
989 } else if (c && !strcmp(var, "TIMESTAMP")) {
991 localtime_r(&thistime, &brokentime);
992 /* 20031130-150612 */
993 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
994 brokentime.tm_year+1900,
1002 } else if (c && !strcmp(var, "UNIQUEID")) {
1003 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1005 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1006 snprintf(workspace, workspacelen, "%i", c->hangupcause);
1008 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1009 strncpy(workspace, c->accountcode, workspacelen - 1);
1011 } else if (c && !strcmp(var, "LANGUAGE")) {
1012 strncpy(workspace, c->language, workspacelen - 1);
1016 AST_LIST_TRAVERSE(headp,variables,entries) {
1018 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1020 if (strcasecmp(ast_var_name(variables),var)==0) {
1021 *ret=ast_var_value(variables);
1023 strncpy(workspace, *ret, workspacelen - 1);
1032 AST_LIST_TRAVERSE(&globals,variables,entries) {
1034 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1036 if (strcasecmp(ast_var_name(variables),var)==0) {
1037 *ret=ast_var_value(variables);
1039 strncpy(workspace, *ret, workspacelen - 1);
1046 int len=strlen(var);
1047 int len_env=strlen("ENV(");
1048 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1050 strncpy(cp3, var, sizeof(cp3) - 1);
1052 *ret=getenv(cp3+len_env);
1054 strncpy(workspace, *ret, workspacelen - 1);
1062 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1065 const char *tmp, *whereweare;
1067 char workspace[4096];
1068 char ltmp[4096], var[4096];
1069 char *nextvar, *nextexp;
1071 int pos, brackets, needsub, len;
1073 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1076 while(!ast_strlen_zero(whereweare) && count) {
1077 /* Assume we're copying the whole remaining string */
1078 pos = strlen(whereweare);
1080 /* Look for a variable */
1081 nextvar = strstr(whereweare, "${");
1083 /* Look for an expression */
1084 nextexp = strstr(whereweare, "$[");
1086 /* Pick the first one only */
1087 if (nextvar && nextexp) {
1088 if (nextvar < nextexp)
1094 /* If there is one, we only go that far */
1096 pos = nextvar - whereweare;
1098 pos = nextexp - whereweare;
1100 /* Can't copy more than 'count' bytes */
1104 /* Copy that many bytes */
1105 memcpy(cp2, whereweare, pos);
1112 /* We have a variable. Find the start and end, and determine
1113 if we are going to have to recursively call ourselves on the
1115 vars = vare = nextvar + 2;
1119 /* Find the end of it */
1120 while(brackets && *vare) {
1121 if ((vare[0] == '$') && (vare[1] == '{')) {
1124 } else if (vare[0] == '}') {
1126 } else if ((vare[0] == '$') && (vare[1] == '['))
1131 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1132 len = vare - vars - 1;
1134 /* Skip totally over variable name */
1135 whereweare += ( len + 3);
1137 /* Store variable name (and truncate) */
1138 memset(var, 0, sizeof(var));
1139 strncpy(var, vars, sizeof(var) - 1);
1142 /* Substitute if necessary */
1144 memset(ltmp, 0, sizeof(ltmp));
1145 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1151 /* Retrieve variable value */
1152 workspace[0] = '\0';
1153 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace), headp);
1155 length = strlen(cp4);
1158 memcpy(cp2, cp4, length);
1163 } else if (nextexp) {
1164 /* We have an expression. Find the start and end, and determine
1165 if we are going to have to recursively call ourselves on the
1167 vars = vare = nextexp + 2;
1171 /* Find the end of it */
1172 while(brackets && *vare) {
1173 if ((vare[0] == '$') && (vare[1] == '[')) {
1177 } else if (vare[0] == '[') {
1179 } else if (vare[0] == ']') {
1181 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1188 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1189 len = vare - vars - 1;
1191 /* Skip totally over variable name */
1192 whereweare += ( len + 3);
1194 /* Store variable name (and truncate) */
1195 memset(var, 0, sizeof(var));
1196 strncpy(var, vars, sizeof(var) - 1);
1199 /* Substitute if necessary */
1201 memset(ltmp, 0, sizeof(ltmp));
1202 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1208 /* Evaluate expression */
1209 cp4 = ast_expr(vars);
1211 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1214 length = strlen(cp4);
1217 memcpy(cp2, cp4, length);
1228 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1230 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1233 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1235 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1238 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1240 memset(passdata, 0, datalen);
1242 /* No variables or expressions in e->data, so why scan it? */
1243 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1244 strncpy(passdata, e->data, datalen - 1);
1245 passdata[datalen-1] = '\0';
1249 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1252 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)
1254 struct ast_exten *e;
1255 struct ast_app *app;
1256 struct ast_switch *sw;
1261 char *incstack[AST_PBX_MAX_STACK];
1262 char passdata[EXT_DATA_SIZE];
1266 char tmp3[EXT_DATA_SIZE];
1268 if (ast_mutex_lock(&conlock)) {
1269 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1270 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1275 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data);
1278 case HELPER_CANMATCH:
1279 ast_mutex_unlock(&conlock);
1282 ast_mutex_unlock(&conlock);
1284 case HELPER_FINDLABEL:
1286 ast_mutex_unlock(&conlock);
1288 case HELPER_MATCHMORE:
1289 ast_mutex_unlock(&conlock);
1295 app = pbx_findapp(e->app);
1296 ast_mutex_unlock(&conlock);
1298 if (c->context != context)
1299 strncpy(c->context, context, sizeof(c->context)-1);
1300 if (c->exten != exten)
1301 strncpy(c->exten, exten, sizeof(c->exten)-1);
1302 c->priority = priority;
1303 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1305 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1306 if (option_verbose > 2)
1307 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1308 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1309 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1310 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1311 (newstack ? "in new stack" : "in same stack"));
1312 manager_event(EVENT_FLAG_CALL, "Newexten",
1317 "Application: %s\r\n"
1320 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1321 res = pbx_exec(c, app, passdata, newstack);
1324 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1328 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1332 case HELPER_CANMATCH:
1333 ast_mutex_unlock(&conlock);
1336 ast_mutex_unlock(&conlock);
1338 case HELPER_MATCHMORE:
1339 ast_mutex_unlock(&conlock);
1341 case HELPER_FINDLABEL:
1342 ast_mutex_unlock(&conlock);
1348 ast_mutex_unlock(&conlock);
1350 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1352 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1357 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1361 ast_mutex_unlock(&conlock);
1363 case STATUS_NO_CONTEXT:
1364 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1365 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1367 case STATUS_NO_EXTENSION:
1368 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1369 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1371 case STATUS_NO_PRIORITY:
1372 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1373 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1375 case STATUS_NO_LABEL:
1377 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1380 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1383 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1391 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1393 struct ast_exten *e;
1394 struct ast_switch *sw;
1397 char *incstack[AST_PBX_MAX_STACK];
1400 if (ast_mutex_lock(&conlock)) {
1401 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1404 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1405 ast_mutex_unlock(&conlock);
1409 static int ast_extension_state2(struct ast_exten *e)
1411 char hint[AST_MAX_EXTENSION] = "";
1414 int allunavailable = 1, allbusy = 1, allfree = 1;
1417 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1421 rest = strchr(cur, '&');
1427 res = ast_device_state(cur);
1429 case AST_DEVICE_NOT_INUSE:
1433 case AST_DEVICE_INUSE:
1434 return AST_EXTENSION_INUSE;
1435 case AST_DEVICE_BUSY:
1440 case AST_DEVICE_UNAVAILABLE:
1441 case AST_DEVICE_INVALID:
1454 return AST_EXTENSION_NOT_INUSE;
1456 return AST_EXTENSION_BUSY;
1458 return AST_EXTENSION_UNAVAILABLE;
1460 return AST_EXTENSION_INUSE;
1462 return AST_EXTENSION_NOT_INUSE;
1466 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1468 struct ast_exten *e;
1470 e = ast_hint_extension(c, context, exten);
1474 return ast_extension_state2(e);
1477 int ast_device_state_changed(const char *fmt, ...)
1479 struct ast_hint *list;
1480 struct ast_state_cb *cblist;
1481 char hint[AST_MAX_EXTENSION] = "";
1482 char device[AST_MAX_EXTENSION];
1489 vsnprintf(device, sizeof(device), fmt, ap);
1492 rest = strchr(device, '-');
1497 ast_mutex_lock(&hintlock);
1503 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1506 rest = strchr(cur, '&');
1512 if (!strcmp(cur, device)) {
1513 /* Found extension execute callbacks */
1514 state = ast_extension_state2(list->exten);
1515 if ((state != -1) && (state != list->laststate)) {
1516 /* For general callbacks */
1519 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1520 cblist = cblist->next;
1523 /* For extension callbacks */
1524 cblist = list->callbacks;
1526 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1527 cblist = cblist->next;
1530 list->laststate = state;
1538 ast_mutex_unlock(&hintlock);
1542 int ast_extension_state_add(const char *context, const char *exten,
1543 ast_state_cb_type callback, void *data)
1545 struct ast_hint *list;
1546 struct ast_state_cb *cblist;
1547 struct ast_exten *e;
1549 /* No context and extension add callback to statecbs list */
1550 if (!context && !exten) {
1551 ast_mutex_lock(&hintlock);
1555 if (cblist->callback == callback) {
1556 cblist->data = data;
1557 ast_mutex_unlock(&hintlock);
1559 cblist = cblist->next;
1562 /* Now inserts the callback */
1563 cblist = malloc(sizeof(struct ast_state_cb));
1565 ast_mutex_unlock(&hintlock);
1568 memset(cblist, 0, sizeof(struct ast_state_cb));
1570 cblist->callback = callback;
1571 cblist->data = data;
1573 cblist->next = statecbs;
1576 ast_mutex_unlock(&hintlock);
1580 if (!context || !exten)
1583 /* This callback type is for only one hint */
1584 e = ast_hint_extension(NULL, context, exten);
1589 ast_mutex_lock(&hintlock);
1593 if (list->exten == e)
1599 ast_mutex_unlock(&hintlock);
1603 /* Now inserts the callback */
1604 cblist = malloc(sizeof(struct ast_state_cb));
1606 ast_mutex_unlock(&hintlock);
1609 memset(cblist, 0, sizeof(struct ast_state_cb));
1610 cblist->id = stateid++;
1611 cblist->callback = callback;
1612 cblist->data = data;
1614 cblist->next = list->callbacks;
1615 list->callbacks = cblist;
1617 ast_mutex_unlock(&hintlock);
1621 int ast_extension_state_del(int id, ast_state_cb_type callback)
1623 struct ast_hint *list;
1624 struct ast_state_cb *cblist, *cbprev;
1626 if (!id && !callback)
1629 ast_mutex_lock(&hintlock);
1631 /* id is zero is a callback without extension */
1636 if (cblist->callback == callback) {
1638 statecbs = cblist->next;
1640 cbprev->next = cblist->next;
1644 ast_mutex_unlock(&hintlock);
1648 cblist = cblist->next;
1651 ast_mutex_lock(&hintlock);
1655 /* id greater than zero is a callback with extension */
1658 cblist = list->callbacks;
1661 if (cblist->id==id) {
1663 list->callbacks = cblist->next;
1665 cbprev->next = cblist->next;
1669 ast_mutex_unlock(&hintlock);
1673 cblist = cblist->next;
1678 ast_mutex_unlock(&hintlock);
1682 static int ast_add_hint(struct ast_exten *e)
1684 struct ast_hint *list;
1689 ast_mutex_lock(&hintlock);
1692 /* Search if hint exists, do nothing */
1694 if (list->exten == e) {
1695 ast_mutex_unlock(&hintlock);
1701 list = malloc(sizeof(struct ast_hint));
1703 ast_mutex_unlock(&hintlock);
1706 /* Initialize and insert new item */
1707 memset(list, 0, sizeof(struct ast_hint));
1709 list->laststate = ast_extension_state2(e);
1713 ast_mutex_unlock(&hintlock);
1717 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1719 struct ast_hint *list;
1721 ast_mutex_lock(&hintlock);
1725 if (list->exten == oe) {
1727 ast_mutex_unlock(&hintlock);
1732 ast_mutex_unlock(&hintlock);
1737 static int ast_remove_hint(struct ast_exten *e)
1739 /* Cleanup the Notifys if hint is removed */
1740 struct ast_hint *list, *prev = NULL;
1741 struct ast_state_cb *cblist, *cbprev;
1746 ast_mutex_lock(&hintlock);
1750 if (list->exten==e) {
1752 cblist = list->callbacks;
1754 /* Notify with -1 and remove all callbacks */
1756 cblist = cblist->next;
1757 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1760 list->callbacks = NULL;
1765 prev->next = list->next;
1768 ast_mutex_unlock(&hintlock);
1776 ast_mutex_unlock(&hintlock);
1781 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1783 struct ast_exten *e;
1784 e = ast_hint_extension(c, context, exten);
1786 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1792 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1794 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1797 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1799 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1802 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1804 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1807 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1809 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1812 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1814 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1817 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1819 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1822 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1824 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1827 int ast_pbx_run(struct ast_channel *c)
1836 /* A little initial setup here */
1838 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1839 c->pbx = malloc(sizeof(struct ast_pbx));
1841 ast_log(LOG_ERROR, "Out of memory\n");
1846 c->cdr = ast_cdr_alloc();
1848 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1852 ast_cdr_init(c->cdr, c);
1855 memset(c->pbx, 0, sizeof(struct ast_pbx));
1856 /* Set reasonable defaults */
1857 c->pbx->rtimeout = 10;
1858 c->pbx->dtimeout = 5;
1860 /* Start by trying whatever the channel is set to */
1861 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1862 /* JK02: If not successfull fall back to 's' */
1863 if (option_verbose > 1)
1864 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);
1865 strncpy(c->exten, "s", sizeof(c->exten)-1);
1866 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1867 /* JK02: And finally back to default if everything else failed */
1868 if (option_verbose > 1)
1869 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);
1870 strncpy(c->context, "default", sizeof(c->context)-1);
1874 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1875 ast_cdr_start(c->cdr);
1879 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1880 memset(exten, 0, sizeof(exten));
1881 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1882 /* Something bad happened, or a hangup has been requested. */
1883 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1884 (res == '*') || (res == '#')) {
1885 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1886 memset(exten, 0, sizeof(exten));
1888 exten[pos++] = digit = res;
1892 case AST_PBX_KEEPALIVE:
1894 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1895 else if (option_verbose > 1)
1896 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1901 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1902 else if (option_verbose > 1)
1903 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1904 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1909 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1919 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1920 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1921 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1922 c->whentohangup = 0;
1924 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1925 } else if (c->_softhangup) {
1926 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1927 c->exten, c->priority);
1933 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1934 /* It's not a valid extension anymore */
1935 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1936 if (option_verbose > 2)
1937 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1938 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1939 strncpy(c->exten, "i", sizeof(c->exten)-1);
1942 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1943 c->name, c->exten, c->context);
1946 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1947 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1950 /* Done, wait for an extension */
1953 waittime = c->pbx->dtimeout;
1954 else if (!autofallthrough)
1955 waittime = c->pbx->rtimeout;
1957 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1958 /* As long as we're willing to wait, and as long as it's not defined,
1959 keep reading digits until we can't possibly get a right answer anymore. */
1960 digit = ast_waitfordigit(c, waittime * 1000);
1961 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1968 /* Error, maybe a hangup */
1970 exten[pos++] = digit;
1971 waittime = c->pbx->dtimeout;
1974 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1975 /* Prepare the next cycle */
1976 strncpy(c->exten, exten, sizeof(c->exten)-1);
1979 /* No such extension */
1980 if (!ast_strlen_zero(exten)) {
1981 /* An invalid extension */
1982 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1983 if (option_verbose > 2)
1984 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1985 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1986 strncpy(c->exten, "i", sizeof(c->exten)-1);
1989 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
1993 /* A simple timeout */
1994 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
1995 if (option_verbose > 2)
1996 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1997 strncpy(c->exten, "t", sizeof(c->exten)-1);
2000 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2006 if (option_verbose > 2)
2007 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2011 if (option_verbose > 0) {
2013 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2016 if (option_verbose > 2)
2017 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2018 if (!strcasecmp(status, "CONGESTION"))
2019 res = pbx_builtin_congestion(c, "10");
2020 else if (!strcasecmp(status, "CHANUNAVAIL"))
2021 res = pbx_builtin_congestion(c, "10");
2022 else if (!strcasecmp(status, "BUSY"))
2023 res = pbx_builtin_busy(c, "10");
2030 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2032 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2036 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2037 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2038 /* Something bad happened, or a hangup has been requested. */
2040 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2041 else if (option_verbose > 1)
2042 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2049 pbx_destroy(c->pbx);
2051 if (res != AST_PBX_KEEPALIVE)
2056 static void *pbx_thread(void *data)
2058 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2059 answer this channel and get it going. The setjmp stuff is fairly
2060 confusing, but necessary to get smooth transitions between
2061 the execution of different applications (without the use of
2062 additional threads) */
2063 struct ast_channel *c = data;
2069 int ast_pbx_start(struct ast_channel *c)
2072 pthread_attr_t attr;
2074 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2078 /* Start a new thread, and get something handling this channel. */
2079 pthread_attr_init(&attr);
2080 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2081 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2082 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2088 int pbx_set_autofallthrough(int newval)
2091 oldval = autofallthrough;
2092 if (oldval != newval)
2093 autofallthrough = newval;
2098 * This function locks contexts list by &conlist, search for the right context
2099 * structure, leave context list locked and call ast_context_remove_include2
2100 * which removes include, unlock contexts list and return ...
2102 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2104 struct ast_context *c;
2106 if (ast_lock_contexts()) return -1;
2108 /* walk contexts and search for the right one ...*/
2109 c = ast_walk_contexts(NULL);
2111 /* we found one ... */
2112 if (!strcmp(ast_get_context_name(c), context)) {
2114 /* remove include from this context ... */
2115 ret = ast_context_remove_include2(c, include, registrar);
2117 ast_unlock_contexts();
2119 /* ... return results */
2122 c = ast_walk_contexts(c);
2125 /* we can't find the right one context */
2126 ast_unlock_contexts();
2131 * When we call this function, &conlock lock must be locked, because when
2132 * we giving *con argument, some process can remove/change this context
2133 * and after that there can be segfault.
2135 * This function locks given context, removes include, unlock context and
2138 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2140 struct ast_include *i, *pi = NULL;
2142 if (ast_mutex_lock(&con->lock)) return -1;
2147 /* find our include */
2148 if (!strcmp(i->name, include) &&
2149 (!registrar || !strcmp(i->registrar, registrar))) {
2150 /* remove from list */
2154 con->includes = i->next;
2155 /* free include and return */
2157 ast_mutex_unlock(&con->lock);
2164 /* we can't find the right include */
2165 ast_mutex_unlock(&con->lock);
2170 * This function locks contexts list by &conlist, search for the rigt context
2171 * structure, leave context list locked and call ast_context_remove_switch2
2172 * which removes switch, unlock contexts list and return ...
2174 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2176 struct ast_context *c;
2178 if (ast_lock_contexts()) return -1;
2180 /* walk contexts and search for the right one ...*/
2181 c = ast_walk_contexts(NULL);
2183 /* we found one ... */
2184 if (!strcmp(ast_get_context_name(c), context)) {
2186 /* remove switch from this context ... */
2187 ret = ast_context_remove_switch2(c, sw, data, registrar);
2189 ast_unlock_contexts();
2191 /* ... return results */
2194 c = ast_walk_contexts(c);
2197 /* we can't find the right one context */
2198 ast_unlock_contexts();
2203 * When we call this function, &conlock lock must be locked, because when
2204 * we giving *con argument, some process can remove/change this context
2205 * and after that there can be segfault.
2207 * This function locks given context, removes switch, unlock context and
2210 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2212 struct ast_sw *i, *pi = NULL;
2214 if (ast_mutex_lock(&con->lock)) return -1;
2219 /* find our switch */
2220 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2221 (!registrar || !strcmp(i->registrar, registrar))) {
2222 /* remove from list */
2226 con->alts = i->next;
2227 /* free switch and return */
2229 ast_mutex_unlock(&con->lock);
2236 /* we can't find the right switch */
2237 ast_mutex_unlock(&con->lock);
2242 * This functions lock contexts list, search for the right context,
2243 * call ast_context_remove_extension2, unlock contexts list and return.
2244 * In this function we are using
2246 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2248 struct ast_context *c;
2250 if (ast_lock_contexts()) return -1;
2252 /* walk contexts ... */
2253 c = ast_walk_contexts(NULL);
2255 /* ... search for the right one ... */
2256 if (!strcmp(ast_get_context_name(c), context)) {
2257 /* ... remove extension ... */
2258 int ret = ast_context_remove_extension2(c, extension, priority,
2260 /* ... unlock contexts list and return */
2261 ast_unlock_contexts();
2264 c = ast_walk_contexts(c);
2267 /* we can't find the right context */
2268 ast_unlock_contexts();
2273 * When do you want to call this function, make sure that &conlock is locked,
2274 * because some process can handle with your *con context before you lock
2277 * This functionc locks given context, search for the right extension and
2278 * fires out all peer in this extensions with given priority. If priority
2279 * is set to 0, all peers are removed. After that, unlock context and
2282 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2284 struct ast_exten *exten, *prev_exten = NULL;
2286 if (ast_mutex_lock(&con->lock)) return -1;
2288 /* go through all extensions in context and search the right one ... */
2292 /* look for right extension */
2293 if (!strcmp(exten->exten, extension) &&
2294 (!registrar || !strcmp(exten->registrar, registrar))) {
2295 struct ast_exten *peer;
2297 /* should we free all peers in this extension? (priority == 0)? */
2298 if (priority == 0) {
2299 /* remove this extension from context list */
2301 prev_exten->next = exten->next;
2303 con->root = exten->next;
2305 /* fire out all peers */
2310 if (!peer->priority==PRIORITY_HINT)
2311 ast_remove_hint(peer);
2313 peer->datad(peer->data);
2319 ast_mutex_unlock(&con->lock);
2322 /* remove only extension with exten->priority == priority */
2323 struct ast_exten *previous_peer = NULL;
2327 /* is this our extension? */
2328 if (peer->priority == priority &&
2329 (!registrar || !strcmp(peer->registrar, registrar) )) {
2330 /* we are first priority extension? */
2331 if (!previous_peer) {
2332 /* exists previous extension here? */
2334 /* yes, so we must change next pointer in
2335 * previous connection to next peer
2338 prev_exten->next = peer->peer;
2339 peer->peer->next = exten->next;
2341 prev_exten->next = exten->next;
2343 /* no previous extension, we are first
2344 * extension, so change con->root ...
2347 con->root = peer->peer;
2349 con->root = exten->next;
2352 /* we are not first priority in extension */
2353 previous_peer->peer = peer->peer;
2356 /* now, free whole priority extension */
2357 if (peer->priority==PRIORITY_HINT)
2358 ast_remove_hint(peer);
2359 peer->datad(peer->data);
2362 ast_mutex_unlock(&con->lock);
2365 /* this is not right extension, skip to next peer */
2366 previous_peer = peer;
2371 ast_mutex_unlock(&con->lock);
2377 exten = exten->next;
2380 /* we can't find right extension */
2381 ast_mutex_unlock(&con->lock);
2386 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2388 struct ast_app *tmp, *prev, *cur;
2391 length = sizeof(struct ast_app);
2392 length += strlen(app) + 1;
2393 if (ast_mutex_lock(&applock)) {
2394 ast_log(LOG_ERROR, "Unable to lock application list\n");
2399 if (!strcasecmp(app, tmp->name)) {
2400 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2401 ast_mutex_unlock(&applock);
2406 tmp = malloc(length);
2408 memset(tmp, 0, length);
2409 strcpy(tmp->name, app);
2410 tmp->execute = execute;
2411 tmp->synopsis = synopsis;
2412 tmp->description = description;
2413 /* Store in alphabetical order */
2417 if (strcasecmp(tmp->name, cur->name) < 0)
2423 tmp->next = prev->next;
2430 ast_log(LOG_ERROR, "Out of memory\n");
2431 ast_mutex_unlock(&applock);
2434 if (option_verbose > 1)
2435 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2436 ast_mutex_unlock(&applock);
2440 int ast_register_switch(struct ast_switch *sw)
2442 struct ast_switch *tmp, *prev=NULL;
2443 if (ast_mutex_lock(&switchlock)) {
2444 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2449 if (!strcasecmp(tmp->name, sw->name))
2455 ast_mutex_unlock(&switchlock);
2456 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2464 ast_mutex_unlock(&switchlock);
2468 void ast_unregister_switch(struct ast_switch *sw)
2470 struct ast_switch *tmp, *prev=NULL;
2471 if (ast_mutex_lock(&switchlock)) {
2472 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2479 prev->next = tmp->next;
2481 switches = tmp->next;
2488 ast_mutex_unlock(&switchlock);
2492 * Help for CLI commands ...
2494 static char show_application_help[] =
2495 "Usage: show application <application> [<application> [<application> [...]]]\n"
2496 " Describes a particular application.\n";
2498 static char show_applications_help[] =
2499 "Usage: show applications [{like|describing} <text>]\n"
2500 " List applications which are currently available.\n"
2501 " If 'like', <text> will be a substring of the app name\n"
2502 " If 'describing', <text> will be a substring of the description\n";
2504 static char show_dialplan_help[] =
2505 "Usage: show dialplan [exten@][context]\n"
2508 static char show_switches_help[] =
2509 "Usage: show switches\n"
2510 " Show registered switches\n";
2513 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2518 * 'show application' CLI command implementation functions ...
2522 * There is a possibility to show informations about more than one
2523 * application at one time. You can type 'show application Dial Echo' and
2524 * you will see informations about these two applications ...
2526 static char *complete_show_application(char *line, char *word,
2532 /* try to lock applications list ... */
2533 if (ast_mutex_lock(&applock)) {
2534 ast_log(LOG_ERROR, "Unable to lock application list\n");
2538 /* ... walk all applications ... */
2541 /* ... check if word matches this application ... */
2542 if (!strncasecmp(word, a->name, strlen(word))) {
2543 /* ... if this is right app serve it ... */
2544 if (++which > state) {
2545 char *ret = strdup(a->name);
2546 ast_mutex_unlock(&applock);
2553 /* no application match */
2554 ast_mutex_unlock(&applock);
2558 static int handle_show_application(int fd, int argc, char *argv[])
2561 int app, no_registered_app = 1;
2563 if (argc < 3) return RESULT_SHOWUSAGE;
2565 /* try to lock applications list ... */
2566 if (ast_mutex_lock(&applock)) {
2567 ast_log(LOG_ERROR, "Unable to lock application list\n");
2571 /* ... go through all applications ... */
2574 /* ... compare this application name with all arguments given
2575 * to 'show application' command ... */
2576 for (app = 2; app < argc; app++) {
2577 if (!strcasecmp(a->name, argv[app])) {
2578 /* Maximum number of characters added by terminal coloring is 22 */
2579 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2580 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2581 int synopsis_size, description_size;
2583 no_registered_app = 0;
2586 synopsis_size = strlen(a->synopsis) + 23;
2588 synopsis_size = strlen("Not available") + 23;
2589 synopsis = alloca(synopsis_size);
2592 description_size = strlen(a->description) + 23;
2594 description_size = strlen("Not available") + 23;
2595 description = alloca(description_size);
2597 if (synopsis && description) {
2598 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2599 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2600 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2601 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2602 term_color(synopsis,
2603 a->synopsis ? a->synopsis : "Not available",
2604 COLOR_CYAN, 0, synopsis_size);
2605 term_color(description,
2606 a->description ? a->description : "Not available",
2607 COLOR_CYAN, 0, description_size);
2609 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2611 /* ... one of our applications, show info ...*/
2612 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2613 "[Synopsis]:\n %s\n\n"
2614 "[Description]:\n%s\n",
2616 a->synopsis ? a->synopsis : "Not available",
2617 a->description ? a->description : "Not available");
2624 ast_mutex_unlock(&applock);
2626 /* we found at least one app? no? */
2627 if (no_registered_app) {
2628 ast_cli(fd, "Your application(s) is (are) not registered\n");
2629 return RESULT_FAILURE;
2632 return RESULT_SUCCESS;
2635 static int handle_show_switches(int fd, int argc, char *argv[])
2637 struct ast_switch *sw;
2639 ast_cli(fd, "There are no registered alternative switches\n");
2640 return RESULT_SUCCESS;
2642 /* ... we have applications ... */
2643 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2644 if (ast_mutex_lock(&switchlock)) {
2645 ast_log(LOG_ERROR, "Unable to lock switches\n");
2650 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2653 ast_mutex_unlock(&switchlock);
2654 return RESULT_SUCCESS;
2658 * 'show applications' CLI command implementation functions ...
2660 static int handle_show_applications(int fd, int argc, char *argv[])
2663 int like=0, describing=0;
2665 /* try to lock applications list ... */
2666 if (ast_mutex_lock(&applock)) {
2667 ast_log(LOG_ERROR, "Unable to lock application list\n");
2671 /* ... have we got at least one application (first)? no? */
2673 ast_cli(fd, "There are no registered applications\n");
2674 ast_mutex_unlock(&applock);
2678 /* show applications like <keyword> */
2679 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2681 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2685 /* show applications describing <keyword1> [<keyword2>] [...] */
2686 if ((!like) && (!describing)) {
2687 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2689 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2692 /* ... go through all applications ... */
2693 for (a = apps; a; a = a->next) {
2694 /* ... show informations about applications ... */
2698 if (ast_strcasestr(a->name, argv[3])) {
2701 } else if (describing) {
2702 if (a->description) {
2703 /* Match all words on command line */
2706 for (i=3;i<argc;i++) {
2707 if (! ast_strcasestr(a->description, argv[i])) {
2717 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2721 /* ... unlock and return */
2722 ast_mutex_unlock(&applock);
2724 return RESULT_SUCCESS;
2727 static char *complete_show_applications(char *line, char *word, int pos, int state)
2730 if (ast_strlen_zero(word)) {
2733 return strdup("like");
2735 return strdup("describing");
2739 } else if (! strncasecmp(word, "like", strlen(word))) {
2741 return strdup("like");
2745 } else if (! strncasecmp(word, "describing", strlen(word))) {
2747 return strdup("describing");
2757 * 'show dialplan' CLI command implementation functions ...
2759 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2762 struct ast_context *c;
2765 /* we are do completion of [exten@]context on second position only */
2766 if (pos != 2) return NULL;
2768 /* try to lock contexts list ... */
2769 if (ast_lock_contexts()) {
2770 ast_log(LOG_ERROR, "Unable to lock context list\n");
2774 /* ... walk through all contexts ... */
2775 c = ast_walk_contexts(NULL);
2777 /* ... word matches context name? yes? ... */
2778 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2779 /* ... for serve? ... */
2780 if (++which > state) {
2781 /* ... yes, serve this context name ... */
2782 char *ret = strdup(ast_get_context_name(c));
2783 ast_unlock_contexts();
2787 c = ast_walk_contexts(c);
2790 /* ... unlock and return */
2791 ast_unlock_contexts();
2795 static int handle_show_dialplan(int fd, int argc, char *argv[])
2797 struct ast_context *c;
2798 char *exten = NULL, *context = NULL;
2799 int context_existence = 0, extension_existence = 0;
2801 if (argc != 3 && argc != 2) return -1;
2803 /* we obtain [exten@]context? if yes, split them ... */
2805 char *splitter = argv[2];
2806 /* is there a '@' character? */
2807 if (strchr(argv[2], '@')) {
2808 /* yes, split into exten & context ... */
2809 exten = strsep(&splitter, "@");
2812 /* check for length and change to NULL if ast_strlen_zero() */
2813 if (ast_strlen_zero(exten)) exten = NULL;
2814 if (ast_strlen_zero(context)) context = NULL;
2817 /* no '@' char, only context given */
2819 if (ast_strlen_zero(context)) context = NULL;
2823 /* try to lock contexts */
2824 if (ast_lock_contexts()) {
2825 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2826 return RESULT_FAILURE;
2829 /* walk all contexts ... */
2830 c = ast_walk_contexts(NULL);
2832 /* show this context? */
2834 !strcmp(ast_get_context_name(c), context)) {
2835 context_existence = 1;
2837 /* try to lock context before walking in ... */
2838 if (!ast_lock_context(c)) {
2839 struct ast_exten *e;
2840 struct ast_include *i;
2841 struct ast_ignorepat *ip;
2843 char buf[256], buf2[256];
2844 int context_info_printed = 0;
2846 /* are we looking for exten too? if yes, we print context
2847 * if we our extension only
2850 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2851 ast_get_context_name(c), ast_get_context_registrar(c));
2852 context_info_printed = 1;
2855 /* walk extensions ... */
2856 e = ast_walk_context_extensions(c, NULL);
2858 struct ast_exten *p;
2860 /* looking for extension? is this our extension? */
2862 strcmp(ast_get_extension_name(e), exten))
2864 /* we are looking for extension and it's not our
2865 * extension, so skip to next extension */
2866 e = ast_walk_context_extensions(c, e);
2870 extension_existence = 1;
2872 /* may we print context info? */
2873 if (!context_info_printed) {
2874 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2875 ast_get_context_name(c),
2876 ast_get_context_registrar(c));
2877 context_info_printed = 1;
2880 /* write extension name and first peer */
2881 bzero(buf, sizeof(buf));
2882 snprintf(buf, sizeof(buf), "'%s' =>",
2883 ast_get_extension_name(e));
2885 snprintf(buf2, sizeof(buf2),
2887 ast_get_extension_priority(e),
2888 ast_get_extension_app(e),
2889 (char *)ast_get_extension_app_data(e));
2891 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2892 ast_get_extension_registrar(e));
2894 /* walk next extension peers */
2895 p = ast_walk_extension_priorities(e, e);
2897 bzero((void *)buf2, sizeof(buf2));
2898 bzero((void *)buf, sizeof(buf));
2899 if (ast_get_extension_label(p))
2900 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
2901 snprintf(buf2, sizeof(buf2),
2903 ast_get_extension_priority(p),
2904 ast_get_extension_app(p),
2905 (char *)ast_get_extension_app_data(p));
2907 ast_cli(fd," %-17s %-45s [%s]\n",
2909 ast_get_extension_registrar(p));
2911 p = ast_walk_extension_priorities(e, p);
2913 e = ast_walk_context_extensions(c, e);
2916 /* include & ignorepat we all printing if we are not
2917 * looking for exact extension
2920 if (ast_walk_context_extensions(c, NULL))
2923 /* walk included and write info ... */
2924 i = ast_walk_context_includes(c, NULL);
2926 bzero(buf, sizeof(buf));
2927 snprintf(buf, sizeof(buf), "'%s'",
2928 ast_get_include_name(i));
2929 ast_cli(fd, " Include => %-45s [%s]\n",
2930 buf, ast_get_include_registrar(i));
2931 i = ast_walk_context_includes(c, i);
2934 /* walk ignore patterns and write info ... */
2935 ip = ast_walk_context_ignorepats(c, NULL);
2937 bzero(buf, sizeof(buf));
2938 snprintf(buf, sizeof(buf), "'%s'",
2939 ast_get_ignorepat_name(ip));
2940 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2941 buf, ast_get_ignorepat_registrar(ip));
2942 ip = ast_walk_context_ignorepats(c, ip);
2944 sw = ast_walk_context_switches(c, NULL);
2946 bzero(buf, sizeof(buf));
2947 snprintf(buf, sizeof(buf), "'%s/%s'",
2948 ast_get_switch_name(sw),
2949 ast_get_switch_data(sw));
2950 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2951 buf, ast_get_switch_registrar(sw));
2952 sw = ast_walk_context_switches(c, sw);
2956 ast_unlock_context(c);
2958 /* if we print something in context, make an empty line */
2959 if (context_info_printed) ast_cli(fd, "\n");
2962 c = ast_walk_contexts(c);
2964 ast_unlock_contexts();
2966 /* check for input failure and throw some error messages */
2967 if (context && !context_existence) {
2968 ast_cli(fd, "There is no existence of '%s' context\n",
2970 return RESULT_FAILURE;
2973 if (exten && !extension_existence) {
2975 ast_cli(fd, "There is no existence of %s@%s extension\n",
2979 "There is no existence of '%s' extension in all contexts\n",
2981 return RESULT_FAILURE;
2985 return RESULT_SUCCESS;
2989 * CLI entries for upper commands ...
2991 static struct ast_cli_entry show_applications_cli =
2992 { { "show", "applications", NULL },
2993 handle_show_applications, "Shows registered applications",
2994 show_applications_help, complete_show_applications };
2996 static struct ast_cli_entry show_application_cli =
2997 { { "show", "application", NULL },
2998 handle_show_application, "Describe a specific application",
2999 show_application_help, complete_show_application };
3001 static struct ast_cli_entry show_dialplan_cli =
3002 { { "show", "dialplan", NULL },
3003 handle_show_dialplan, "Show dialplan",
3004 show_dialplan_help, complete_show_dialplan_context };
3006 static struct ast_cli_entry show_switches_cli =
3007 { { "show", "switches", NULL },
3008 handle_show_switches, "Show alternative switches",
3009 show_switches_help, NULL };
3011 int ast_unregister_application(const char *app) {
3012 struct ast_app *tmp, *tmpl = NULL;
3013 if (ast_mutex_lock(&applock)) {
3014 ast_log(LOG_ERROR, "Unable to lock application list\n");
3019 if (!strcasecmp(app, tmp->name)) {
3021 tmpl->next = tmp->next;
3024 if (option_verbose > 1)
3025 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3027 ast_mutex_unlock(&applock);
3033 ast_mutex_unlock(&applock);
3037 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3039 struct ast_context *tmp, **local_contexts;
3041 length = sizeof(struct ast_context);
3042 length += strlen(name) + 1;
3044 local_contexts = &contexts;
3045 ast_mutex_lock(&conlock);
3047 local_contexts = extcontexts;
3049 tmp = *local_contexts;
3051 if (!strcasecmp(tmp->name, name)) {
3052 ast_mutex_unlock(&conlock);
3053 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3055 ast_mutex_unlock(&conlock);
3060 tmp = malloc(length);
3062 memset(tmp, 0, length);
3063 ast_mutex_init(&tmp->lock);
3064 strcpy(tmp->name, name);
3066 tmp->registrar = registrar;
3067 tmp->next = *local_contexts;
3068 tmp->includes = NULL;
3069 tmp->ignorepats = NULL;
3070 *local_contexts = tmp;
3072 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3073 else if (option_verbose > 2)
3074 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3076 ast_log(LOG_ERROR, "Out of memory\n");
3079 ast_mutex_unlock(&conlock);
3083 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3085 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) {
3086 struct ast_context *tmp, *lasttmp = NULL;
3088 ast_mutex_lock(&conlock);
3090 __ast_context_destroy(NULL,registrar);
3097 __ast_context_destroy(tmp,tmp->registrar);
3103 lasttmp->next = contexts;
3104 contexts = *extcontexts;
3105 *extcontexts = NULL;
3107 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3108 ast_mutex_unlock(&conlock);
3114 * EBUSY - can't lock
3115 * ENOENT - no existence of context
3117 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3119 struct ast_context *c;
3121 if (ast_lock_contexts()) {
3126 /* walk contexts ... */
3127 c = ast_walk_contexts(NULL);
3129 /* ... search for the right one ... */
3130 if (!strcmp(ast_get_context_name(c), context)) {
3131 int ret = ast_context_add_include2(c, include, registrar);
3132 /* ... unlock contexts list and return */
3133 ast_unlock_contexts();
3136 c = ast_walk_contexts(c);
3139 /* we can't find the right context */
3140 ast_unlock_contexts();
3148 while(*c && (*c != '|')) c++; \
3149 if (*c) { *c = '\0'; c++; } else c = NULL; \
3152 static void get_timerange(struct ast_include *i, char *times)
3160 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3161 memset(i->minmask, 0, sizeof(i->minmask));
3163 /* Star is all times */
3164 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3166 i->minmask[x] = (1 << 30) - 1;
3169 /* Otherwise expect a range */
3170 e = strchr(times, '-');
3172 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3177 while(*e && !isdigit(*e)) e++;
3179 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3182 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3183 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3186 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3187 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3192 s1 = s1 * 30 + s2/2;
3193 if ((s1 < 0) || (s1 >= 24*30)) {
3194 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3197 e1 = e1 * 30 + e2/2;
3198 if ((e1 < 0) || (e1 >= 24*30)) {
3199 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3202 /* Go through the time and enable each appropriate bit */
3203 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3204 i->minmask[x/30] |= (1 << (x % 30));
3206 /* Do the last one */
3207 i->minmask[x/30] |= (1 << (x % 30));
3209 for (cth=0;cth<24;cth++) {
3210 /* Initialize masks to blank */
3211 i->minmask[cth] = 0;
3212 for (ctm=0;ctm<30;ctm++) {
3214 /* First hour with more than one hour */
3215 (((cth == s1) && (ctm >= s2)) &&
3218 || (((cth == s1) && (ctm >= s2)) &&
3219 ((cth == e1) && (ctm <= e2)))
3220 /* In between first and last hours (more than 2 hours) */
3223 /* Last hour with more than one hour */
3225 ((cth == e1) && (ctm <= e2)))
3227 i->minmask[cth] |= (1 << (ctm / 2));
3235 static char *days[] =
3246 static unsigned int get_dow(char *dow)
3249 /* The following line is coincidence, really! */
3253 /* Check for all days */
3254 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3255 return (1 << 7) - 1;
3256 /* Get start and ending days */
3257 c = strchr(dow, '-');
3263 /* Find the start */
3265 while((s < 7) && strcasecmp(dow, days[s])) s++;
3267 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3272 while((e < 7) && strcasecmp(c, days[e])) e++;
3274 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3280 for (x=s; x != e; x = (x + 1) % 7) {
3288 static unsigned int get_day(char *day)
3291 /* The following line is coincidence, really! */
3295 /* Check for all days */
3296 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3297 mask = (1 << 30) + ((1 << 30) - 1);
3300 /* Get start and ending days */
3301 c = strchr(day, '-');
3306 /* Find the start */
3307 if (sscanf(day, "%d", &s) != 1) {
3308 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3311 if ((s < 1) || (s > 31)) {
3312 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3317 if (sscanf(c, "%d", &e) != 1) {
3318 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3321 if ((e < 1) || (e > 31)) {
3322 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3329 for (x=s;x!=e;x = (x + 1) % 31) {
3336 static char *months[] =
3352 static unsigned int get_month(char *mon)
3355 /* The following line is coincidence, really! */
3359 /* Check for all days */
3360 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
3361 return (1 << 12) - 1;
3362 /* Get start and ending days */
3363 c = strchr(mon, '-');
3368 /* Find the start */
3370 while((s < 12) && strcasecmp(mon, months[s])) s++;
3372 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3377 while((e < 12) && strcasecmp(mon, months[e])) e++;
3379 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3385 for (x=s; x!=e; x = (x + 1) % 12) {
3393 static void build_timing(struct ast_include *i, char *info)
3397 /* Check for empty just in case */
3398 if (ast_strlen_zero(info))
3401 /* Assume everything except time */
3402 i->monthmask = (1 << 12) - 1;
3403 i->daymask = (1 << 30) - 1 + (1 << 30);
3404 i->dowmask = (1 << 7) - 1;
3405 /* Avoid using str tok */
3407 /* Info has the time range, start with that */
3408 get_timerange(i, info);
3413 /* Now check for day of week */
3414 i->dowmask = get_dow(info);
3420 /* Now check for the day of the month */
3421 i->daymask = get_day(info);
3426 /* And finally go for the month */
3427 i->monthmask = get_month(info);
3432 * ENOMEM - out of memory
3433 * EBUSY - can't lock
3434 * EEXIST - already included
3435 * EINVAL - there is no existence of context for inclusion
3437 int ast_context_add_include2(struct ast_context *con, const char *value,
3438 const char *registrar)
3440 struct ast_include *new_include;
3442 struct ast_include *i, *il = NULL; /* include, include_last */
3446 length = sizeof(struct ast_include);
3447 length += 2 * (strlen(value) + 1);
3449 /* allocate new include structure ... */
3450 if (!(new_include = malloc(length))) {
3451 ast_log(LOG_ERROR, "Out of memory\n");
3456 /* ... fill in this structure ... */
3457 memset(new_include, 0, length);
3458 p = new_include->stuff;
3459 new_include->name = p;
3460 strcpy(new_include->name, value);
3461 p += strlen(value) + 1;
3462 new_include->rname = p;
3463 strcpy(new_include->rname, value);
3464 c = new_include->rname;
3465 /* Strip off timing info */
3466 while(*c && (*c != '|')) c++;
3467 /* Process if it's there */
3469 build_timing(new_include, c+1);