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>
45 * The speed of extension handling will likely be among the most important
46 * aspects of this PBX. The switching scheme as it exists right now isn't
47 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
48 * of priorities, but a constant search time here would be great ;-)
53 #define EXT_DATA_SIZE 256
55 #define EXT_DATA_SIZE 8192
60 /* ast_exten: An extension */
62 char *exten; /* Extension name */
63 int matchcid; /* Match caller id ? */
64 char *cidmatch; /* Caller id to match for this extension */
65 int priority; /* Priority */
66 char *label; /* Label */
67 struct ast_context *parent; /* An extension */
68 char *app; /* Application to execute */
69 void *data; /* Data to use */
70 void (*datad)(void *); /* Data destructor */
71 struct ast_exten *peer; /* Next higher priority with our extension */
72 const char *registrar; /* Registrar */
73 struct ast_exten *next; /* Extension with a greater ID */
77 /* ast_include: include= support in extensions.conf */
80 char *rname; /* Context to include */
81 const char *registrar; /* Registrar */
82 int hastime; /* If time construct exists */
83 unsigned int monthmask; /* Mask for month */
84 unsigned int daymask; /* Mask for date */
85 unsigned int dowmask; /* Mask for day of week (mon-sun) */
86 unsigned int minmask[24]; /* Mask for minute */
87 struct ast_include *next; /* Link them together */
91 /* ast_sw: Switch statement in extensions.conf */
94 const char *registrar; /* Registrar */
95 char *data; /* Data load */
96 struct ast_sw *next; /* Link them together */
100 struct ast_ignorepat {
101 const char *registrar;
102 struct ast_ignorepat *next;
106 /* ast_context: An extension context */
108 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
109 struct ast_exten *root; /* The root of the list of extensions */
110 struct ast_context *next; /* Link them together */
111 struct ast_include *includes; /* Include other contexts */
112 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
113 const char *registrar; /* Registrar */
114 struct ast_sw *alts; /* Alternative switches */
115 char name[0]; /* Name of the context */
119 /* ast_app: An application */
121 int (*execute)(struct ast_channel *chan, void *data);
122 const char *synopsis; /* Synopsis text for 'show applications' */
123 const char *description; /* Description (help text) for 'show application <name>' */
124 struct ast_app *next; /* Next app in list */
125 char name[0]; /* Name of the application */
128 /* ast_state_cb: An extension state notify */
129 struct ast_state_cb {
132 ast_state_cb_type callback;
133 struct ast_state_cb *next;
137 struct ast_exten *exten;
139 struct ast_state_cb *callbacks;
140 struct ast_hint *next;
144 static int pbx_builtin_prefix(struct ast_channel *, void *);
145 static int pbx_builtin_suffix(struct ast_channel *, void *);
146 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
147 static int pbx_builtin_answer(struct ast_channel *, void *);
148 static int pbx_builtin_goto(struct ast_channel *, void *);
149 static int pbx_builtin_hangup(struct ast_channel *, void *);
150 static int pbx_builtin_background(struct ast_channel *, void *);
151 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
152 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
153 static int pbx_builtin_atimeout(struct ast_channel *, void *);
154 static int pbx_builtin_wait(struct ast_channel *, void *);
155 static int pbx_builtin_waitexten(struct ast_channel *, void *);
156 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
157 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
158 static int pbx_builtin_setaccount(struct ast_channel *, void *);
159 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
160 static int pbx_builtin_ringing(struct ast_channel *, void *);
161 static int pbx_builtin_progress(struct ast_channel *, void *);
162 static int pbx_builtin_congestion(struct ast_channel *, void *);
163 static int pbx_builtin_busy(struct ast_channel *, void *);
164 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
165 static int pbx_builtin_noop(struct ast_channel *, void *);
166 static int pbx_builtin_gotoif(struct ast_channel *, void *);
167 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
168 static int pbx_builtin_saynumber(struct ast_channel *, void *);
169 static int pbx_builtin_saydigits(struct ast_channel *, void *);
170 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
171 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
172 int pbx_builtin_setvar(struct ast_channel *, void *);
173 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
174 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
176 static struct varshead globals;
178 static struct pbx_builtin {
179 char name[AST_MAX_APP];
180 int (*execute)(struct ast_channel *chan, void *data);
185 /* These applications are built into the PBX core and do not
186 need separate modules
190 { "AbsoluteTimeout", pbx_builtin_atimeout,
191 "Set absolute maximum time of call",
192 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
193 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
196 { "Answer", pbx_builtin_answer,
197 "Answer a channel if ringing",
198 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
199 "Returns 0 unless it tries to answer the channel and fails.\n"
202 { "BackGround", pbx_builtin_background,
203 "Play a file while awaiting extension",
204 " Background(filename[|options[|langoverride]]): Plays a given file, while simultaneously\n"
205 "waiting for the user to begin typing an extension. The timeouts do not\n"
206 "count until the last BackGround application has ended.\n"
207 "Options may also be included following a pipe symbol. The 'skip'\n"
208 "option causes the playback of the message to be skipped if the channel\n"
209 "is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
210 "specified, the application will return immediately should the channel not be\n"
211 "off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
212 "be answered before the sound is played. Not all channels support playing\n"
213 "messages while still hook. The 'langoverride' may be a language to use for\n"
214 "playing the prompt which differs from the current language of the channel\n"
215 "Returns -1 if the channel was hung up, or if the file does not exist. \n"
216 "Returns 0 otherwise.\n"
219 { "Busy", pbx_builtin_busy,
220 "Indicate busy condition and stop",
221 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
222 "then waits for the user to hang up or the optional timeout to expire.\n"
226 { "Congestion", pbx_builtin_congestion,
227 "Indicate congestion and stop",
228 " Congestion([timeout]): Requests that the channel indicate congestion\n"
229 "and then waits for the user to hang up or for the optional timeout to\n"
230 "expire. Always returns -1."
233 { "DigitTimeout", pbx_builtin_dtimeout,
234 "Set maximum timeout between digits",
235 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
236 "digits when the user is typing in an extension. When this timeout expires,\n"
237 "after the user has started to type in an extension, the extension will be\n"
238 "considered complete, and will be interpreted. Note that if an extension\n"
239 "typed in is valid, it will not have to timeout to be tested, so typically\n"
240 "at the expiry of this timeout, the extension will be considered invalid\n"
241 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
242 "exist the call would be terminated). Always returns 0.\n"
245 { "Goto", pbx_builtin_goto,
246 "Goto a particular priority, extension, or context",
247 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
248 "value, optionally setting the extension and optionally the context as well.\n"
249 "The extension BYEXTENSION is special in that it uses the current extension,\n"
250 "thus permitting you to go to a different context, without specifying a\n"
251 "specific extension. Always returns 0, even if the given context, extension,\n"
252 "or priority is invalid.\n"
255 { "GotoIf", pbx_builtin_gotoif,
257 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
258 "true, to label2 if condition is false. Either label1 or label2 may be\n"
259 "omitted (in that case, we just don't take the particular branch) but not\n"
260 "both. Look for the condition syntax in examples or documentation."
263 { "GotoIfTime", pbx_builtin_gotoiftime,
264 "Conditional goto on current time",
265 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
266 "If the current time matches the specified time, then branch to the specified\n"
267 "extension. Each of the elements may be specified either as '*' (for always)\n"
268 "or as a range. See the 'include' syntax for details."
271 { "Hangup", pbx_builtin_hangup,
272 "Unconditional hangup",
273 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
276 { "NoOp", pbx_builtin_noop,
278 " NoOp(): No-operation; Does nothing."
281 { "Prefix", pbx_builtin_prefix,
282 "Prepend leading digits",
283 " Prefix(digits): Prepends the digit string specified by digits to the\n"
284 "channel's associated extension. For example, the number 1212 when prefixed\n"
285 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
286 "continue processing at the next priority for the *new* extension.\n"
287 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
288 "executed will be priority 4 of 5551212. If you switch into an extension\n"
289 "which has no first step, the PBX will treat it as though the user dialed an\n"
290 "invalid extension.\n"
293 { "Progress", pbx_builtin_progress,
295 " Progress(): Request that the channel indicate in-band progress is \n"
296 "available to the user.\nAlways returns 0.\n"
299 { "ResetCDR", pbx_builtin_resetcdr,
300 "Resets the Call Data Record",
301 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
302 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
303 "record WILL be stored.\nAlways returns 0.\n"
306 { "ResponseTimeout", pbx_builtin_rtimeout,
307 "Set maximum timeout awaiting response",
308 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
309 "falling through a series of priorities for a channel in which the user may\n"
310 "begin typing an extension. If the user does not type an extension in this\n"
311 "amount of time, control will pass to the 't' extension if it exists, and\n"
312 "if not the call would be terminated.\nAlways returns 0.\n"
315 { "Ringing", pbx_builtin_ringing,
316 "Indicate ringing tone",
317 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
318 "Always returns 0.\n"
321 { "SayNumber", pbx_builtin_saynumber,
323 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
324 "the current language setting for the channel. (See app SetLanguage).\n"
327 { "SayDigits", pbx_builtin_saydigits,
329 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
330 "current language setting for the channel. (See app setLanguage)\n"
333 { "SayAlpha", pbx_builtin_saycharacters,
335 " SayAlpha(string): Spells the passed string\n"
338 { "SayPhonetic", pbx_builtin_sayphonetic,
340 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
343 { "SetAccount", pbx_builtin_setaccount,
345 " SetAccount([account]): Set the channel account code for billing\n"
346 "purposes. Always returns 0.\n"
349 { "SetAMAFlags", pbx_builtin_setamaflags,
351 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
352 "purposes. Always returns 0.\n"
355 { "SetGlobalVar", pbx_builtin_setglobalvar,
356 "Set global variable to value",
357 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
358 "variable are available across channels.\n"
361 { "SetLanguage", pbx_builtin_setlanguage,
362 "Sets user language",
363 " SetLanguage(language): Set the channel language to 'language'. This\n"
364 "information is used for the syntax in generation of numbers, and to choose\n"
365 "a natural language file when available.\n"
366 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
367 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
368 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
369 "Always returns 0.\n"
372 { "SetVar", pbx_builtin_setvar,
373 "Set variable to value",
374 " Setvar(#n=value): Sets channel specific variable n to value"
377 { "StripMSD", pbx_builtin_stripmsd,
378 "Strip leading digits",
379 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
380 "associated extension. For example, the number 5551212 when stripped with a\n"
381 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
382 "will continue processing at the next priority for the *new* extension.\n"
383 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
384 "executed will be priority 4 of 1212. If you switch into an extension which\n"
385 "has no first step, the PBX will treat it as though the user dialed an\n"
386 "invalid extension.\n"
389 { "Suffix", pbx_builtin_suffix,
390 "Append trailing digits",
391 " Suffix(digits): Appends the digit string specified by digits to the\n"
392 "channel's associated extension. For example, the number 555 when suffixed\n"
393 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
394 "continue processing at the next priority for the *new* extension.\n"
395 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
396 "executed will be priority 4 of 5551212. If you switch into an extension\n"
397 "which has no first step, the PBX will treat it as though the user dialed an\n"
398 "invalid extension.\n"
401 { "Wait", pbx_builtin_wait,
402 "Waits for some time",
403 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
404 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
407 { "WaitExten", pbx_builtin_waitexten,
408 "Waits for some time",
409 " Wait(seconds): Waits for the user to enter a new extension for the \n"
410 "specified number of seconds, then returns 0. Seconds can be passed with\n"
411 "fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
416 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
417 static struct ast_context *contexts = NULL;
418 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
419 static struct ast_app *apps = NULL;
421 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
422 struct ast_switch *switches = NULL;
424 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
425 static int stateid = 1;
426 struct ast_hint *hints = NULL;
427 struct ast_state_cb *statecbs = NULL;
429 int pbx_exec(struct ast_channel *c, /* Channel */
430 struct ast_app *app, /* Application */
431 void *data, /* Data for execution */
432 int newstack) /* Force stack increment */
434 /* This function is special. It saves the stack so that no matter
435 how many times it is called, it returns to the same place */
441 int stack = c->stack;
442 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
444 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
445 /* Don't allow us to go over the max number of stacks we
447 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
450 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
451 /* Okay, here's where it gets weird. If newstack is non-zero,
452 then we increase the stack increment, but setjmp is not going
453 to return until longjmp is called -- when the application
454 exec'd is finished running. */
457 if (c->stack != stack + 1)
458 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
459 else if (c->app[c->stack])
460 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
465 ast_cdr_setapp(c->cdr, app->name, data);
467 /* save channel values */
468 saved_c_appl= c->appl;
469 saved_c_data= c->data;
473 res = execute(c, data);
474 /* restore channel values */
475 c->appl= saved_c_appl;
476 c->data= saved_c_data;
478 /* Any application that returns, we longjmp back, just in case. */
479 if (c->stack != stack + 1)
480 ast_log(LOG_WARNING, "Stack is not at expected value\n");
481 longjmp(c->jmp[stack+1], res);
487 /* Go no deeper than this through includes (not counting loops) */
488 #define AST_PBX_MAX_STACK 64
490 #define HELPER_EXISTS 0
491 #define HELPER_SPAWN 1
492 #define HELPER_EXEC 2
493 #define HELPER_CANMATCH 3
494 #define HELPER_MATCHMORE 4
495 #define HELPER_FINDLABEL 5
497 struct ast_app *pbx_findapp(const char *app)
501 if (ast_mutex_lock(&applock)) {
502 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
507 if (!strcasecmp(tmp->name, app))
511 ast_mutex_unlock(&applock);
515 static struct ast_switch *pbx_findswitch(const char *sw)
517 struct ast_switch *asw;
519 if (ast_mutex_lock(&switchlock)) {
520 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
525 if (!strcasecmp(asw->name, sw))
529 ast_mutex_unlock(&switchlock);
533 static inline int include_valid(struct ast_include *i)
543 /* If it's not the right month, return */
544 if (!(i->monthmask & (1 << tm.tm_mon))) {
548 /* If it's not that time of the month.... */
549 /* Warning, tm_mday has range 1..31! */
550 if (!(i->daymask & (1 << (tm.tm_mday-1))))
553 /* If it's not the right day of the week */
554 if (!(i->dowmask & (1 << tm.tm_wday)))
557 /* Sanity check the hour just to be safe */
558 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
559 ast_log(LOG_WARNING, "Insane time...\n");
563 /* Now the tough part, we calculate if it fits
564 in the right time based on min/hour */
565 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
568 /* If we got this far, then we're good */
572 static void pbx_destroy(struct ast_pbx *p)
577 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
578 /* All patterns begin with _ */\
579 if (pattern[0] != '_') \
581 /* Start optimistic */\
584 while(match && *data && *pattern && (*pattern != '/')) {\
585 switch(toupper(*pattern)) {\
592 where=strchr(pattern,']');\
594 border=(int)(where-pattern);\
595 if (!where || border > strlen(pattern)) {\
596 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
599 for (i=0; i<border; i++) {\
602 if (pattern[i+1]=='-') {\
603 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
610 if (res==1 || *data==pattern[i]) {\
619 if ((*data < '2') || (*data > '9'))\
623 if ((*data < '0') || (*data > '9'))\
627 if ((*data < '1') || (*data > '9'))\
635 /* Ignore these characters */\
639 if (*data != *pattern)\
647 int ast_extension_match(const char *pattern, const char *data)
650 /* If they're the same return */
651 if (!strcmp(pattern, data))
653 EXTENSION_MATCH_CORE(data,pattern,match);
654 /* Must be at the end of both */
655 if (*data || (*pattern && (*pattern != '/')))
660 static int extension_close(const char *pattern, const char *data, int needmore)
663 /* If "data" is longer, it can'be a subset of pattern unless
664 pattern is a pattern match */
665 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
668 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
669 (!needmore || (strlen(pattern) > strlen(data)))) {
672 EXTENSION_MATCH_CORE(data,pattern,match);
673 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
674 if (!needmore || *pattern) {
680 struct ast_context *ast_context_find(const char *name)
682 struct ast_context *tmp;
683 ast_mutex_lock(&conlock);
687 if (!strcasecmp(name, tmp->name))
693 ast_mutex_unlock(&conlock);
697 #define STATUS_NO_CONTEXT 1
698 #define STATUS_NO_EXTENSION 2
699 #define STATUS_NO_PRIORITY 3
700 #define STATUS_NO_LABEL 4
701 #define STATUS_SUCCESS 5
703 static int matchcid(const char *cidpattern, const char *callerid)
707 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
708 failing to get a number should count as a match, otherwise not */
711 if (!ast_strlen_zero(cidpattern))
719 return ast_extension_match(cidpattern, callerid);
722 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, 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)
725 struct ast_context *tmp;
726 struct ast_exten *e, *eroot;
727 struct ast_include *i;
729 struct ast_switch *asw;
731 /* Initialize status if appropriate */
733 *status = STATUS_NO_CONTEXT;
737 /* Check for stack overflow */
738 if (*stacklen >= AST_PBX_MAX_STACK) {
739 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
742 /* Check first to see if we've already been checked */
743 for (x=0;x<*stacklen;x++) {
744 if (!strcasecmp(incstack[x], context))
750 if (!strcmp(tmp->name, context)) {
751 if (*status < STATUS_NO_EXTENSION)
752 *status = STATUS_NO_EXTENSION;
755 /* Match extension */
756 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
757 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
758 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
759 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
761 if (*status < STATUS_NO_PRIORITY)
762 *status = STATUS_NO_PRIORITY;
765 if (action == HELPER_FINDLABEL) {
766 if (*status < STATUS_NO_LABEL)
767 *status = STATUS_NO_LABEL;
768 if (label && e->label && !strcmp(label, e->label)) {
769 *status = STATUS_SUCCESS;
772 } else if (e->priority == priority) {
773 *status = STATUS_SUCCESS;
781 /* Check alternative switches */
784 if ((asw = pbx_findswitch(sw->name))) {
785 if (action == HELPER_CANMATCH)
786 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
787 else if (action == HELPER_MATCHMORE)
788 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
790 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
798 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
802 /* Setup the stack */
803 incstack[*stacklen] = tmp->name;
805 /* Now try any includes we have in this context */
808 if (include_valid(i)) {
809 if ((e = pbx_find_extension(chan, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data)))
822 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
825 char tmpvar[80] = "";
827 struct tm brokentime;
829 struct ast_var_t *variables;
830 struct varshead *headp=NULL;
835 /* Now we have the variable name on cp3 */
836 if (!strncasecmp(var,"LEN(",4)) {
839 if (strrchr(var,')')) {
841 strncpy(cp3, var, sizeof(cp3) - 1);
842 cp3[len-len_len-1]='\0';
843 sprintf(workspace,"%d",(int)strlen(cp3));
849 } else if ((first=strchr(var,':'))) {
850 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
851 first = strchr(tmpvar, ':');
853 first = tmpvar + strlen(tmpvar);
855 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
857 offset=atoi(first+1);
858 if ((second=strchr(first+1,':'))) {
860 offset2=atoi(second+1);
862 offset2=strlen(*ret)-offset;
863 if (abs(offset)>strlen(*ret)) {
867 offset=-strlen(*ret);
869 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
871 offset2=strlen(*ret)-offset;
873 offset2=strlen(*ret)+offset;
878 *ret+=strlen(*ret)+offset;
879 (*ret)[offset2] = '\0';
880 } else if (c && !strcmp(var, "CALLERIDNUM")) {
881 if (c->cid.cid_num) {
882 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
886 } else if (c && !strcmp(var, "CALLERANI")) {
887 if (c->cid.cid_ani) {
888 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
892 } else if (c && !strcmp(var, "CALLERIDNAME")) {
893 if (c->cid.cid_name) {
894 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
898 } else if (c && !strcmp(var, "CALLERID")) {
899 if (c->cid.cid_num) {
900 if (c->cid.cid_name) {
901 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
903 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
906 } else if (c->cid.cid_name) {
907 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
911 } else if (c && !strcmp(var, "DNID")) {
912 if (c->cid.cid_dnid) {
913 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
917 } else if (c && !strcmp(var, "HINT")) {
918 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
922 } else if (c && !strcmp(var, "EXTEN")) {
923 strncpy(workspace, c->exten, workspacelen - 1);
925 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
926 /* XXX Remove me eventually */
927 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
930 if (offset > strlen(c->exten))
931 offset = strlen(c->exten);
932 strncpy(workspace, c->exten + offset, workspacelen - 1);
934 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
935 } else if (c && !strcmp(var, "RDNIS")) {
936 if (c->cid.cid_rdnis) {
937 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
941 } else if (c && !strcmp(var, "CONTEXT")) {
942 strncpy(workspace, c->context, workspacelen - 1);
944 } else if (c && !strcmp(var, "PRIORITY")) {
945 snprintf(workspace, workspacelen, "%d", c->priority);
947 } else if (c && !strcmp(var, "CALLINGPRES")) {
948 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
950 } else if (c && !strcmp(var, "CALLINGANI2")) {
951 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
953 } else if (c && !strcmp(var, "CALLINGTON")) {
954 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
956 } else if (c && !strcmp(var, "CALLINGTNS")) {
957 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
959 } else if (c && !strcmp(var, "CHANNEL")) {
960 strncpy(workspace, c->name, workspacelen - 1);
962 } else if (c && !strcmp(var, "EPOCH")) {
963 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
965 } else if (c && !strcmp(var, "DATETIME")) {
967 localtime_r(&thistime, &brokentime);
968 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
971 brokentime.tm_year+1900,
977 } else if (c && !strcmp(var, "TIMESTAMP")) {
979 localtime_r(&thistime, &brokentime);
980 /* 20031130-150612 */
981 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
982 brokentime.tm_year+1900,
990 } else if (c && !strcmp(var, "UNIQUEID")) {
991 snprintf(workspace, workspacelen, "%s", c->uniqueid);
993 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
994 snprintf(workspace, workspacelen, "%i", c->hangupcause);
996 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
997 strncpy(workspace, c->accountcode, workspacelen - 1);
999 } else if (c && !strcmp(var, "LANGUAGE")) {
1000 strncpy(workspace, c->language, workspacelen - 1);
1004 AST_LIST_TRAVERSE(headp,variables,entries) {
1006 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1008 if (strcasecmp(ast_var_name(variables),var)==0) {
1009 *ret=ast_var_value(variables);
1011 strncpy(workspace, *ret, workspacelen - 1);
1020 AST_LIST_TRAVERSE(&globals,variables,entries) {
1022 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1024 if (strcasecmp(ast_var_name(variables),var)==0) {
1025 *ret=ast_var_value(variables);
1027 strncpy(workspace, *ret, workspacelen - 1);
1034 int len=strlen(var);
1035 int len_env=strlen("ENV(");
1036 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1038 strncpy(cp3, var, sizeof(cp3) - 1);
1040 *ret=getenv(cp3+len_env);
1042 strncpy(workspace, *ret, workspacelen - 1);
1050 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1053 const char *tmp, *whereweare;
1055 char workspace[4096];
1056 char ltmp[4096], var[4096];
1057 char *nextvar, *nextexp;
1059 int pos, brackets, needsub, len;
1061 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1064 while(!ast_strlen_zero(whereweare) && count) {
1065 /* Assume we're copying the whole remaining string */
1066 pos = strlen(whereweare);
1068 /* Look for a variable */
1069 nextvar = strstr(whereweare, "${");
1071 /* Look for an expression */
1072 nextexp = strstr(whereweare, "$[");
1074 /* Pick the first one only */
1075 if (nextvar && nextexp) {
1076 if (nextvar < nextexp)
1082 /* If there is one, we only go that far */
1084 pos = nextvar - whereweare;
1086 pos = nextexp - whereweare;
1088 /* Can't copy more than 'count' bytes */
1092 /* Copy that many bytes */
1093 memcpy(cp2, whereweare, pos);
1100 /* We have a variable. Find the start and end, and determine
1101 if we are going to have to recursively call ourselves on the
1103 vars = vare = nextvar + 2;
1107 /* Find the end of it */
1108 while(brackets && *vare) {
1109 if ((vare[0] == '$') && (vare[1] == '{')) {
1112 } else if (vare[0] == '}') {
1114 } else if ((vare[0] == '$') && (vare[1] == '['))
1119 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1120 len = vare - vars - 1;
1122 /* Skip totally over variable name */
1123 whereweare += ( len + 3);
1125 /* Store variable name (and truncate) */
1126 memset(var, 0, sizeof(var));
1127 strncpy(var, vars, sizeof(var) - 1);
1130 /* Substitute if necessary */
1132 memset(ltmp, 0, sizeof(ltmp));
1133 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1139 /* Retrieve variable value */
1140 workspace[0] = '\0';
1141 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1143 length = strlen(cp4);
1146 memcpy(cp2, cp4, length);
1151 } else if (nextexp) {
1152 /* We have an expression. Find the start and end, and determine
1153 if we are going to have to recursively call ourselves on the
1155 vars = vare = nextexp + 2;
1159 /* Find the end of it */
1160 while(brackets && *vare) {
1161 if ((vare[0] == '$') && (vare[1] == '[')) {
1165 } else if (vare[0] == '[') {
1167 } else if (vare[0] == ']') {
1169 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1176 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1177 len = vare - vars - 1;
1179 /* Skip totally over variable name */
1180 whereweare += ( len + 3);
1182 /* Store variable name (and truncate) */
1183 memset(var, 0, sizeof(var));
1184 strncpy(var, vars, sizeof(var) - 1);
1187 /* Substitute if necessary */
1189 memset(ltmp, 0, sizeof(ltmp));
1190 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1196 /* Evaluate expression */
1197 cp4 = ast_expr(vars);
1199 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1202 length = strlen(cp4);
1205 memcpy(cp2, cp4, length);
1216 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1218 memset(passdata, 0, datalen);
1220 /* No variables or expressions in e->data, so why scan it? */
1221 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1222 strncpy(passdata, e->data, datalen - 1);
1223 passdata[datalen-1] = '\0';
1227 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1230 static int pbx_extension_helper(struct ast_channel *c, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
1232 struct ast_exten *e;
1233 struct ast_app *app;
1234 struct ast_switch *sw;
1239 char *incstack[AST_PBX_MAX_STACK];
1240 char passdata[EXT_DATA_SIZE];
1244 char tmp3[EXT_DATA_SIZE];
1246 if (ast_mutex_lock(&conlock)) {
1247 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1248 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1253 e = pbx_find_extension(c, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data);
1256 case HELPER_CANMATCH:
1257 ast_mutex_unlock(&conlock);
1260 ast_mutex_unlock(&conlock);
1262 case HELPER_FINDLABEL:
1264 ast_mutex_unlock(&conlock);
1266 case HELPER_MATCHMORE:
1267 ast_mutex_unlock(&conlock);
1273 app = pbx_findapp(e->app);
1274 ast_mutex_unlock(&conlock);
1276 if (c->context != context)
1277 strncpy(c->context, context, sizeof(c->context)-1);
1278 if (c->exten != exten)
1279 strncpy(c->exten, exten, sizeof(c->exten)-1);
1280 c->priority = priority;
1281 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1283 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1284 else if (option_verbose > 2)
1285 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1286 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1287 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1288 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1289 (newstack ? "in new stack" : "in same stack"));
1290 manager_event(EVENT_FLAG_CALL, "Newexten",
1295 "Application: %s\r\n"
1298 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1299 res = pbx_exec(c, app, passdata, newstack);
1302 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1306 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1310 case HELPER_CANMATCH:
1311 ast_mutex_unlock(&conlock);
1314 ast_mutex_unlock(&conlock);
1316 case HELPER_MATCHMORE:
1317 ast_mutex_unlock(&conlock);
1319 case HELPER_FINDLABEL:
1320 ast_mutex_unlock(&conlock);
1326 ast_mutex_unlock(&conlock);
1328 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1330 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1335 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1339 ast_mutex_unlock(&conlock);
1341 case STATUS_NO_CONTEXT:
1342 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1343 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1345 case STATUS_NO_EXTENSION:
1346 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1347 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1349 case STATUS_NO_PRIORITY:
1350 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1351 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1353 case STATUS_NO_LABEL:
1354 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1357 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1360 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1368 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1370 struct ast_exten *e;
1371 struct ast_switch *sw;
1374 char *incstack[AST_PBX_MAX_STACK];
1377 if (ast_mutex_lock(&conlock)) {
1378 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1381 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1382 ast_mutex_unlock(&conlock);
1386 static int ast_extension_state2(struct ast_exten *e)
1388 char hint[AST_MAX_EXTENSION] = "";
1391 int allunavailable = 1, allbusy = 1, allfree = 1;
1394 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1398 rest = strchr(cur, '&');
1404 res = ast_device_state(cur);
1406 case AST_DEVICE_NOT_INUSE:
1410 case AST_DEVICE_INUSE:
1411 return AST_EXTENSION_INUSE;
1412 case AST_DEVICE_BUSY:
1417 case AST_DEVICE_UNAVAILABLE:
1418 case AST_DEVICE_INVALID:
1431 return AST_EXTENSION_NOT_INUSE;
1433 return AST_EXTENSION_BUSY;
1435 return AST_EXTENSION_UNAVAILABLE;
1437 return AST_EXTENSION_INUSE;
1439 return AST_EXTENSION_NOT_INUSE;
1443 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1445 struct ast_exten *e;
1447 e = ast_hint_extension(c, context, exten);
1451 return ast_extension_state2(e);
1454 int ast_device_state_changed(const char *fmt, ...)
1456 struct ast_hint *list;
1457 struct ast_state_cb *cblist;
1458 char hint[AST_MAX_EXTENSION] = "";
1459 char device[AST_MAX_EXTENSION];
1466 vsnprintf(device, sizeof(device), fmt, ap);
1469 rest = strchr(device, '-');
1474 ast_mutex_lock(&hintlock);
1480 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1483 rest = strchr(cur, '&');
1489 if (!strcmp(cur, device)) {
1490 /* Found extension execute callbacks */
1491 state = ast_extension_state2(list->exten);
1492 if ((state != -1) && (state != list->laststate)) {
1493 /* For general callbacks */
1496 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1497 cblist = cblist->next;
1500 /* For extension callbacks */
1501 cblist = list->callbacks;
1503 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1504 cblist = cblist->next;
1507 list->laststate = state;
1515 ast_mutex_unlock(&hintlock);
1519 int ast_extension_state_add(const char *context, const char *exten,
1520 ast_state_cb_type callback, void *data)
1522 struct ast_hint *list;
1523 struct ast_state_cb *cblist;
1524 struct ast_exten *e;
1526 /* No context and extension add callback to statecbs list */
1527 if (!context && !exten) {
1528 ast_mutex_lock(&hintlock);
1532 if (cblist->callback == callback) {
1533 cblist->data = data;
1534 ast_mutex_unlock(&hintlock);
1536 cblist = cblist->next;
1539 /* Now inserts the callback */
1540 cblist = malloc(sizeof(struct ast_state_cb));
1542 ast_mutex_unlock(&hintlock);
1545 memset(cblist, 0, sizeof(struct ast_state_cb));
1547 cblist->callback = callback;
1548 cblist->data = data;
1550 cblist->next = statecbs;
1553 ast_mutex_unlock(&hintlock);
1557 if (!context || !exten)
1560 /* This callback type is for only one hint */
1561 e = ast_hint_extension(NULL, context, exten);
1566 ast_mutex_lock(&hintlock);
1570 if (list->exten == e)
1576 ast_mutex_unlock(&hintlock);
1580 /* Now inserts the callback */
1581 cblist = malloc(sizeof(struct ast_state_cb));
1583 ast_mutex_unlock(&hintlock);
1586 memset(cblist, 0, sizeof(struct ast_state_cb));
1587 cblist->id = stateid++;
1588 cblist->callback = callback;
1589 cblist->data = data;
1591 cblist->next = list->callbacks;
1592 list->callbacks = cblist;
1594 ast_mutex_unlock(&hintlock);
1598 int ast_extension_state_del(int id, ast_state_cb_type callback)
1600 struct ast_hint *list;
1601 struct ast_state_cb *cblist, *cbprev;
1603 if (!id && !callback)
1606 ast_mutex_lock(&hintlock);
1608 /* id is zero is a callback without extension */
1613 if (cblist->callback == callback) {
1615 statecbs = cblist->next;
1617 cbprev->next = cblist->next;
1621 ast_mutex_unlock(&hintlock);
1625 cblist = cblist->next;
1628 ast_mutex_lock(&hintlock);
1632 /* id greater than zero is a callback with extension */
1635 cblist = list->callbacks;
1638 if (cblist->id==id) {
1640 list->callbacks = cblist->next;
1642 cbprev->next = cblist->next;
1646 ast_mutex_unlock(&hintlock);
1650 cblist = cblist->next;
1655 ast_mutex_unlock(&hintlock);
1659 static int ast_add_hint(struct ast_exten *e)
1661 struct ast_hint *list;
1666 ast_mutex_lock(&hintlock);
1669 /* Search if hint exists, do nothing */
1671 if (list->exten == e) {
1672 ast_mutex_unlock(&hintlock);
1678 list = malloc(sizeof(struct ast_hint));
1680 ast_mutex_unlock(&hintlock);
1683 /* Initialize and insert new item */
1684 memset(list, 0, sizeof(struct ast_hint));
1686 list->laststate = ast_extension_state2(e);
1690 ast_mutex_unlock(&hintlock);
1694 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1696 struct ast_hint *list;
1698 ast_mutex_lock(&hintlock);
1702 if (list->exten == oe) {
1704 ast_mutex_unlock(&hintlock);
1709 ast_mutex_unlock(&hintlock);
1714 static int ast_remove_hint(struct ast_exten *e)
1716 /* Cleanup the Notifys if hint is removed */
1717 struct ast_hint *list, *prev = NULL;
1718 struct ast_state_cb *cblist, *cbprev;
1723 ast_mutex_lock(&hintlock);
1727 if (list->exten==e) {
1729 cblist = list->callbacks;
1731 /* Notify with -1 and remove all callbacks */
1733 cblist = cblist->next;
1734 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1737 list->callbacks = NULL;
1742 prev->next = list->next;
1745 ast_mutex_unlock(&hintlock);
1753 ast_mutex_unlock(&hintlock);
1758 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1760 struct ast_exten *e;
1761 e = ast_hint_extension(c, context, exten);
1763 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1769 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1771 return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1774 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1776 return pbx_extension_helper(c, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1779 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1781 return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1784 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1786 return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1789 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1791 return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1794 int ast_pbx_run(struct ast_channel *c)
1803 /* A little initial setup here */
1805 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1806 c->pbx = malloc(sizeof(struct ast_pbx));
1808 ast_log(LOG_ERROR, "Out of memory\n");
1813 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1815 c->cdr = ast_cdr_alloc();
1817 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1821 ast_cdr_init(c->cdr, c);
1824 memset(c->pbx, 0, sizeof(struct ast_pbx));
1825 /* Set reasonable defaults */
1826 c->pbx->rtimeout = 10;
1827 c->pbx->dtimeout = 5;
1829 /* Start by trying whatever the channel is set to */
1830 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1831 /* JK02: If not successfull fall back to 's' */
1832 if (option_verbose > 1)
1833 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);
1834 strncpy(c->exten, "s", sizeof(c->exten)-1);
1835 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1836 /* JK02: And finally back to default if everything else failed */
1837 if (option_verbose > 1)
1838 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);
1839 strncpy(c->context, "default", sizeof(c->context)-1);
1844 ast_cdr_start(c->cdr);
1848 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1849 memset(exten, 0, sizeof(exten));
1850 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1851 /* Something bad happened, or a hangup has been requested. */
1852 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1853 (res == '*') || (res == '#')) {
1854 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1855 memset(exten, 0, sizeof(exten));
1857 exten[pos++] = digit = res;
1861 case AST_PBX_KEEPALIVE:
1863 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1864 else if (option_verbose > 1)
1865 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1870 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1871 else if (option_verbose > 1)
1872 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1873 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1878 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1888 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1889 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1890 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1891 c->whentohangup = 0;
1893 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1894 } else if (c->_softhangup) {
1895 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1896 c->exten, c->priority);
1902 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1903 /* It's not a valid extension anymore */
1904 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1905 if (option_verbose > 2)
1906 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1907 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1908 strncpy(c->exten, "i", sizeof(c->exten)-1);
1911 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1912 c->name, c->exten, c->context);
1915 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1916 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1919 /* Done, wait for an extension */
1921 waittime = c->pbx->dtimeout;
1923 waittime = c->pbx->rtimeout;
1924 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1925 /* As long as we're willing to wait, and as long as it's not defined,
1926 keep reading digits until we can't possibly get a right answer anymore. */
1927 digit = ast_waitfordigit(c, waittime * 1000);
1928 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1935 /* Error, maybe a hangup */
1937 exten[pos++] = digit;
1938 waittime = c->pbx->dtimeout;
1941 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1942 /* Prepare the next cycle */
1943 strncpy(c->exten, exten, sizeof(c->exten)-1);
1946 /* No such extension */
1947 if (!ast_strlen_zero(exten)) {
1948 /* An invalid extension */
1949 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1950 if (option_verbose > 2)
1951 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1952 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1953 strncpy(c->exten, "i", sizeof(c->exten)-1);
1956 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
1960 /* A simple timeout */
1961 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
1962 if (option_verbose > 2)
1963 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1964 strncpy(c->exten, "t", sizeof(c->exten)-1);
1967 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1973 if (option_verbose > 2)
1974 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1980 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1982 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
1986 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1987 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1988 /* Something bad happened, or a hangup has been requested. */
1990 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1991 else if (option_verbose > 1)
1992 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1999 pbx_destroy(c->pbx);
2001 if (res != AST_PBX_KEEPALIVE)
2006 static void *pbx_thread(void *data)
2008 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2009 answer this channel and get it going. The setjmp stuff is fairly
2010 confusing, but necessary to get smooth transitions between
2011 the execution of different applications (without the use of
2012 additional threads) */
2013 struct ast_channel *c = data;
2019 int ast_pbx_start(struct ast_channel *c)
2022 pthread_attr_t attr;
2024 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2028 /* Start a new thread, and get something handling this channel. */
2029 pthread_attr_init(&attr);
2030 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2031 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2032 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2039 * This function locks contexts list by &conlist, search for the right context
2040 * structure, leave context list locked and call ast_context_remove_include2
2041 * which removes include, unlock contexts list and return ...
2043 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2045 struct ast_context *c;
2047 if (ast_lock_contexts()) return -1;
2049 /* walk contexts and search for the right one ...*/
2050 c = ast_walk_contexts(NULL);
2052 /* we found one ... */
2053 if (!strcmp(ast_get_context_name(c), context)) {
2055 /* remove include from this context ... */
2056 ret = ast_context_remove_include2(c, include, registrar);
2058 ast_unlock_contexts();
2060 /* ... return results */
2063 c = ast_walk_contexts(c);
2066 /* we can't find the right one context */
2067 ast_unlock_contexts();
2072 * When we call this function, &conlock lock must be locked, because when
2073 * we giving *con argument, some process can remove/change this context
2074 * and after that there can be segfault.
2076 * This function locks given context, removes include, unlock context and
2079 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2081 struct ast_include *i, *pi = NULL;
2083 if (ast_mutex_lock(&con->lock)) return -1;
2088 /* find our include */
2089 if (!strcmp(i->name, include) &&
2090 (!registrar || !strcmp(i->registrar, registrar))) {
2091 /* remove from list */
2095 con->includes = i->next;
2096 /* free include and return */
2098 ast_mutex_unlock(&con->lock);
2105 /* we can't find the right include */
2106 ast_mutex_unlock(&con->lock);
2111 * This function locks contexts list by &conlist, search for the rigt context
2112 * structure, leave context list locked and call ast_context_remove_switch2
2113 * which removes switch, unlock contexts list and return ...
2115 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2117 struct ast_context *c;
2119 if (ast_lock_contexts()) return -1;
2121 /* walk contexts and search for the right one ...*/
2122 c = ast_walk_contexts(NULL);
2124 /* we found one ... */
2125 if (!strcmp(ast_get_context_name(c), context)) {
2127 /* remove switch from this context ... */
2128 ret = ast_context_remove_switch2(c, sw, data, registrar);
2130 ast_unlock_contexts();
2132 /* ... return results */
2135 c = ast_walk_contexts(c);
2138 /* we can't find the right one context */
2139 ast_unlock_contexts();
2144 * When we call this function, &conlock lock must be locked, because when
2145 * we giving *con argument, some process can remove/change this context
2146 * and after that there can be segfault.
2148 * This function locks given context, removes switch, unlock context and
2151 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2153 struct ast_sw *i, *pi = NULL;
2155 if (ast_mutex_lock(&con->lock)) return -1;
2160 /* find our switch */
2161 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2162 (!registrar || !strcmp(i->registrar, registrar))) {
2163 /* remove from list */
2167 con->alts = i->next;
2168 /* free switch and return */
2170 ast_mutex_unlock(&con->lock);
2177 /* we can't find the right switch */
2178 ast_mutex_unlock(&con->lock);
2183 * This functions lock contexts list, search for the right context,
2184 * call ast_context_remove_extension2, unlock contexts list and return.
2185 * In this function we are using
2187 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2189 struct ast_context *c;
2191 if (ast_lock_contexts()) return -1;
2193 /* walk contexts ... */
2194 c = ast_walk_contexts(NULL);
2196 /* ... search for the right one ... */
2197 if (!strcmp(ast_get_context_name(c), context)) {
2198 /* ... remove extension ... */
2199 int ret = ast_context_remove_extension2(c, extension, priority,
2201 /* ... unlock contexts list and return */
2202 ast_unlock_contexts();
2205 c = ast_walk_contexts(c);
2208 /* we can't find the right context */
2209 ast_unlock_contexts();
2214 * When do you want to call this function, make sure that &conlock is locked,
2215 * because some process can handle with your *con context before you lock
2218 * This functionc locks given context, search for the right extension and
2219 * fires out all peer in this extensions with given priority. If priority
2220 * is set to 0, all peers are removed. After that, unlock context and
2223 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2225 struct ast_exten *exten, *prev_exten = NULL;
2227 if (ast_mutex_lock(&con->lock)) return -1;
2229 /* go through all extensions in context and search the right one ... */
2233 /* look for right extension */
2234 if (!strcmp(exten->exten, extension) &&
2235 (!registrar || !strcmp(exten->registrar, registrar))) {
2236 struct ast_exten *peer;
2238 /* should we free all peers in this extension? (priority == 0)? */
2239 if (priority == 0) {
2240 /* remove this extension from context list */
2242 prev_exten->next = exten->next;
2244 con->root = exten->next;
2246 /* fire out all peers */
2251 if (!peer->priority==PRIORITY_HINT)
2252 ast_remove_hint(peer);
2254 peer->datad(peer->data);
2260 ast_mutex_unlock(&con->lock);
2263 /* remove only extension with exten->priority == priority */
2264 struct ast_exten *previous_peer = NULL;
2268 /* is this our extension? */
2269 if (peer->priority == priority &&
2270 (!registrar || !strcmp(peer->registrar, registrar) )) {
2271 /* we are first priority extension? */
2272 if (!previous_peer) {
2273 /* exists previous extension here? */
2275 /* yes, so we must change next pointer in
2276 * previous connection to next peer
2279 prev_exten->next = peer->peer;
2280 peer->peer->next = exten->next;
2282 prev_exten->next = exten->next;
2284 /* no previous extension, we are first
2285 * extension, so change con->root ...
2288 con->root = peer->peer;
2290 con->root = exten->next;
2293 /* we are not first priority in extension */
2294 previous_peer->peer = peer->peer;
2297 /* now, free whole priority extension */
2298 if (peer->priority==PRIORITY_HINT)
2299 ast_remove_hint(peer);
2300 peer->datad(peer->data);
2303 ast_mutex_unlock(&con->lock);
2306 /* this is not right extension, skip to next peer */
2307 previous_peer = peer;
2312 ast_mutex_unlock(&con->lock);
2318 exten = exten->next;
2321 /* we can't find right extension */
2322 ast_mutex_unlock(&con->lock);
2327 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2329 struct ast_app *tmp, *prev, *cur;
2332 length = sizeof(struct ast_app);
2333 length += strlen(app) + 1;
2334 if (ast_mutex_lock(&applock)) {
2335 ast_log(LOG_ERROR, "Unable to lock application list\n");
2340 if (!strcasecmp(app, tmp->name)) {
2341 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2342 ast_mutex_unlock(&applock);
2347 tmp = malloc(length);
2349 memset(tmp, 0, length);
2350 strcpy(tmp->name, app);
2351 tmp->execute = execute;
2352 tmp->synopsis = synopsis;
2353 tmp->description = description;
2354 /* Store in alphabetical order */
2358 if (strcasecmp(tmp->name, cur->name) < 0)
2364 tmp->next = prev->next;
2371 ast_log(LOG_ERROR, "Out of memory\n");
2372 ast_mutex_unlock(&applock);
2375 if (option_verbose > 1)
2376 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2377 ast_mutex_unlock(&applock);
2381 int ast_register_switch(struct ast_switch *sw)
2383 struct ast_switch *tmp, *prev=NULL;
2384 if (ast_mutex_lock(&switchlock)) {
2385 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2390 if (!strcasecmp(tmp->name, sw->name))
2396 ast_mutex_unlock(&switchlock);
2397 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2405 ast_mutex_unlock(&switchlock);
2409 void ast_unregister_switch(struct ast_switch *sw)
2411 struct ast_switch *tmp, *prev=NULL;
2412 if (ast_mutex_lock(&switchlock)) {
2413 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2420 prev->next = tmp->next;
2422 switches = tmp->next;
2429 ast_mutex_unlock(&switchlock);
2433 * Help for CLI commands ...
2435 static char show_application_help[] =
2436 "Usage: show application <application> [<application> [<application> [...]]]\n"
2437 " Describes a particular application.\n";
2439 static char show_applications_help[] =
2440 "Usage: show applications [{like|describing} <text>]\n"
2441 " List applications which are currently available.\n"
2442 " If 'like', <text> will be a substring of the app name\n"
2443 " If 'describing', <text> will be a substring of the description\n";
2445 static char show_dialplan_help[] =
2446 "Usage: show dialplan [exten@][context]\n"
2449 static char show_switches_help[] =
2450 "Usage: show switches\n"
2451 " Show registered switches\n";
2454 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2459 * 'show application' CLI command implementation functions ...
2463 * There is a possibility to show informations about more than one
2464 * application at one time. You can type 'show application Dial Echo' and
2465 * you will see informations about these two applications ...
2467 static char *complete_show_application(char *line, char *word,
2473 /* try to lock applications list ... */
2474 if (ast_mutex_lock(&applock)) {
2475 ast_log(LOG_ERROR, "Unable to lock application list\n");
2479 /* ... walk all applications ... */
2482 /* ... check if word matches this application ... */
2483 if (!strncasecmp(word, a->name, strlen(word))) {
2484 /* ... if this is right app serve it ... */
2485 if (++which > state) {
2486 char *ret = strdup(a->name);
2487 ast_mutex_unlock(&applock);
2494 /* no application match */
2495 ast_mutex_unlock(&applock);
2499 static int handle_show_application(int fd, int argc, char *argv[])
2502 int app, no_registered_app = 1;
2504 if (argc < 3) return RESULT_SHOWUSAGE;
2506 /* try to lock applications list ... */
2507 if (ast_mutex_lock(&applock)) {
2508 ast_log(LOG_ERROR, "Unable to lock application list\n");
2512 /* ... go through all applications ... */
2515 /* ... compare this application name with all arguments given
2516 * to 'show application' command ... */
2517 for (app = 2; app < argc; app++) {
2518 if (!strcasecmp(a->name, argv[app])) {
2519 /* Maximum number of characters added by terminal coloring is 22 */
2520 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2521 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2522 int synopsis_size, description_size;
2524 no_registered_app = 0;
2527 synopsis_size = strlen(a->synopsis) + 23;
2529 synopsis_size = strlen("Not available") + 23;
2530 synopsis = alloca(synopsis_size);
2533 description_size = strlen(a->description) + 23;
2535 description_size = strlen("Not available") + 23;
2536 description = alloca(description_size);
2538 if (synopsis && description) {
2539 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2540 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2541 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2542 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2543 term_color(synopsis,
2544 a->synopsis ? a->synopsis : "Not available",
2545 COLOR_CYAN, 0, synopsis_size);
2546 term_color(description,
2547 a->description ? a->description : "Not available",
2548 COLOR_CYAN, 0, description_size);
2550 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2552 /* ... one of our applications, show info ...*/
2553 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2554 "[Synopsis]:\n %s\n\n"
2555 "[Description]:\n%s\n",
2557 a->synopsis ? a->synopsis : "Not available",
2558 a->description ? a->description : "Not available");
2565 ast_mutex_unlock(&applock);
2567 /* we found at least one app? no? */
2568 if (no_registered_app) {
2569 ast_cli(fd, "Your application(s) is (are) not registered\n");
2570 return RESULT_FAILURE;
2573 return RESULT_SUCCESS;
2576 static int handle_show_switches(int fd, int argc, char *argv[])
2578 struct ast_switch *sw;
2580 ast_cli(fd, "There are no registered alternative switches\n");
2581 return RESULT_SUCCESS;
2583 /* ... we have applications ... */
2584 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2585 if (ast_mutex_lock(&switchlock)) {
2586 ast_log(LOG_ERROR, "Unable to lock switches\n");
2591 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2594 ast_mutex_unlock(&switchlock);
2595 return RESULT_SUCCESS;
2599 * 'show applications' CLI command implementation functions ...
2601 static int handle_show_applications(int fd, int argc, char *argv[])
2604 int like=0, describing=0;
2606 /* try to lock applications list ... */
2607 if (ast_mutex_lock(&applock)) {
2608 ast_log(LOG_ERROR, "Unable to lock application list\n");
2612 /* ... have we got at least one application (first)? no? */
2614 ast_cli(fd, "There are no registered applications\n");
2615 ast_mutex_unlock(&applock);
2619 /* show applications like <keyword> */
2620 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2622 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2626 /* show applications describing <keyword1> [<keyword2>] [...] */
2627 if ((!like) && (!describing)) {
2628 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2630 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2633 /* ... go through all applications ... */
2634 for (a = apps; a; a = a->next) {
2635 /* ... show informations about applications ... */
2639 if (ast_strcasestr(a->name, argv[3])) {
2642 } else if (describing) {
2643 if (a->description) {
2644 /* Match all words on command line */
2647 for (i=3;i<argc;i++) {
2648 if (! ast_strcasestr(a->description, argv[i])) {
2658 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2662 /* ... unlock and return */
2663 ast_mutex_unlock(&applock);
2665 return RESULT_SUCCESS;
2668 static char *complete_show_applications(char *line, char *word, int pos, int state)
2671 if (ast_strlen_zero(word)) {
2674 return strdup("like");
2676 return strdup("describing");
2680 } else if (! strncasecmp(word, "like", strlen(word))) {
2682 return strdup("like");
2686 } else if (! strncasecmp(word, "describing", strlen(word))) {
2688 return strdup("describing");
2698 * 'show dialplan' CLI command implementation functions ...
2700 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2703 struct ast_context *c;
2706 /* we are do completion of [exten@]context on second position only */
2707 if (pos != 2) return NULL;
2709 /* try to lock contexts list ... */
2710 if (ast_lock_contexts()) {
2711 ast_log(LOG_ERROR, "Unable to lock context list\n");
2715 /* ... walk through all contexts ... */
2716 c = ast_walk_contexts(NULL);
2718 /* ... word matches context name? yes? ... */
2719 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2720 /* ... for serve? ... */
2721 if (++which > state) {
2722 /* ... yes, serve this context name ... */
2723 char *ret = strdup(ast_get_context_name(c));
2724 ast_unlock_contexts();
2728 c = ast_walk_contexts(c);
2731 /* ... unlock and return */
2732 ast_unlock_contexts();
2736 static int handle_show_dialplan(int fd, int argc, char *argv[])
2738 struct ast_context *c;
2739 char *exten = NULL, *context = NULL;
2740 int context_existence = 0, extension_existence = 0;
2742 if (argc != 3 && argc != 2) return -1;
2744 /* we obtain [exten@]context? if yes, split them ... */
2746 char *splitter = argv[2];
2747 /* is there a '@' character? */
2748 if (strchr(argv[2], '@')) {
2749 /* yes, split into exten & context ... */
2750 exten = strsep(&splitter, "@");
2753 /* check for length and change to NULL if ast_strlen_zero() */
2754 if (ast_strlen_zero(exten)) exten = NULL;
2755 if (ast_strlen_zero(context)) context = NULL;
2758 /* no '@' char, only context given */
2760 if (ast_strlen_zero(context)) context = NULL;
2764 /* try to lock contexts */
2765 if (ast_lock_contexts()) {
2766 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2767 return RESULT_FAILURE;
2770 /* walk all contexts ... */
2771 c = ast_walk_contexts(NULL);
2773 /* show this context? */
2775 !strcmp(ast_get_context_name(c), context)) {
2776 context_existence = 1;
2778 /* try to lock context before walking in ... */
2779 if (!ast_lock_context(c)) {
2780 struct ast_exten *e;
2781 struct ast_include *i;
2782 struct ast_ignorepat *ip;
2784 char buf[256], buf2[256];
2785 int context_info_printed = 0;
2787 /* are we looking for exten too? if yes, we print context
2788 * if we our extension only
2791 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2792 ast_get_context_name(c), ast_get_context_registrar(c));
2793 context_info_printed = 1;
2796 /* walk extensions ... */
2797 e = ast_walk_context_extensions(c, NULL);
2799 struct ast_exten *p;
2801 /* looking for extension? is this our extension? */
2803 strcmp(ast_get_extension_name(e), exten))
2805 /* we are looking for extension and it's not our
2806 * extension, so skip to next extension */
2807 e = ast_walk_context_extensions(c, e);
2811 extension_existence = 1;
2813 /* may we print context info? */
2814 if (!context_info_printed) {
2815 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2816 ast_get_context_name(c),
2817 ast_get_context_registrar(c));
2818 context_info_printed = 1;
2821 /* write extension name and first peer */
2822 bzero(buf, sizeof(buf));
2823 snprintf(buf, sizeof(buf), "'%s' =>",
2824 ast_get_extension_name(e));
2826 snprintf(buf2, sizeof(buf2),
2828 ast_get_extension_priority(e),
2829 ast_get_extension_app(e),
2830 (char *)ast_get_extension_app_data(e));
2832 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2833 ast_get_extension_registrar(e));
2835 /* walk next extension peers */
2836 p = ast_walk_extension_priorities(e, e);
2838 bzero((void *)buf2, sizeof(buf2));
2839 bzero((void *)buf, sizeof(buf));
2840 if (ast_get_extension_label(p))
2841 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
2842 snprintf(buf2, sizeof(buf2),
2844 ast_get_extension_priority(p),
2845 ast_get_extension_app(p),
2846 (char *)ast_get_extension_app_data(p));
2848 ast_cli(fd," %-17s %-45s [%s]\n",
2850 ast_get_extension_registrar(p));
2852 p = ast_walk_extension_priorities(e, p);
2854 e = ast_walk_context_extensions(c, e);
2857 /* include & ignorepat we all printing if we are not
2858 * looking for exact extension
2861 if (ast_walk_context_extensions(c, NULL))
2864 /* walk included and write info ... */
2865 i = ast_walk_context_includes(c, NULL);
2867 bzero(buf, sizeof(buf));
2868 snprintf(buf, sizeof(buf), "'%s'",
2869 ast_get_include_name(i));
2870 ast_cli(fd, " Include => %-45s [%s]\n",
2871 buf, ast_get_include_registrar(i));
2872 i = ast_walk_context_includes(c, i);
2875 /* walk ignore patterns and write info ... */
2876 ip = ast_walk_context_ignorepats(c, NULL);
2878 bzero(buf, sizeof(buf));
2879 snprintf(buf, sizeof(buf), "'%s'",
2880 ast_get_ignorepat_name(ip));
2881 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2882 buf, ast_get_ignorepat_registrar(ip));
2883 ip = ast_walk_context_ignorepats(c, ip);
2885 sw = ast_walk_context_switches(c, NULL);
2887 bzero(buf, sizeof(buf));
2888 snprintf(buf, sizeof(buf), "'%s/%s'",
2889 ast_get_switch_name(sw),
2890 ast_get_switch_data(sw));
2891 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2892 buf, ast_get_switch_registrar(sw));
2893 sw = ast_walk_context_switches(c, sw);
2897 ast_unlock_context(c);
2899 /* if we print something in context, make an empty line */
2900 if (context_info_printed) ast_cli(fd, "\n");
2903 c = ast_walk_contexts(c);
2905 ast_unlock_contexts();
2907 /* check for input failure and throw some error messages */
2908 if (context && !context_existence) {
2909 ast_cli(fd, "There is no existence of '%s' context\n",
2911 return RESULT_FAILURE;
2914 if (exten && !extension_existence) {
2916 ast_cli(fd, "There is no existence of %s@%s extension\n",
2920 "There is no existence of '%s' extension in all contexts\n",
2922 return RESULT_FAILURE;
2926 return RESULT_SUCCESS;
2930 * CLI entries for upper commands ...
2932 static struct ast_cli_entry show_applications_cli =
2933 { { "show", "applications", NULL },
2934 handle_show_applications, "Shows registered applications",
2935 show_applications_help, complete_show_applications };
2937 static struct ast_cli_entry show_application_cli =
2938 { { "show", "application", NULL },
2939 handle_show_application, "Describe a specific application",
2940 show_application_help, complete_show_application };
2942 static struct ast_cli_entry show_dialplan_cli =
2943 { { "show", "dialplan", NULL },
2944 handle_show_dialplan, "Show dialplan",
2945 show_dialplan_help, complete_show_dialplan_context };
2947 static struct ast_cli_entry show_switches_cli =
2948 { { "show", "switches", NULL },
2949 handle_show_switches, "Show alternative switches",
2950 show_switches_help, NULL };
2952 int ast_unregister_application(const char *app) {
2953 struct ast_app *tmp, *tmpl = NULL;
2954 if (ast_mutex_lock(&applock)) {
2955 ast_log(LOG_ERROR, "Unable to lock application list\n");
2960 if (!strcasecmp(app, tmp->name)) {
2962 tmpl->next = tmp->next;
2965 if (option_verbose > 1)
2966 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2968 ast_mutex_unlock(&applock);
2974 ast_mutex_unlock(&applock);
2978 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
2980 struct ast_context *tmp, **local_contexts;
2982 length = sizeof(struct ast_context);
2983 length += strlen(name) + 1;
2985 local_contexts = &contexts;
2986 ast_mutex_lock(&conlock);
2988 local_contexts = extcontexts;
2990 tmp = *local_contexts;
2992 if (!strcasecmp(tmp->name, name)) {
2993 ast_mutex_unlock(&conlock);
2994 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2996 ast_mutex_unlock(&conlock);
3001 tmp = malloc(length);
3003 memset(tmp, 0, length);
3004 ast_mutex_init(&tmp->lock);
3005 strcpy(tmp->name, name);
3007 tmp->registrar = registrar;
3008 tmp->next = *local_contexts;
3009 tmp->includes = NULL;
3010 tmp->ignorepats = NULL;
3011 *local_contexts = tmp;
3013 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3014 else if (option_verbose > 2)
3015 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3017 ast_log(LOG_ERROR, "Out of memory\n");
3020 ast_mutex_unlock(&conlock);
3024 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3026 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) {
3027 struct ast_context *tmp, *lasttmp = NULL;
3029 ast_mutex_lock(&conlock);
3031 __ast_context_destroy(NULL,registrar);
3038 __ast_context_destroy(tmp,tmp->registrar);
3044 lasttmp->next = contexts;
3045 contexts = *extcontexts;
3046 *extcontexts = NULL;
3048 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3049 ast_mutex_unlock(&conlock);
3055 * EBUSY - can't lock
3056 * ENOENT - no existence of context
3058 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3060 struct ast_context *c;
3062 if (ast_lock_contexts()) {
3067 /* walk contexts ... */
3068 c = ast_walk_contexts(NULL);
3070 /* ... search for the right one ... */
3071 if (!strcmp(ast_get_context_name(c), context)) {
3072 int ret = ast_context_add_include2(c, include, registrar);
3073 /* ... unlock contexts list and return */
3074 ast_unlock_contexts();
3077 c = ast_walk_contexts(c);
3080 /* we can't find the right context */
3081 ast_unlock_contexts();
3089 while(*c && (*c != '|')) c++; \
3090 if (*c) { *c = '\0'; c++; } else c = NULL; \
3093 static void get_timerange(struct ast_include *i, char *times)
3101 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3102 memset(i->minmask, 0, sizeof(i->minmask));
3104 /* Star is all times */
3105 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3107 i->minmask[x] = (1 << 30) - 1;
3110 /* Otherwise expect a range */
3111 e = strchr(times, '-');
3113 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3118 while(*e && !isdigit(*e)) e++;
3120 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3123 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3124 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3127 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3128 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3133 s1 = s1 * 30 + s2/2;
3134 if ((s1 < 0) || (s1 >= 24*30)) {
3135 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3138 e1 = e1 * 30 + e2/2;
3139 if ((e1 < 0) || (e1 >= 24*30)) {
3140 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3143 /* Go through the time and enable each appropriate bit */
3144 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3145 i->minmask[x/30] |= (1 << (x % 30));
3147 /* Do the last one */
3148 i->minmask[x/30] |= (1 << (x % 30));
3150 for (cth=0;cth<24;cth++) {
3151 /* Initialize masks to blank */
3152 i->minmask[cth] = 0;
3153 for (ctm=0;ctm<30;ctm++) {
3155 /* First hour with more than one hour */
3156 (((cth == s1) && (ctm >= s2)) &&
3159 || (((cth == s1) && (ctm >= s2)) &&
3160 ((cth == e1) && (ctm <= e2)))
3161 /* In between first and last hours (more than 2 hours) */
3164 /* Last hour with more than one hour */
3166 ((cth == e1) && (ctm <= e2)))
3168 i->minmask[cth] |= (1 << (ctm / 2));
3176 static char *days[] =
3187 static unsigned int get_dow(char *dow)
3190 /* The following line is coincidence, really! */
3194 /* Check for all days */
3195 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3196 return (1 << 7) - 1;
3197 /* Get start and ending days */
3198 c = strchr(dow, '-');
3204 /* Find the start */
3206 while((s < 7) && strcasecmp(dow, days[s])) s++;
3208 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3213 while((e < 7) && strcasecmp(c, days[e])) e++;
3215 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3221 for (x=s; x != e; x = (x + 1) % 7) {
3229 static unsigned int get_day(char *day)
3232 /* The following line is coincidence, really! */
3236 /* Check for all days */
3237 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3238 mask = (1 << 30) + ((1 << 30) - 1);
3241 /* Get start and ending days */
3242 c = strchr(day, '-');
3247 /* Find the start */
3248 if (sscanf(day, "%d", &s) != 1) {
3249 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3252 if ((s < 1) || (s > 31)) {
3253 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3258 if (sscanf(c, "%d", &e) != 1) {
3259 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3262 if ((e < 1) || (e > 31)) {
3263 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3270 for (x=s;x!=e;x = (x + 1) % 31) {
3277 static char *months[] =
3293 static unsigned int get_month(char *mon)
3296 /* The following line is coincidence, really! */
3300 /* Check for all days */
3301 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
3302 return (1 << 12) - 1;
3303 /* Get start and ending days */
3304 c = strchr(mon, '-');
3309 /* Find the start */
3311 while((s < 12) && strcasecmp(mon, months[s])) s++;
3313 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3318 while((e < 12) && strcasecmp(mon, months[e])) e++;
3320 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3326 for (x=s; x!=e; x = (x + 1) % 12) {
3334 static void build_timing(struct ast_include *i, char *info)
3338 /* Check for empty just in case */
3339 if (ast_strlen_zero(info))
3342 /* Assume everything except time */
3343 i->monthmask = (1 << 12) - 1;
3344 i->daymask = (1 << 30) - 1 + (1 << 30);
3345 i->dowmask = (1 << 7) - 1;
3346 /* Avoid using str tok */
3348 /* Info has the time range, start with that */
3349 get_timerange(i, info);
3354 /* Now check for day of week */
3355 i->dowmask = get_dow(info);
3361 /* Now check for the day of the month */
3362 i->daymask = get_day(info);
3367 /* And finally go for the month */
3368 i->monthmask = get_month(info);
3373 * ENOMEM - out of memory
3374 * EBUSY - can't lock
3375 * EEXIST - already included
3376 * EINVAL - there is no existence of context for inclusion
3378 int ast_context_add_include2(struct ast_context *con, const char *value,
3379 const char *registrar)
3381 struct ast_include *new_include;
3383 struct ast_include *i, *il = NULL; /* include, include_last */
3387 length = sizeof(struct ast_include);
3388 length += 2 * (strlen(value) + 1);
3390 /* allocate new include structure ... */
3391 if (!(new_include = malloc(length))) {
3392 ast_log(LOG_ERROR, "Out of memory\n");
3397 /* ... fill in this structure ... */
3398 memset(new_include, 0, length);
3399 p = new_include->stuff;
3400 new_include->name = p;
3401 strcpy(new_include->name, value);
3402 p += strlen(value) + 1;
3403 new_include->rname = p;
3404 strcpy(new_include->rname, value);
3405 c = new_include->rname;
3406 /* Strip off timing info */
3407 while(*c && (*c != '|')) c++;
3408 /* Process if it's there */
3410 build_timing(new_include, c+1);
3413 new_include->next = NULL;
3414 new_include->registrar = registrar;
3416 /* ... try to lock this context ... */
3417 if (ast_mutex_lock(&con->lock)) {
3423 /* ... go to last include and check if context is already included too... */
3426 if (!strcasecmp(i->name, new_include->name)) {
3428 ast_mutex_unlock(&con->lock);
3436 /* ... include new context into context list, unlock, return */
3438 il->next = new_include;
3440 con->includes = new_include;
3441 if (option_verbose > 2)
3442 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3443 ast_mutex_unlock(&con->lock);
3450 * EBUSY - can't lock
3451 * ENOENT - no existence of context
3453 int ast_context_add_switch(const char *context, const char *sw, const char *data, const char *registrar)
3455 struct ast_context *c;
3457 if (ast_lock_contexts()) {
3462 /* walk contexts ... */
3463 c = ast_walk_contexts(NULL);
3465 /* ... search for the right one ... */
3466 if (!strcmp(ast_get_context_name(c), context)) {
3467 int ret = ast_context_add_switch2(c, sw, data, registrar);
3468 /* ... unlock contexts list and return */
3469 ast_unlock_contexts();
3472 c = ast_walk_contexts(c);
3475 /* we can't find the right context */
3476 ast_unlock_contexts();
3483 * ENOMEM - out of memory
3484 * EBUSY - can't lock
3485 * EEXIST - already included
3486 * EINVAL - there is no existence of context for inclusion
3488 int ast_context_add_switch2(struct ast_context *con, const char *value,
3489 const char *data, const char *registrar)
3491 struct ast_sw *new_sw;
3492 struct ast_sw *i, *il = NULL; /* sw, sw_last */