2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
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 ;-)
57 char exten[AST_MAX_EXTENSION];
59 char cidmatch[AST_MAX_EXTENSION];
62 struct ast_context *parent;
63 /* Application to execute */
64 char app[AST_MAX_EXTENSION];
68 void (*datad)(void *);
69 /* Next higher priority with our extension */
70 struct ast_exten *peer;
73 /* Extension with a greater ID */
74 struct ast_exten *next;
78 char name[AST_MAX_EXTENSION];
79 char rname[AST_MAX_EXTENSION];
82 unsigned int monthmask;
85 unsigned int minmask[24];
86 struct ast_include *next;
90 char name[AST_MAX_EXTENSION];
92 char data[AST_MAX_EXTENSION];
96 struct ast_ignorepat {
97 char pattern[AST_MAX_EXTENSION];
99 struct ast_ignorepat *next;
102 /* An extension context */
104 /* Name of the context */
105 char name[AST_MAX_EXTENSION];
106 /* A lock to prevent multiple threads from clobbering the context */
108 /* The root of the list of extensions */
109 struct ast_exten *root;
110 /* Link them together */
111 struct ast_context *next;
112 /* Include other contexts */
113 struct ast_include *includes;
114 /* Patterns for which to continue playing dialtone */
115 struct ast_ignorepat *ignorepats;
118 /* Alternative switches */
125 /* Name of the application */
126 char name[AST_MAX_APP];
127 int (*execute)(struct ast_channel *chan, void *data);
130 struct ast_app *next;
133 /* 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;
149 static int pbx_builtin_prefix(struct ast_channel *, void *);
150 static int pbx_builtin_suffix(struct ast_channel *, void *);
151 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
152 static int pbx_builtin_answer(struct ast_channel *, void *);
153 static int pbx_builtin_goto(struct ast_channel *, void *);
154 static int pbx_builtin_hangup(struct ast_channel *, void *);
155 static int pbx_builtin_background(struct ast_channel *, void *);
156 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
157 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
158 static int pbx_builtin_atimeout(struct ast_channel *, void *);
159 static int pbx_builtin_wait(struct ast_channel *, void *);
160 static int pbx_builtin_waitexten(struct ast_channel *, void *);
161 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
162 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
163 static int pbx_builtin_setaccount(struct ast_channel *, void *);
164 static int pbx_builtin_ringing(struct ast_channel *, void *);
165 static int pbx_builtin_congestion(struct ast_channel *, void *);
166 static int pbx_builtin_busy(struct ast_channel *, void *);
167 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
168 static int pbx_builtin_noop(struct ast_channel *, void *);
169 static int pbx_builtin_gotoif(struct ast_channel *, void *);
170 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
171 static int pbx_builtin_saynumber(struct ast_channel *, void *);
172 static int pbx_builtin_saydigits(struct ast_channel *, void *);
173 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
174 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
175 int pbx_builtin_setvar(struct ast_channel *, void *);
176 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
177 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
179 static struct varshead globals = AST_LIST_HEAD_INITIALIZER(varshead);
181 static struct pbx_builtin {
182 char name[AST_MAX_APP];
183 int (*execute)(struct ast_channel *chan, void *data);
188 /* These applications are built into the PBX core and do not
189 need separate modules
193 { "AbsoluteTimeout", pbx_builtin_atimeout,
194 "Set absolute maximum time of call",
195 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
196 "for a call. A setting of 0 disables the timeout. Always returns 0.\n" },
198 { "Answer", pbx_builtin_answer,
199 "Answer a channel if ringing",
200 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
201 "Returns 0 unless it tries to answer the channel and fails.\n" },
203 { "BackGround", pbx_builtin_background,
204 "Play a file while awaiting extension",
205 " Background(filename): Plays a given file, while simultaneously waiting for\n"
206 "the user to begin typing an extension. The timeouts do not count until the\n"
207 "last BackGround application as ended. Always returns 0.\n" },
209 { "Busy", pbx_builtin_busy,
210 "Indicate busy condition and stop",
211 " Busy(): Requests that the channel indicate busy condition and then waits\n"
212 "for the user to hang up. Always returns -1." },
214 { "Congestion", pbx_builtin_congestion,
215 "Indicate congestion and stop",
216 " Congestion(): Requests that the channel indicate congestion and then\n"
217 "waits for the user to hang up. Always returns -1." },
219 { "DigitTimeout", pbx_builtin_dtimeout,
220 "Set maximum timeout between digits",
221 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
222 "digits when the user is typing in an extension. When this timeout expires,\n"
223 "after the user has started to type in an extension, the extension will be\n"
224 "considered complete, and will be interpreted. Note that if an extension\n"
225 "typed in is valid, it will not have to timeout to be tested, so typically\n"
226 "at the expiry of this timeout, the extension will be considered invalid\n"
227 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
228 "exist the call would be terminated). Always returns 0.\n" },
230 { "Goto", pbx_builtin_goto,
231 "Goto a particular priority, extension, or context",
232 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
233 "value, optionally setting the extension and optionally the context as well.\n"
234 "The extension BYEXTENSION is special in that it uses the current extension,\n"
235 "thus permitting you to go to a different context, without specifying a\n"
236 "specific extension. Always returns 0, even if the given context, extension,\n"
237 "or priority is invalid.\n" },
239 { "GotoIf", pbx_builtin_gotoif,
241 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
242 "true, to label2 if condition is false. Either label1 or label2 may be\n"
243 "omitted (in that case, we just don't take the particular branch) but not\n"
244 "both. Look for the condition syntax in examples or documentation." },
246 { "GotoIfTime", pbx_builtin_gotoiftime,
247 "Conditional goto on current time",
248 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
249 "If the current time matches the specified time, then branch to the specified\n"
250 "extension. Each of the elements may be specified either as '*' (for always)\n"
251 "or as a range. See the include syntax." },
253 { "Hangup", pbx_builtin_hangup,
254 "Unconditional hangup",
255 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
257 { "NoOp", pbx_builtin_noop,
259 " NoOp(): No-operation; Does nothing." },
261 { "Prefix", pbx_builtin_prefix,
262 "Prepend leading digits",
263 " Prefix(digits): Prepends the digit string specified by digits to the\n"
264 "channel's associated extension. For example, the number 1212 when prefixed\n"
265 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
266 "continue processing at the next priority for the *new* extension.\n"
267 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
268 "executed will be priority 4 of 5551212. If you switch into an extension\n"
269 "which has no first step, the PBX will treat it as though the user dialed an\n"
270 "invalid extension.\n" },
272 { "ResetCDR", pbx_builtin_resetcdr,
273 "Resets the Call Data Record",
274 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
275 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
276 "record WILL be stored. Always returns 0.\n" },
278 { "ResponseTimeout", pbx_builtin_rtimeout,
279 "Set maximum timeout awaiting response",
280 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
281 "falling through a series of priorities for a channel in which the user may\n"
282 "begin typing an extension. If the user does not type an extension in this\n"
283 "amount of time, control will pass to the 't' extension if it exists, and\n"
284 "if not the call would be terminated. Always returns 0.\n" },
286 { "Ringing", pbx_builtin_ringing,
287 "Indicate ringing tone",
288 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
289 "Always returns 0.\n" },
291 { "SayNumber", pbx_builtin_saynumber,
293 " SayNumber(digits[,gender]): Says the passed number\n" },
295 { "SayDigits", pbx_builtin_saydigits,
297 " SayDigits(digits): Says the passed digits\n" },
299 { "SayAlpha", pbx_builtin_saycharacters,
301 " SayAlpha(string): Spells the passed string\n" },
303 { "SayPhonetic", pbx_builtin_sayphonetic,
305 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n" },
307 { "SetAccount", pbx_builtin_setaccount,
309 " SetAccount([account]): Set the channel account code for billing\n"
310 "purposes. Always returns 0.\n" },
312 { "SetGlobalVar", pbx_builtin_setglobalvar,
313 "Set variable to value",
314 " SetGlobalVar(#n=value): Sets global variable n to value" },
316 { "SetLanguage", pbx_builtin_setlanguage,
317 "Sets user language",
318 " SetLanguage(language): Set the channel language to 'language'. This\n"
319 "information is used for the generation of numbers, and to choose a natural\n"
320 "language file when available. For example, if language is set to 'fr' and\n"
321 "the file 'demo-congrats' is requested to be played, if the file 'fr/demo-\n"
322 "congrats' exists, then it will play that file, and if not will play the\n"
323 "normal 'demo-congrats'. Always returns 0.\n" },
325 { "SetVar", pbx_builtin_setvar,
326 "Set variable to value",
327 " Setvar(#n=value): Sets variable n to value" },
329 { "StripMSD", pbx_builtin_stripmsd,
330 "Strip leading digits",
331 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
332 "associated extension. For example, the number 5551212 when stripped with a\n"
333 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
334 "will continue processing at the next priority for the *new* extension.\n"
335 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
336 "executed will be priority 4 of 1212. If you switch into an extension which\n"
337 "has no first step, the PBX will treat it as though the user dialed an\n"
338 "invalid extension.\n" },
340 { "Suffix", pbx_builtin_suffix,
341 "Append trailing digits",
342 " Suffix(digits): Appends the digit string specified by digits to the\n"
343 "channel's associated extension. For example, the number 555 when suffixed\n"
344 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
345 "continue processing at the next priority for the *new* extension.\n"
346 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
347 "executed will be priority 4 of 5551212. If you switch into an extension\n"
348 "which has no first step, the PBX will treat it as though the user dialed an\n"
349 "invalid extension.\n" },
351 { "Wait", pbx_builtin_wait,
352 "Waits for some time",
353 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
354 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" },
356 { "WaitExten", pbx_builtin_waitexten,
357 "Waits for some time",
358 " Wait(seconds): Waits for the user to enter a new extension for the \n"
359 "specified number of seconds, then returns 0. Seconds can be passed with\n"
360 "fractions of a second. (eg: 1.5 = 1.5 seconds)\n" },
364 /* Lock for the application list */
365 static ast_mutex_t applock = AST_MUTEX_INITIALIZER;
366 static struct ast_context *contexts = NULL;
367 /* Lock for the ast_context list */
368 static ast_mutex_t conlock = AST_MUTEX_INITIALIZER;
369 static struct ast_app *apps = NULL;
371 /* Lock for switches */
372 static ast_mutex_t switchlock = AST_MUTEX_INITIALIZER;
373 struct ast_switch *switches = NULL;
375 /* Lock for extension state notifys */
376 static ast_mutex_t hintlock = AST_MUTEX_INITIALIZER;
377 static int stateid = 1;
378 struct ast_hint *hints = NULL;
379 struct ast_state_cb *statecbs = NULL;
381 int pbx_exec(struct ast_channel *c, /* Channel */
383 void *data, /* Data for execution */
384 int newstack) /* Force stack increment */
386 /* This function is special. It saves the stack so that no matter
387 how many times it is called, it returns to the same place */
393 int stack = c->stack;
394 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
395 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
396 /* Don't allow us to go over the max number of stacks we
398 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
401 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
402 /* Okay, here's where it gets weird. If newstack is non-zero,
403 then we increase the stack increment, but setjmp is not going
404 to return until longjmp is called -- when the application
405 exec'd is finished running. */
408 if (c->stack != stack + 1)
409 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
410 else if (c->app[c->stack])
411 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
416 ast_cdr_setapp(c->cdr, app->name, data);
418 // save channel values
419 saved_c_appl= c->appl;
420 saved_c_data= c->data;
424 res = execute(c, data);
425 // restore channel values
426 c->appl= saved_c_appl;
427 c->data= saved_c_data;
429 /* Any application that returns, we longjmp back, just in case. */
430 if (c->stack != stack + 1)
431 ast_log(LOG_WARNING, "Stack is not at expected value\n");
432 longjmp(c->jmp[stack+1], res);
438 /* Go no deeper than this through includes (not counting loops) */
439 #define AST_PBX_MAX_STACK 64
441 #define HELPER_EXISTS 0
442 #define HELPER_SPAWN 1
443 #define HELPER_EXEC 2
444 #define HELPER_CANMATCH 3
445 #define HELPER_MATCHMORE 4
447 struct ast_app *pbx_findapp(char *app)
450 if (ast_mutex_lock(&applock)) {
451 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
456 if (!strcasecmp(tmp->name, app))
460 ast_mutex_unlock(&applock);
464 static struct ast_switch *pbx_findswitch(char *sw)
466 struct ast_switch *asw;
467 if (ast_mutex_lock(&switchlock)) {
468 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
473 if (!strcasecmp(asw->name, sw))
477 ast_mutex_unlock(&switchlock);
481 static inline int include_valid(struct ast_include *i)
490 /* If it's not the right month, return */
491 if (!(i->monthmask & (1 << tm.tm_mon))) {
495 /* If it's not that time of the month.... */
496 /* Warning, tm_mday has range 1..31! */
497 if (!(i->daymask & (1 << (tm.tm_mday-1))))
500 /* If it's not the right day of the week */
501 if (!(i->dowmask & (1 << tm.tm_wday)))
504 /* Sanity check the hour just to be safe */
505 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
506 ast_log(LOG_WARNING, "Insane time...\n");
510 /* Now the tough part, we calculate if it fits
511 in the right time based on min/hour */
512 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
515 /* If we got this far, then we're good */
519 static void pbx_destroy(struct ast_pbx *p)
524 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
525 /* All patterns begin with _ */\
526 if (pattern[0] != '_') \
528 /* Start optimistic */\
531 while(match && *data && *pattern && (*pattern != '/')) {\
532 switch(toupper(*pattern)) {\
539 where=strchr(pattern,']');\
541 border=(int)(where-pattern);\
542 if (!where || border > strlen(pattern)) {\
543 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
546 for (i=0; i<border; i++) {\
549 if (pattern[i+1]=='-') {\
550 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
557 if (res==1 || *data==pattern[i]) {\
566 if ((*data < '2') || (*data > '9'))\
570 if ((*data < '0') || (*data > '9'))\
574 if ((*data < '1') || (*data > '9'))\
582 /* Ignore these characters */\
586 if (*data != *pattern)\
594 int ast_extension_match(char *pattern, char *data)
597 /* If they're the same return */
598 if (!strcmp(pattern, data))
600 EXTENSION_MATCH_CORE(data,pattern,match);
601 /* Must be at the end of both */
602 if (*data || (*pattern && (*pattern != '/')))
607 static int extension_close(char *pattern, char *data, int needmore)
610 /* If "data" is longer, it can'be a subset of pattern unless
611 pattern is a pattern match */
612 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
615 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
616 (!needmore || (strlen(pattern) > strlen(data)))) {
619 EXTENSION_MATCH_CORE(data,pattern,match);
620 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
621 if (!needmore || *pattern) {
627 struct ast_context *ast_context_find(char *name)
629 struct ast_context *tmp;
630 ast_mutex_lock(&conlock);
634 if (!strcasecmp(name, tmp->name))
640 ast_mutex_unlock(&conlock);
644 #define STATUS_NO_CONTEXT 1
645 #define STATUS_NO_EXTENSION 2
646 #define STATUS_NO_PRIORITY 3
647 #define STATUS_SUCCESS 4
649 static int matchcid(char *cidpattern, char *callerid)
651 char tmp[AST_MAX_EXTENSION];
655 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
656 failing to get a number should count as a match, otherwise not */
659 if (!ast_strlen_zero(cidpattern))
667 /* Copy original Caller*ID */
668 strncpy(tmp, callerid, sizeof(tmp)-1);
670 if (ast_callerid_parse(tmp, &name, &num))
674 ast_shrink_phone_number(num);
675 return ast_extension_match(cidpattern, num);
678 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data)
681 struct ast_context *tmp;
682 struct ast_exten *e, *eroot;
683 struct ast_include *i;
685 struct ast_switch *asw;
686 /* Initialize status if appropriate */
688 *status = STATUS_NO_CONTEXT;
692 /* Check for stack overflow */
693 if (*stacklen >= AST_PBX_MAX_STACK) {
694 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
697 /* Check first to see if we've already been checked */
698 for (x=0;x<*stacklen;x++) {
699 if (!strcasecmp(incstack[x], context))
705 if (!strcmp(tmp->name, context)) {
706 if (*status < STATUS_NO_EXTENSION)
707 *status = STATUS_NO_EXTENSION;
710 /* Match extension */
711 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
712 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
713 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
714 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
716 if (*status < STATUS_NO_PRIORITY)
717 *status = STATUS_NO_PRIORITY;
720 if (e->priority == priority) {
721 *status = STATUS_SUCCESS;
729 /* Check alternative switches */
732 if ((asw = pbx_findswitch(sw->name))) {
733 if (action == HELPER_CANMATCH)
734 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
735 else if (action == HELPER_MATCHMORE)
736 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
738 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
746 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
750 /* Setup the stack */
751 incstack[*stacklen] = tmp->name;
753 /* Now try any includes we have in this context */
756 if (include_valid(i)) {
757 if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
770 static void pbx_substitute_variables_temp(struct ast_channel *c,const char *var,char **ret, char *workspace, int workspacelen)
773 char tmpvar[80] = "";
775 struct tm brokentime;
777 struct ast_var_t *variables;
778 char *name, *num; /* for callerid name + num variables */
779 struct varshead *headp=NULL;
784 /* Now we have the variable name on cp3 */
785 if (!strncasecmp(var,"LEN(",4)) {
788 if (strrchr(var,')')) {
790 strncpy(cp3, var, sizeof(cp3) - 1);
791 cp3[len-len_len-1]='\0';
792 sprintf(workspace,"%d",strlen(cp3));
798 } else if ((first=strchr(var,':'))) {
799 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
800 first = strchr(tmpvar, ':');
802 first = tmpvar + strlen(tmpvar);
804 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
806 offset=atoi(first+1);
807 if ((second=strchr(first+1,':'))) {
809 offset2=atoi(second+1);
811 offset2=strlen(*ret)-offset;
812 if (abs(offset)>strlen(*ret)) {
816 offset=-strlen(*ret);
818 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
820 offset2=strlen(*ret)-offset;
822 offset2=strlen(*ret)+offset;
827 *ret+=strlen(*ret)+offset;
828 (*ret)[offset2] = '\0';
829 } else if (c && !strcmp(var, "CALLERIDNUM")) {
831 strncpy(workspace, c->callerid, workspacelen - 1);
832 ast_callerid_parse(workspace, &name, &num);
834 ast_shrink_phone_number(num);
838 } else if (c && !strcmp(var, "CALLERIDNAME")) {
840 strncpy(workspace, c->callerid, workspacelen - 1);
841 ast_callerid_parse(workspace, &name, &num);
846 } else if (c && !strcmp(var, "CALLERID")) {
848 strncpy(workspace, c->callerid, workspacelen - 1);
852 } else if (c && !strcmp(var, "DNID")) {
854 strncpy(workspace, c->dnid, workspacelen - 1);
858 } else if (c && !strcmp(var, "HINT")) {
859 if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
863 } else if (c && !strcmp(var, "EXTEN")) {
864 strncpy(workspace, c->exten, workspacelen - 1);
866 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
867 /* XXX Remove me eventually */
868 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
871 if (offset > strlen(c->exten))
872 offset = strlen(c->exten);
873 strncpy(workspace, c->exten + offset, workspacelen - 1);
875 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
876 } else if (c && !strcmp(var, "RDNIS")) {
878 strncpy(workspace, c->rdnis, workspacelen - 1);
882 } else if (c && !strcmp(var, "CONTEXT")) {
883 strncpy(workspace, c->context, workspacelen - 1);
885 } else if (c && !strcmp(var, "PRIORITY")) {
886 snprintf(workspace, workspacelen, "%d", c->priority);
888 } else if (c && !strcmp(var, "CHANNEL")) {
889 strncpy(workspace, c->name, workspacelen - 1);
891 } else if (c && !strcmp(var, "EPOCH")) {
892 snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
894 } else if (c && !strcmp(var, "DATETIME")) {
896 localtime_r(&thistime, &brokentime);
897 snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
900 brokentime.tm_year+1900,
906 } else if (c && !strcmp(var, "TIMESTAMP")) {
908 localtime_r(&thistime, &brokentime);
909 /* 20031130-150612 */
910 snprintf(workspace, workspacelen -1, "%04d%02d%02d-%02d%02d%02d",
911 brokentime.tm_year+1900,
919 } else if (c && !strcmp(var, "UNIQUEID")) {
920 snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
922 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
923 snprintf(workspace, workspacelen -1, "%i", c->hangupcause);
925 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
926 strncpy(workspace, c->accountcode, workspacelen - 1);
928 } else if (c && !strcmp(var, "LANGUAGE")) {
929 strncpy(workspace, c->language, workspacelen - 1);
933 AST_LIST_TRAVERSE(headp,variables,entries) {
935 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
937 if (strcasecmp(ast_var_name(variables),var)==0) {
938 *ret=ast_var_value(variables);
940 strncpy(workspace, *ret, workspacelen - 1);
949 AST_LIST_TRAVERSE(&globals,variables,entries) {
951 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
953 if (strcasecmp(ast_var_name(variables),var)==0) {
954 *ret=ast_var_value(variables);
956 strncpy(workspace, *ret, workspacelen - 1);
964 int len_env=strlen("ENV(");
965 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
967 strncpy(cp3, var, sizeof(cp3) - 1);
969 *ret=getenv(cp3+len_env);
971 strncpy(workspace, *ret, workspacelen - 1);
979 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
982 const char *tmp, *whereweare;
985 char ltmp[256], var[256];
986 char *nextvar, *nextexp;
988 int pos, brackets, needsub, len;
990 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
993 while(!ast_strlen_zero(whereweare) && count) {
994 /* Assume we're copying the whole remaining string */
995 pos = strlen(whereweare);
997 /* Look for a variable */
998 nextvar = strstr(whereweare, "${");
1000 nextexp = strstr(whereweare, "$[");
1002 if (nextvar && nextexp) {
1003 if (nextvar < nextexp)
1009 /* If there is one, we only go that far */
1011 pos = nextvar - whereweare;
1013 pos = nextexp - whereweare;
1015 /* Can't copy more than 'count' bytes */
1019 /* Copy that many bytes */
1020 memcpy(cp2, whereweare, pos);
1027 /* We have a variable. Find the start and end, and determine
1028 if we are going to have to recursively call ourselves on the
1030 vars = vare = nextvar + 2;
1034 /* Find the end of it */
1035 while(brackets && *vare) {
1036 if ((vare[0] == '$') && (vare[1] == '{')) {
1039 } else if (vare[0] == '}') {
1041 } else if ((vare[0] == '$') && (vare[1] == '['))
1046 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1047 len = vare - vars - 1;
1049 /* Skip totally over variable name */
1050 whereweare += ( len + 3);
1052 /* Store variable name (and truncate) */
1053 memset(var, 0, sizeof(var));
1054 strncpy(var, vars, sizeof(var) - 1);
1057 /* Substitute if necessary */
1059 memset(ltmp, 0, sizeof(ltmp));
1060 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1066 /* Retrieve variable value */
1067 strcpy(workspace, "");
1068 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1070 length = strlen(cp4);
1073 memcpy(cp2, cp4, length);
1078 } else if (nextexp) {
1079 /* We have an expression. Find the start and end, and determine
1080 if we are going to have to recursively call ourselves on the
1082 vars = vare = nextexp + 2;
1086 /* Find the end of it */
1087 while(brackets && *vare) {
1088 if ((vare[0] == '$') && (vare[1] == '[')) {
1091 } else if (vare[0] == ']') {
1093 } else if ((vare[0] == '$') && (vare[1] == '{'))
1098 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1099 len = vare - vars - 1;
1101 /* Skip totally over variable name */
1102 whereweare += ( len + 3);
1104 /* Store variable name (and truncate) */
1105 memset(var, 0, sizeof(var));
1106 strncpy(var, vars, sizeof(var) - 1);
1109 /* Substitute if necessary */
1111 memset(ltmp, 0, sizeof(ltmp));
1112 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1118 /* Evaluate expression */
1119 cp4 = ast_expr(vars);
1121 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1124 length = strlen(cp4);
1127 memcpy(cp2, cp4, length);
1138 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1140 memset(passdata, 0, datalen);
1142 /* No variables or expressions in e->data, so why scan it? */
1143 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1144 strncpy(passdata, e->data, datalen - 1);
1145 passdata[datalen-1] = '\0';
1149 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1152 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1154 struct ast_exten *e;
1155 struct ast_app *app;
1156 struct ast_switch *sw;
1161 char *incstack[AST_PBX_MAX_STACK];
1167 if (ast_mutex_lock(&conlock)) {
1168 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1169 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1174 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1177 case HELPER_CANMATCH:
1178 ast_mutex_unlock(&conlock);
1181 ast_mutex_unlock(&conlock);
1183 case HELPER_MATCHMORE:
1184 ast_mutex_unlock(&conlock);
1190 app = pbx_findapp(e->app);
1191 ast_mutex_unlock(&conlock);
1193 if (c->context != context)
1194 strncpy(c->context, context, sizeof(c->context)-1);
1195 if (c->exten != exten)
1196 strncpy(c->exten, exten, sizeof(c->exten)-1);
1197 c->priority = priority;
1198 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1200 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1201 else if (option_verbose > 2)
1202 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1203 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1204 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1205 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1206 (newstack ? "in new stack" : "in same stack"));
1207 res = pbx_exec(c, app, passdata, newstack);
1210 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1214 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1218 case HELPER_CANMATCH:
1219 ast_mutex_unlock(&conlock);
1222 ast_mutex_unlock(&conlock);
1224 case HELPER_MATCHMORE:
1225 ast_mutex_unlock(&conlock);
1231 ast_mutex_unlock(&conlock);
1233 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1235 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1240 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1244 ast_mutex_unlock(&conlock);
1246 case STATUS_NO_CONTEXT:
1247 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1248 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1250 case STATUS_NO_EXTENSION:
1251 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1252 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1254 case STATUS_NO_PRIORITY:
1255 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1256 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1259 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1261 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1269 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1271 struct ast_exten *e;
1272 struct ast_switch *sw;
1275 char *incstack[AST_PBX_MAX_STACK];
1278 if (ast_mutex_lock(&conlock)) {
1279 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1282 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1283 ast_mutex_unlock(&conlock);
1287 static int ast_extension_state2(struct ast_exten *e)
1289 char hint[AST_MAX_EXTENSION] = "";
1292 int allunavailable = 1, allbusy = 1, allfree = 1;
1295 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1299 rest = strchr(cur, '&');
1305 res = ast_device_state(cur);
1307 case AST_DEVICE_NOT_INUSE:
1311 case AST_DEVICE_INUSE:
1312 return AST_EXTENSION_INUSE;
1313 case AST_DEVICE_BUSY:
1318 case AST_DEVICE_UNAVAILABLE:
1319 case AST_DEVICE_INVALID:
1332 return AST_EXTENSION_NOT_INUSE;
1334 return AST_EXTENSION_BUSY;
1336 return AST_EXTENSION_UNAVAILABLE;
1338 return AST_EXTENSION_INUSE;
1340 return AST_EXTENSION_NOT_INUSE;
1344 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1346 struct ast_exten *e;
1348 e = ast_hint_extension(c, context, exten);
1352 return ast_extension_state2(e);
1355 int ast_device_state_changed(const char *fmt, ...)
1357 struct ast_hint *list;
1358 struct ast_state_cb *cblist;
1359 char hint[AST_MAX_EXTENSION];
1360 char device[AST_MAX_EXTENSION];
1367 vsnprintf(device, sizeof(device)-1, fmt, ap);
1370 rest = strchr(device, '-');
1375 ast_mutex_lock(&hintlock);
1381 strcpy(hint, ast_get_extension_app(list->exten));
1384 rest = strchr(cur, '&');
1390 if (!strcmp(cur, device)) {
1391 // Found extension execute callbacks
1392 state = ast_extension_state2(list->exten);
1393 if ((state != -1) && (state != list->laststate)) {
1394 // For general callbacks
1397 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1398 cblist = cblist->next;
1401 // For extension callbacks
1402 cblist = list->callbacks;
1404 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1405 cblist = cblist->next;
1408 list->laststate = state;
1418 ast_mutex_unlock(&hintlock);
1422 int ast_extension_state_add(char *context, char *exten,
1423 ast_state_cb_type callback, void *data)
1425 struct ast_hint *list;
1426 struct ast_state_cb *cblist;
1427 struct ast_exten *e;
1429 /* No context and extension add callback to statecbs list */
1430 if (!context && !exten) {
1431 ast_mutex_lock(&hintlock);
1435 if (cblist->callback == callback) {
1436 cblist->data = data;
1437 ast_mutex_unlock(&hintlock);
1440 cblist = cblist->next;
1443 /* Now inserts the callback */
1444 cblist = malloc(sizeof(struct ast_state_cb));
1446 ast_mutex_unlock(&hintlock);
1449 memset(cblist, 0, sizeof(struct ast_state_cb));
1451 cblist->callback = callback;
1452 cblist->data = data;
1454 cblist->next = statecbs;
1457 ast_mutex_unlock(&hintlock);
1461 if (!context || !exten)
1464 /* This callback type is for only one hint */
1465 e = ast_hint_extension(NULL, context, exten);
1470 ast_mutex_lock(&hintlock);
1474 if (list->exten == e)
1480 ast_mutex_unlock(&hintlock);
1484 /* Now inserts the callback */
1485 cblist = malloc(sizeof(struct ast_state_cb));
1487 ast_mutex_unlock(&hintlock);
1490 memset(cblist, 0, sizeof(struct ast_state_cb));
1491 cblist->id = stateid++;
1492 cblist->callback = callback;
1493 cblist->data = data;
1495 cblist->next = list->callbacks;
1496 list->callbacks = cblist;
1498 ast_mutex_unlock(&hintlock);
1502 int ast_extension_state_del(int id, ast_state_cb_type callback)
1504 struct ast_hint *list;
1505 struct ast_state_cb *cblist, *cbprev;
1507 if (!id && !callback)
1510 ast_mutex_lock(&hintlock);
1512 /* id is zero is a callback without extension */
1517 if (cblist->callback == callback) {
1519 statecbs = cblist->next;
1521 cbprev->next = cblist->next;
1525 ast_mutex_unlock(&hintlock);
1529 cblist = cblist->next;
1532 ast_mutex_lock(&hintlock);
1536 /* id greater zero is a callback with extension */
1539 cblist = list->callbacks;
1542 if (cblist->id==id) {
1544 list->callbacks = cblist->next;
1546 cbprev->next = cblist->next;
1550 ast_mutex_unlock(&hintlock);
1554 cblist = cblist->next;
1559 ast_mutex_unlock(&hintlock);
1563 static int ast_add_hint(struct ast_exten *e)
1565 struct ast_hint *list;
1569 ast_mutex_lock(&hintlock);
1572 /* Search if hint exists, do nothing */
1574 if (list->exten == e) {
1575 ast_mutex_unlock(&hintlock);
1581 list = malloc(sizeof(struct ast_hint));
1583 ast_mutex_unlock(&hintlock);
1586 /* Initialize and insert new item */
1587 memset(list, 0, sizeof(struct ast_hint));
1589 list->laststate = ast_extension_state2(e);
1593 ast_mutex_unlock(&hintlock);
1597 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1599 struct ast_hint *list;
1601 ast_mutex_lock(&hintlock);
1606 if (list->exten == oe) {
1608 ast_mutex_unlock(&hintlock);
1613 ast_mutex_unlock(&hintlock);
1618 static int ast_remove_hint(struct ast_exten *e)
1620 /* Cleanup the Notifys if hint is removed */
1621 struct ast_hint *list, *prev = NULL;
1622 struct ast_state_cb *cblist, *cbprev;
1627 ast_mutex_lock(&hintlock);
1631 if (list->exten==e) {
1633 cblist = list->callbacks;
1635 /* Notify with -1 and remove all callbacks */
1637 cblist = cblist->next;
1638 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1641 list->callbacks = NULL;
1646 prev->next = list->next;
1650 ast_mutex_unlock(&hintlock);
1658 ast_mutex_unlock(&hintlock);
1663 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1665 struct ast_exten *e;
1666 e = ast_hint_extension(c, context, exten);
1668 strncpy(hint, ast_get_extension_app(e), maxlen);
1674 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1676 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1679 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1681 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1684 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1686 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1689 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1691 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1694 int ast_pbx_run(struct ast_channel *c)
1703 /* A little initial setup here */
1705 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1706 c->pbx = malloc(sizeof(struct ast_pbx));
1708 ast_log(LOG_ERROR, "Out of memory\n");
1713 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1715 c->cdr = ast_cdr_alloc();
1717 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1721 ast_cdr_init(c->cdr, c);
1724 memset(c->pbx, 0, sizeof(struct ast_pbx));
1725 /* Set reasonable defaults */
1726 c->pbx->rtimeout = 10;
1727 c->pbx->dtimeout = 5;
1729 /* Start by trying whatever the channel is set to */
1730 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1731 /* JK02: If not successfull fall back to 's' */
1732 strncpy(c->exten, "s", sizeof(c->exten)-1);
1733 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1734 /* JK02: And finally back to default if everything else failed */
1735 strncpy(c->context, "default", sizeof(c->context)-1);
1740 ast_cdr_start(c->cdr);
1744 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1745 memset(exten, 0, sizeof(exten));
1746 manager_event(EVENT_FLAG_CALL, "Newexten",
1752 c->name, c->context, c->exten, c->priority, c->uniqueid);
1753 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1754 /* Something bad happened, or a hangup has been requested. */
1755 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1756 (res == '*') || (res == '#')) {
1757 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1758 memset(exten, 0, sizeof(exten));
1760 exten[pos++] = digit = res;
1764 case AST_PBX_KEEPALIVE:
1766 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1767 else if (option_verbose > 1)
1768 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1773 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1774 else if (option_verbose > 1)
1775 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1776 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1781 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1791 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1792 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1793 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1794 c->whentohangup = 0;
1796 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1797 } else if (c->_softhangup) {
1798 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1799 c->exten, c->priority);
1805 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1806 /* It's not a valid extension anymore */
1807 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1808 if (option_verbose > 2)
1809 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1810 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1811 strncpy(c->exten, "i", sizeof(c->exten)-1);
1814 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1815 c->name, c->exten, c->context);
1818 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1819 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1822 /* Done, wait for an extension */
1824 waittime = c->pbx->dtimeout;
1826 waittime = c->pbx->rtimeout;
1827 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1828 /* As long as we're willing to wait, and as long as it's not defined,
1829 keep reading digits until we can't possibly get a right answer anymore. */
1830 digit = ast_waitfordigit(c, waittime * 1000);
1831 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1838 /* Error, maybe a hangup */
1840 exten[pos++] = digit;
1841 waittime = c->pbx->dtimeout;
1844 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1845 /* Prepare the next cycle */
1846 strncpy(c->exten, exten, sizeof(c->exten)-1);
1849 /* No such extension */
1850 if (!ast_strlen_zero(exten)) {
1851 /* An invalid extension */
1852 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1853 if (option_verbose > 2)
1854 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1855 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1856 strncpy(c->exten, "i", sizeof(c->exten)-1);
1859 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1863 /* A simple timeout */
1864 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1865 if (option_verbose > 2)
1866 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1867 strncpy(c->exten, "t", sizeof(c->exten)-1);
1870 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1876 if (option_verbose > 2)
1877 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1883 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1885 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1886 strcpy(c->exten, "h");
1888 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1889 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1890 /* Something bad happened, or a hangup has been requested. */
1892 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1893 else if (option_verbose > 1)
1894 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1901 pbx_destroy(c->pbx);
1903 if (res != AST_PBX_KEEPALIVE)
1908 static void *pbx_thread(void *data)
1910 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1911 answer this channel and get it going. The setjmp stuff is fairly
1912 confusing, but necessary to get smooth transitions between
1913 the execution of different applications (without the use of
1914 additional threads) */
1915 struct ast_channel *c = data;
1921 int ast_pbx_start(struct ast_channel *c)
1924 pthread_attr_t attr;
1926 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1930 /* Start a new thread, and get something handling this channel. */
1931 pthread_attr_init(&attr);
1932 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1933 if (pthread_create(&t, &attr, pbx_thread, c)) {
1934 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1941 * This function locks contexts list by &conlist, search for the rigt context
1942 * structure, leave context list locked and call ast_context_remove_include2
1943 * which removes include, unlock contexts list and return ...
1945 int ast_context_remove_include(char *context, char *include, char *registrar)
1947 struct ast_context *c;
1949 if (ast_lock_contexts()) return -1;
1951 /* walk contexts and search for the right one ...*/
1952 c = ast_walk_contexts(NULL);
1954 /* we found one ... */
1955 if (!strcmp(ast_get_context_name(c), context)) {
1957 /* remove include from this context ... */
1958 ret = ast_context_remove_include2(c, include, registrar);
1960 ast_unlock_contexts();
1962 /* ... return results */
1965 c = ast_walk_contexts(c);
1968 /* we can't find the right one context */
1969 ast_unlock_contexts();
1974 * When we call this function, &conlock lock must be locked, because when
1975 * we giving *con argument, some process can remove/change this context
1976 * and after that there can be segfault.
1978 * This function locks given context, removes include, unlock context and
1981 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1983 struct ast_include *i, *pi = NULL;
1985 if (ast_mutex_lock(&con->lock)) return -1;
1990 /* find our include */
1991 if (!strcmp(i->name, include) &&
1992 (!strcmp(i->registrar, registrar) || !registrar)) {
1993 /* remove from list */
1997 con->includes = i->next;
1998 /* free include and return */
2000 ast_mutex_unlock(&con->lock);
2007 /* we can't find the right include */
2008 ast_mutex_unlock(&con->lock);
2013 * This function locks contexts list by &conlist, search for the rigt context
2014 * structure, leave context list locked and call ast_context_remove_switch2
2015 * which removes switch, unlock contexts list and return ...
2017 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
2019 struct ast_context *c;
2021 if (ast_lock_contexts()) return -1;
2023 /* walk contexts and search for the right one ...*/
2024 c = ast_walk_contexts(NULL);
2026 /* we found one ... */
2027 if (!strcmp(ast_get_context_name(c), context)) {
2029 /* remove switch from this context ... */
2030 ret = ast_context_remove_switch2(c, sw, data, registrar);
2032 ast_unlock_contexts();
2034 /* ... return results */
2037 c = ast_walk_contexts(c);
2040 /* we can't find the right one context */
2041 ast_unlock_contexts();
2046 * When we call this function, &conlock lock must be locked, because when
2047 * we giving *con argument, some process can remove/change this context
2048 * and after that there can be segfault.
2050 * This function locks given context, removes switch, unlock context and
2053 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2055 struct ast_sw *i, *pi = NULL;
2057 if (ast_mutex_lock(&con->lock)) return -1;
2062 /* find our switch */
2063 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2064 (!strcmp(i->registrar, registrar) || !registrar)) {
2065 /* remove from list */
2069 con->alts = i->next;
2070 /* free switch and return */
2072 ast_mutex_unlock(&con->lock);
2079 /* we can't find the right switch */
2080 ast_mutex_unlock(&con->lock);
2085 * This functions lock contexts list, search for the right context,
2086 * call ast_context_remove_extension2, unlock contexts list and return.
2087 * In this function we are using
2089 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2091 struct ast_context *c;
2093 if (ast_lock_contexts()) return -1;
2095 /* walk contexts ... */
2096 c = ast_walk_contexts(NULL);
2098 /* ... search for the right one ... */
2099 if (!strcmp(ast_get_context_name(c), context)) {
2100 /* ... remove extension ... */
2101 int ret = ast_context_remove_extension2(c, extension, priority,
2103 /* ... unlock contexts list and return */
2104 ast_unlock_contexts();
2107 c = ast_walk_contexts(c);
2110 /* we can't find the right context */
2111 ast_unlock_contexts();
2116 * When do you want to call this function, make sure that &conlock is locked,
2117 * because some process can handle with your *con context before you lock
2120 * This functionc locks given context, search for the right extension and
2121 * fires out all peer in this extensions with given priority. If priority
2122 * is set to 0, all peers are removed. After that, unlock context and
2125 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2127 struct ast_exten *exten, *prev_exten = NULL;
2129 if (ast_mutex_lock(&con->lock)) return -1;
2131 /* go through all extensions in context and search the right one ... */
2135 /* look for right extension */
2136 if (!strcmp(exten->exten, extension) &&
2137 (!strcmp(exten->registrar, registrar) || !registrar)) {
2138 struct ast_exten *peer;
2140 /* should we free all peers in this extension? (priority == 0)? */
2141 if (priority == 0) {
2142 /* remove this extension from context list */
2144 prev_exten->next = exten->next;
2146 con->root = exten->next;
2148 /* fire out all peers */
2153 if (!peer->priority==PRIORITY_HINT)
2154 ast_remove_hint(peer);
2156 peer->datad(peer->data);
2162 ast_mutex_unlock(&con->lock);
2165 /* remove only extension with exten->priority == priority */
2166 struct ast_exten *previous_peer = NULL;
2170 /* is this our extension? */
2171 if (peer->priority == priority &&
2172 (!strcmp(peer->registrar, registrar) || !registrar)) {
2173 /* we are first priority extension? */
2174 if (!previous_peer) {
2175 /* exists previous extension here? */
2177 /* yes, so we must change next pointer in
2178 * previous connection to next peer
2181 prev_exten->next = peer->peer;
2182 peer->peer->next = exten->next;
2184 prev_exten->next = exten->next;
2186 /* no previous extension, we are first
2187 * extension, so change con->root ...
2190 con->root = peer->peer;
2192 con->root = exten->next;
2195 /* we are not first priority in extension */
2196 previous_peer->peer = peer->peer;
2199 /* now, free whole priority extension */
2200 if (peer->priority==PRIORITY_HINT)
2201 ast_remove_hint(peer);
2202 peer->datad(peer->data);
2205 ast_mutex_unlock(&con->lock);
2208 /* this is not right extension, skip to next peer */
2209 previous_peer = peer;
2214 ast_mutex_unlock(&con->lock);
2220 exten = exten->next;
2223 /* we can't find right extension */
2224 ast_mutex_unlock(&con->lock);
2229 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2231 struct ast_app *tmp, *prev, *cur;
2233 if (ast_mutex_lock(&applock)) {
2234 ast_log(LOG_ERROR, "Unable to lock application list\n");
2239 if (!strcasecmp(app, tmp->name)) {
2240 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2241 ast_mutex_unlock(&applock);
2246 tmp = malloc(sizeof(struct ast_app));
2248 memset(tmp, 0, sizeof(struct ast_app));
2249 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2250 tmp->execute = execute;
2251 tmp->synopsis = synopsis;
2252 tmp->description = description;
2253 /* Store in alphabetical order */
2257 if (strcasecmp(tmp->name, cur->name) < 0)
2263 tmp->next = prev->next;
2270 ast_log(LOG_ERROR, "Out of memory\n");
2271 ast_mutex_unlock(&applock);
2274 if (option_verbose > 1)
2275 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2276 ast_mutex_unlock(&applock);
2280 int ast_register_switch(struct ast_switch *sw)
2282 struct ast_switch *tmp, *prev=NULL;
2283 if (ast_mutex_lock(&switchlock)) {
2284 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2289 if (!strcasecmp(tmp->name, sw->name))
2295 ast_mutex_unlock(&switchlock);
2296 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2304 ast_mutex_unlock(&switchlock);
2308 void ast_unregister_switch(struct ast_switch *sw)
2310 struct ast_switch *tmp, *prev=NULL;
2311 if (ast_mutex_lock(&switchlock)) {
2312 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2319 prev->next = tmp->next;
2321 switches = tmp->next;
2328 ast_mutex_unlock(&switchlock);
2332 * Help for CLI commands ...
2334 static char show_application_help[] =
2335 "Usage: show application <application> [<application> [<application> [...]]]\n"
2336 " Describes a particular application.\n";
2338 static char show_applications_help[] =
2339 "Usage: show applications\n"
2340 " List applications which are currently available.\n";
2342 static char show_dialplan_help[] =
2343 "Usage: show dialplan [exten@][context]\n"
2346 static char show_switches_help[] =
2347 "Usage: show switches\n"
2348 " Show registered switches\n";
2351 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2356 * 'show application' CLI command implementation functions ...
2360 * There is a possibility to show informations about more than one
2361 * application at one time. You can type 'show application Dial Echo' and
2362 * you will see informations about these two applications ...
2364 static char *complete_show_application(char *line, char *word,
2370 /* try to lock applications list ... */
2371 if (ast_mutex_lock(&applock)) {
2372 ast_log(LOG_ERROR, "Unable to lock application list\n");
2376 /* ... walk all applications ... */
2379 /* ... check if word matches this application ... */
2380 if (!strncasecmp(word, a->name, strlen(word))) {
2381 /* ... if this is right app serve it ... */
2382 if (++which > state) {
2383 char *ret = strdup(a->name);
2384 ast_mutex_unlock(&applock);
2391 /* no application match */
2392 ast_mutex_unlock(&applock);
2396 static int handle_show_application(int fd, int argc, char *argv[])
2399 int app, no_registered_app = 1;
2401 if (argc < 3) return RESULT_SHOWUSAGE;
2403 /* try to lock applications list ... */
2404 if (ast_mutex_lock(&applock)) {
2405 ast_log(LOG_ERROR, "Unable to lock application list\n");
2409 /* ... go through all applications ... */
2412 /* ... compare this application name with all arguments given
2413 * to 'show application' command ... */
2414 for (app = 2; app < argc; app++) {
2415 if (!strcasecmp(a->name, argv[app])) {
2416 /* Maximum number of characters added by terminal coloring is 22 */
2417 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2418 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2419 int synopsis_size, description_size;
2421 no_registered_app = 0;
2424 synopsis_size = strlen(a->synopsis) + 23;
2426 synopsis_size = strlen("Not available") + 23;
2427 synopsis = alloca(synopsis_size);
2430 description_size = strlen(a->description) + 23;
2432 description_size = strlen("Not available") + 23;
2433 description = alloca(description_size);
2435 if (synopsis && description) {
2436 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2437 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2438 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2439 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2440 term_color(synopsis,
2441 a->synopsis ? a->synopsis : "Not available",
2442 COLOR_CYAN, 0, synopsis_size);
2443 term_color(description,
2444 a->description ? a->description : "Not available",
2445 COLOR_CYAN, 0, description_size);
2447 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2449 /* ... one of our applications, show info ...*/
2450 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2451 "[Synopsis]:\n %s\n\n"
2452 "[Description]:\n%s\n",
2454 a->synopsis ? a->synopsis : "Not available",
2455 a->description ? a->description : "Not available");
2462 ast_mutex_unlock(&applock);
2464 /* we found at least one app? no? */
2465 if (no_registered_app) {
2466 ast_cli(fd, "Your application(s) is (are) not registered\n");
2467 return RESULT_FAILURE;
2470 return RESULT_SUCCESS;
2473 static int handle_show_switches(int fd, int argc, char *argv[])
2475 struct ast_switch *sw;
2477 ast_cli(fd, "There are no registered alternative switches\n");
2478 return RESULT_SUCCESS;
2480 /* ... we have applications ... */
2481 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2482 if (ast_mutex_lock(&switchlock)) {
2483 ast_log(LOG_ERROR, "Unable to lock switches\n");
2488 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2491 ast_mutex_unlock(&switchlock);
2492 return RESULT_SUCCESS;
2496 * 'show applications' CLI command implementation functions ...
2498 static int handle_show_applications(int fd, int argc, char *argv[])
2502 /* try to lock applications list ... */
2503 if (ast_mutex_lock(&applock)) {
2504 ast_log(LOG_ERROR, "Unable to lock application list\n");
2508 /* ... go to first application ... */
2511 /* ... have we got at least one application (first)? no? */
2513 ast_cli(fd, "There is no registered applications\n");
2514 ast_mutex_unlock(&applock);
2518 /* ... we have applications ... */
2519 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2521 /* ... go through all applications ... */
2523 /* ... show informations about applications ... */
2524 ast_cli(fd," %20s: %s\n",
2526 a->synopsis ? a->synopsis : "<Synopsis not available>");
2530 /* ... unlock and return */
2531 ast_mutex_unlock(&applock);
2533 return RESULT_SUCCESS;
2537 * 'show dialplan' CLI command implementation functions ...
2539 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2542 struct ast_context *c;
2545 /* we are do completion of [exten@]context on second position only */
2546 if (pos != 2) return NULL;
2548 /* try to lock contexts list ... */
2549 if (ast_lock_contexts()) {
2550 ast_log(LOG_ERROR, "Unable to lock context list\n");
2554 /* ... walk through all contexts ... */
2555 c = ast_walk_contexts(NULL);
2557 /* ... word matches context name? yes? ... */
2558 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2559 /* ... for serve? ... */
2560 if (++which > state) {
2561 /* ... yes, serve this context name ... */
2562 char *ret = strdup(ast_get_context_name(c));
2563 ast_unlock_contexts();
2567 c = ast_walk_contexts(c);
2570 /* ... unlock and return */
2571 ast_unlock_contexts();
2575 static int handle_show_dialplan(int fd, int argc, char *argv[])
2577 struct ast_context *c;
2578 char *exten = NULL, *context = NULL;
2579 int context_existence = 0, extension_existence = 0;
2581 if (argc != 3 && argc != 2) return -1;
2583 /* we obtain [exten@]context? if yes, split them ... */
2585 char *splitter = argv[2];
2586 /* is there a '@' character? */
2587 if (strchr(argv[2], '@')) {
2588 /* yes, split into exten & context ... */
2589 exten = strsep(&splitter, "@");
2592 /* check for length and change to NULL if !strlen() */
2593 if (ast_strlen_zero(exten)) exten = NULL;
2594 if (ast_strlen_zero(context)) context = NULL;
2597 /* no '@' char, only context given */
2599 if (ast_strlen_zero(context)) context = NULL;
2603 /* try to lock contexts */
2604 if (ast_lock_contexts()) {
2605 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2606 return RESULT_FAILURE;
2609 /* walk all contexts ... */
2610 c = ast_walk_contexts(NULL);
2612 /* show this context? */
2614 !strcmp(ast_get_context_name(c), context)) {
2615 context_existence = 1;
2617 /* try to lock context before walking in ... */
2618 if (!ast_lock_context(c)) {
2619 struct ast_exten *e;
2620 struct ast_include *i;
2621 struct ast_ignorepat *ip;
2623 char buf[256], buf2[256];
2624 int context_info_printed = 0;
2626 /* are we looking for exten too? if yes, we print context
2627 * if we our extension only
2630 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2631 ast_get_context_name(c), ast_get_context_registrar(c));
2632 context_info_printed = 1;
2635 /* walk extensions ... */
2636 e = ast_walk_context_extensions(c, NULL);
2638 struct ast_exten *p;
2640 /* looking for extension? is this our extension? */
2642 strcmp(ast_get_extension_name(e), exten))
2644 /* we are looking for extension and it's not our
2645 * extension, so skip to next extension */
2646 e = ast_walk_context_extensions(c, e);
2650 extension_existence = 1;
2652 /* may we print context info? */
2653 if (!context_info_printed) {
2654 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2655 ast_get_context_name(c),
2656 ast_get_context_registrar(c));
2657 context_info_printed = 1;
2660 /* write extension name and first peer */
2661 bzero(buf, sizeof(buf));
2662 snprintf(buf, sizeof(buf), "'%s' =>",
2663 ast_get_extension_name(e));
2665 snprintf(buf2, sizeof(buf2),
2667 ast_get_extension_priority(e),
2668 ast_get_extension_app(e),
2669 (char *)ast_get_extension_app_data(e));
2671 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2672 ast_get_extension_registrar(e));
2674 /* walk next extension peers */
2675 p = ast_walk_extension_priorities(e, e);
2677 bzero((void *)buf2, sizeof(buf2));
2679 snprintf(buf2, sizeof(buf2),
2681 ast_get_extension_priority(p),
2682 ast_get_extension_app(p),
2683 (char *)ast_get_extension_app_data(p));
2685 ast_cli(fd," %-17s %-45s [%s]\n",
2687 ast_get_extension_registrar(p));
2689 p = ast_walk_extension_priorities(e, p);
2691 e = ast_walk_context_extensions(c, e);
2694 /* include & ignorepat we all printing if we are not
2695 * looking for exact extension
2698 if (ast_walk_context_extensions(c, NULL))
2701 /* walk included and write info ... */
2702 i = ast_walk_context_includes(c, NULL);
2704 bzero(buf, sizeof(buf));
2705 snprintf(buf, sizeof(buf), "'%s'",
2706 ast_get_include_name(i));
2707 ast_cli(fd, " Include => %-45s [%s]\n",
2708 buf, ast_get_include_registrar(i));
2709 i = ast_walk_context_includes(c, i);
2712 /* walk ignore patterns and write info ... */
2713 ip = ast_walk_context_ignorepats(c, NULL);
2715 bzero(buf, sizeof(buf));
2716 snprintf(buf, sizeof(buf), "'%s'",
2717 ast_get_ignorepat_name(ip));
2718 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2719 buf, ast_get_ignorepat_registrar(ip));
2720 ip = ast_walk_context_ignorepats(c, ip);
2722 sw = ast_walk_context_switches(c, NULL);
2724 bzero(buf, sizeof(buf));
2725 snprintf(buf, sizeof(buf), "'%s/%s'",
2726 ast_get_switch_name(sw),
2727 ast_get_switch_data(sw));
2728 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2729 buf, ast_get_switch_registrar(sw));
2730 sw = ast_walk_context_switches(c, sw);
2734 ast_unlock_context(c);
2736 /* if we print something in context, make an empty line */
2737 if (context_info_printed) ast_cli(fd, "\n");
2740 c = ast_walk_contexts(c);
2742 ast_unlock_contexts();
2744 /* check for input failure and throw some error messages */
2745 if (context && !context_existence) {
2746 ast_cli(fd, "There is no existence of '%s' context\n",
2748 return RESULT_FAILURE;
2751 if (exten && !extension_existence) {
2753 ast_cli(fd, "There is no existence of %s@%s extension\n",
2757 "There is no existence of '%s' extension in all contexts\n",
2759 return RESULT_FAILURE;
2763 return RESULT_SUCCESS;
2767 * CLI entries for upper commands ...
2769 static struct ast_cli_entry show_applications_cli =
2770 { { "show", "applications", NULL },
2771 handle_show_applications, "Shows registered applications",
2772 show_applications_help };
2774 static struct ast_cli_entry show_application_cli =
2775 { { "show", "application", NULL },
2776 handle_show_application, "Describe a specific application",
2777 show_application_help, complete_show_application };
2779 static struct ast_cli_entry show_dialplan_cli =
2780 { { "show", "dialplan", NULL },
2781 handle_show_dialplan, "Show dialplan",
2782 show_dialplan_help, complete_show_dialplan_context };
2784 static struct ast_cli_entry show_switches_cli =
2785 { { "show", "switches", NULL },
2786 handle_show_switches, "Show alternative switches",
2787 show_switches_help, NULL };
2789 int ast_unregister_application(char *app) {
2790 struct ast_app *tmp, *tmpl = NULL;
2791 if (ast_mutex_lock(&applock)) {
2792 ast_log(LOG_ERROR, "Unable to lock application list\n");
2797 if (!strcasecmp(app, tmp->name)) {
2799 tmpl->next = tmp->next;
2802 if (option_verbose > 1)
2803 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2804 ast_mutex_unlock(&applock);
2810 ast_mutex_unlock(&applock);
2814 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2816 struct ast_context *tmp, **local_contexts;
2818 local_contexts = &contexts;
2819 ast_mutex_lock(&conlock);
2821 local_contexts = extcontexts;
2823 tmp = *local_contexts;
2825 if (!strcasecmp(tmp->name, name)) {
2826 ast_mutex_unlock(&conlock);
2827 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2829 ast_mutex_unlock(&conlock);
2834 tmp = malloc(sizeof(struct ast_context));
2836 memset(tmp, 0, sizeof(struct ast_context));
2837 ast_mutex_init(&tmp->lock);
2838 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2840 tmp->registrar = registrar;
2841 tmp->next = *local_contexts;
2842 tmp->includes = NULL;
2843 tmp->ignorepats = NULL;
2844 *local_contexts = tmp;
2846 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2847 else if (option_verbose > 2)
2848 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2850 ast_log(LOG_ERROR, "Out of memory\n");
2853 ast_mutex_unlock(&conlock);
2857 void __ast_context_destroy(struct ast_context *con, char *registrar);
2859 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2860 struct ast_context *tmp, *lasttmp = NULL;
2862 ast_mutex_lock(&conlock);
2864 __ast_context_destroy(NULL,registrar);
2871 __ast_context_destroy(tmp,tmp->registrar);
2877 lasttmp->next = contexts;
2878 contexts = *extcontexts;
2879 *extcontexts = NULL;
2881 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2882 ast_mutex_unlock(&conlock);
2888 * EBUSY - can't lock
2889 * ENOENT - no existence of context
2891 int ast_context_add_include(char *context, char *include, char *registrar)
2893 struct ast_context *c;
2895 if (ast_lock_contexts()) {
2900 /* walk contexts ... */
2901 c = ast_walk_contexts(NULL);
2903 /* ... search for the right one ... */
2904 if (!strcmp(ast_get_context_name(c), context)) {
2905 int ret = ast_context_add_include2(c, include, registrar);
2906 /* ... unlock contexts list and return */
2907 ast_unlock_contexts();
2910 c = ast_walk_contexts(c);
2913 /* we can't find the right context */
2914 ast_unlock_contexts();
2922 while(*c && (*c != '|')) c++; \
2923 if (*c) { *c = '\0'; c++; } else c = NULL; \
2926 static void get_timerange(struct ast_include *i, char *times)
2935 //start disabling all times, fill the fields with 0's, as they may contain garbage
2936 memset(i->minmask, 0, sizeof(i->minmask));
2938 /* Star is all times */
2939 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
2941 i->minmask[x] = (1 << 30) - 1;
2944 /* Otherwise expect a range */
2945 e = strchr(times, '-');
2947 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
2952 while(*e && !isdigit(*e)) e++;
2954 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
2957 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2958 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
2961 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2962 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
2967 s1 = s1 * 30 + s2/2;
2968 if ((s1 < 0) || (s1 >= 24*30)) {
2969 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2972 e1 = e1 * 30 + e2/2;
2973 if ((e1 < 0) || (e1 >= 24*30)) {
2974 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
2977 /* Go through the time and enable each appropriate bit */
2978 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2979 i->minmask[x/30] |= (1 << (x % 30));
2981 /* Do the last one */
2982 i->minmask[x/30] |= (1 << (x % 30));
2984 for (cth=0;cth<24;cth++) {
2985 /* Initialize masks to blank */
2986 i->minmask[cth] = 0;
2987 for (ctm=0;ctm<30;ctm++) {
2989 /* First hour with more than one hour */
2990 (((cth == s1) && (ctm >= s2)) &&
2993 || (((cth == s1) && (ctm >= s2)) &&
2994 ((cth == e1) && (ctm <= e2)))
2995 /* In between first and last hours (more than 2 hours) */
2998 /* Last hour with more than one hour */
3000 ((cth == e1) && (ctm <= e2)))
3002 i->minmask[cth] |= (1 << (ctm / 2));
3010 static char *days[] =
3021 static unsigned int get_dow(char *dow)
3024 /* The following line is coincidence, really! */
3027 /* Check for all days */
3028 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3029 return (1 << 7) - 1;
3030 /* Get start and ending days */
3031 c = strchr(dow, '-');
3037 /* Find the start */
3039 while((s < 7) && strcasecmp(dow, days[s])) s++;
3041 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3046 while((e < 7) && strcasecmp(c, days[e])) e++;
3048 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3054 for (x=s;x!=e;x = (x + 1) % 7) {
3062 static unsigned int get_day(char *day)
3065 /* The following line is coincidence, really! */
3068 /* Check for all days */
3069 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3070 mask = (1 << 30) + ((1 << 30) - 1);
3073 /* Get start and ending days */
3074 c = strchr(day, '-');
3079 /* Find the start */
3080 if (sscanf(day, "%d", &s) != 1) {
3081 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3084 if ((s < 1) || (s > 31)) {
3085 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3090 if (sscanf(c, "%d", &e) != 1) {
3091 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3094 if ((e < 1) || (e > 31)) {
3095 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);