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 ;-)
53 #define EXT_DATA_SIZE 256
55 #define EXT_DATA_SIZE 8192
62 char exten[AST_MAX_EXTENSION];
64 char cidmatch[AST_MAX_EXTENSION];
67 struct ast_context *parent;
68 /* Application to execute */
69 char app[AST_MAX_EXTENSION];
73 void (*datad)(void *);
74 /* Next higher priority with our extension */
75 struct ast_exten *peer;
78 /* Extension with a greater ID */
79 struct ast_exten *next;
83 char name[AST_MAX_EXTENSION];
84 char rname[AST_MAX_EXTENSION];
87 unsigned int monthmask;
90 unsigned int minmask[24];
91 struct ast_include *next;
95 char name[AST_MAX_EXTENSION];
97 char data[AST_MAX_EXTENSION];
101 struct ast_ignorepat {
102 char pattern[AST_MAX_EXTENSION];
104 struct ast_ignorepat *next;
107 /* An extension context */
109 /* Name of the context */
110 char name[AST_MAX_EXTENSION];
111 /* A lock to prevent multiple threads from clobbering the context */
113 /* The root of the list of extensions */
114 struct ast_exten *root;
115 /* Link them together */
116 struct ast_context *next;
117 /* Include other contexts */
118 struct ast_include *includes;
119 /* Patterns for which to continue playing dialtone */
120 struct ast_ignorepat *ignorepats;
123 /* Alternative switches */
130 /* Name of the application */
131 char name[AST_MAX_APP];
132 int (*execute)(struct ast_channel *chan, void *data);
135 struct ast_app *next;
138 /* An extension state notify */
139 struct ast_state_cb {
142 ast_state_cb_type callback;
143 struct ast_state_cb *next;
147 struct ast_exten *exten;
149 struct ast_state_cb *callbacks;
150 struct ast_hint *next;
154 static int pbx_builtin_prefix(struct ast_channel *, void *);
155 static int pbx_builtin_suffix(struct ast_channel *, void *);
156 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
157 static int pbx_builtin_answer(struct ast_channel *, void *);
158 static int pbx_builtin_goto(struct ast_channel *, void *);
159 static int pbx_builtin_hangup(struct ast_channel *, void *);
160 static int pbx_builtin_background(struct ast_channel *, void *);
161 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
162 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
163 static int pbx_builtin_atimeout(struct ast_channel *, void *);
164 static int pbx_builtin_wait(struct ast_channel *, void *);
165 static int pbx_builtin_waitexten(struct ast_channel *, void *);
166 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
167 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
168 static int pbx_builtin_setaccount(struct ast_channel *, void *);
169 static int pbx_builtin_ringing(struct ast_channel *, void *);
170 static int pbx_builtin_progress(struct ast_channel *, void *);
171 static int pbx_builtin_congestion(struct ast_channel *, void *);
172 static int pbx_builtin_busy(struct ast_channel *, void *);
173 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
174 static int pbx_builtin_noop(struct ast_channel *, void *);
175 static int pbx_builtin_gotoif(struct ast_channel *, void *);
176 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
177 static int pbx_builtin_saynumber(struct ast_channel *, void *);
178 static int pbx_builtin_saydigits(struct ast_channel *, void *);
179 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
180 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
181 int pbx_builtin_setvar(struct ast_channel *, void *);
182 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
183 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
185 static struct varshead globals;
187 static struct pbx_builtin {
188 char name[AST_MAX_APP];
189 int (*execute)(struct ast_channel *chan, void *data);
194 /* These applications are built into the PBX core and do not
195 need separate modules
199 { "AbsoluteTimeout", pbx_builtin_atimeout,
200 "Set absolute maximum time of call",
201 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
202 "for a call. A setting of 0 disables the timeout. Always returns 0.\n" },
204 { "Answer", pbx_builtin_answer,
205 "Answer a channel if ringing",
206 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
207 "Returns 0 unless it tries to answer the channel and fails.\n" },
209 { "BackGround", pbx_builtin_background,
210 "Play a file while awaiting extension",
211 " Background(filename): Plays a given file, while simultaneously waiting for\n"
212 "the user to begin typing an extension. The timeouts do not count until the\n"
213 "last BackGround application as ended. Always returns 0.\n" },
215 { "Busy", pbx_builtin_busy,
216 "Indicate busy condition and stop",
217 " Busy(): Requests that the channel indicate busy condition and then waits\n"
218 "for the user to hang up. Always returns -1." },
220 { "Congestion", pbx_builtin_congestion,
221 "Indicate congestion and stop",
222 " Congestion(): Requests that the channel indicate congestion and then\n"
223 "waits for the user to hang up. Always returns -1." },
225 { "DigitTimeout", pbx_builtin_dtimeout,
226 "Set maximum timeout between digits",
227 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
228 "digits when the user is typing in an extension. When this timeout expires,\n"
229 "after the user has started to type in an extension, the extension will be\n"
230 "considered complete, and will be interpreted. Note that if an extension\n"
231 "typed in is valid, it will not have to timeout to be tested, so typically\n"
232 "at the expiry of this timeout, the extension will be considered invalid\n"
233 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
234 "exist the call would be terminated). Always returns 0.\n" },
236 { "Goto", pbx_builtin_goto,
237 "Goto a particular priority, extension, or context",
238 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
239 "value, optionally setting the extension and optionally the context as well.\n"
240 "The extension BYEXTENSION is special in that it uses the current extension,\n"
241 "thus permitting you to go to a different context, without specifying a\n"
242 "specific extension. Always returns 0, even if the given context, extension,\n"
243 "or priority is invalid.\n" },
245 { "GotoIf", pbx_builtin_gotoif,
247 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
248 "true, to label2 if condition is false. Either label1 or label2 may be\n"
249 "omitted (in that case, we just don't take the particular branch) but not\n"
250 "both. Look for the condition syntax in examples or documentation." },
252 { "GotoIfTime", pbx_builtin_gotoiftime,
253 "Conditional goto on current time",
254 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
255 "If the current time matches the specified time, then branch to the specified\n"
256 "extension. Each of the elements may be specified either as '*' (for always)\n"
257 "or as a range. See the include syntax." },
259 { "Hangup", pbx_builtin_hangup,
260 "Unconditional hangup",
261 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
263 { "NoOp", pbx_builtin_noop,
265 " NoOp(): No-operation; Does nothing." },
267 { "Prefix", pbx_builtin_prefix,
268 "Prepend leading digits",
269 " Prefix(digits): Prepends the digit string specified by digits to the\n"
270 "channel's associated extension. For example, the number 1212 when prefixed\n"
271 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
272 "continue processing at the next priority for the *new* extension.\n"
273 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
274 "executed will be priority 4 of 5551212. If you switch into an extension\n"
275 "which has no first step, the PBX will treat it as though the user dialed an\n"
276 "invalid extension.\n" },
278 { "Progress", pbx_builtin_progress,
280 " Progress(): Request that the channel indicate in-band progress is available to the user.\n"
281 "Always returns 0.\n" },
283 { "ResetCDR", pbx_builtin_resetcdr,
284 "Resets the Call Data Record",
285 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
286 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
287 "record WILL be stored. Always returns 0.\n" },
289 { "ResponseTimeout", pbx_builtin_rtimeout,
290 "Set maximum timeout awaiting response",
291 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
292 "falling through a series of priorities for a channel in which the user may\n"
293 "begin typing an extension. If the user does not type an extension in this\n"
294 "amount of time, control will pass to the 't' extension if it exists, and\n"
295 "if not the call would be terminated. Always returns 0.\n" },
297 { "Ringing", pbx_builtin_ringing,
298 "Indicate ringing tone",
299 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
300 "Always returns 0.\n" },
302 { "SayNumber", pbx_builtin_saynumber,
304 " SayNumber(digits[,gender]): Says the passed number\n" },
306 { "SayDigits", pbx_builtin_saydigits,
308 " SayDigits(digits): Says the passed digits\n" },
310 { "SayAlpha", pbx_builtin_saycharacters,
312 " SayAlpha(string): Spells the passed string\n" },
314 { "SayPhonetic", pbx_builtin_sayphonetic,
316 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n" },
318 { "SetAccount", pbx_builtin_setaccount,
320 " SetAccount([account]): Set the channel account code for billing\n"
321 "purposes. Always returns 0.\n" },
323 { "SetGlobalVar", pbx_builtin_setglobalvar,
324 "Set variable to value",
325 " SetGlobalVar(#n=value): Sets global variable n to value" },
327 { "SetLanguage", pbx_builtin_setlanguage,
328 "Sets user language",
329 " SetLanguage(language): Set the channel language to 'language'. This\n"
330 "information is used for the generation of numbers, and to choose a natural\n"
331 "language file when available. For example, if language is set to 'fr' and\n"
332 "the file 'demo-congrats' is requested to be played, if the file 'fr/demo-\n"
333 "congrats' exists, then it will play that file, and if not will play the\n"
334 "normal 'demo-congrats'. Always returns 0.\n" },
336 { "SetVar", pbx_builtin_setvar,
337 "Set variable to value",
338 " Setvar(#n=value): Sets variable n to value" },
340 { "StripMSD", pbx_builtin_stripmsd,
341 "Strip leading digits",
342 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
343 "associated extension. For example, the number 5551212 when stripped with a\n"
344 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
345 "will continue processing at the next priority for the *new* extension.\n"
346 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
347 "executed will be priority 4 of 1212. If you switch into an extension which\n"
348 "has no first step, the PBX will treat it as though the user dialed an\n"
349 "invalid extension.\n" },
351 { "Suffix", pbx_builtin_suffix,
352 "Append trailing digits",
353 " Suffix(digits): Appends the digit string specified by digits to the\n"
354 "channel's associated extension. For example, the number 555 when suffixed\n"
355 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
356 "continue processing at the next priority for the *new* extension.\n"
357 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
358 "executed will be priority 4 of 5551212. If you switch into an extension\n"
359 "which has no first step, the PBX will treat it as though the user dialed an\n"
360 "invalid extension.\n" },
362 { "Wait", pbx_builtin_wait,
363 "Waits for some time",
364 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
365 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" },
367 { "WaitExten", pbx_builtin_waitexten,
368 "Waits for some time",
369 " Wait(seconds): Waits for the user to enter a new extension for the \n"
370 "specified number of seconds, then returns 0. Seconds can be passed with\n"
371 "fractions of a second. (eg: 1.5 = 1.5 seconds)\n" },
375 /* Lock for the application list */
376 AST_MUTEX_DEFINE_STATIC(applock);
377 static struct ast_context *contexts = NULL;
378 /* Lock for the ast_context list */
379 AST_MUTEX_DEFINE_STATIC(conlock);
380 static struct ast_app *apps = NULL;
382 /* Lock for switches */
383 AST_MUTEX_DEFINE_STATIC(switchlock);
384 struct ast_switch *switches = NULL;
386 /* Lock for extension state notifys */
387 AST_MUTEX_DEFINE_STATIC(hintlock);
388 static int stateid = 1;
389 struct ast_hint *hints = NULL;
390 struct ast_state_cb *statecbs = NULL;
392 int pbx_exec(struct ast_channel *c, /* Channel */
394 void *data, /* Data for execution */
395 int newstack) /* Force stack increment */
397 /* This function is special. It saves the stack so that no matter
398 how many times it is called, it returns to the same place */
404 int stack = c->stack;
405 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
406 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
407 /* Don't allow us to go over the max number of stacks we
409 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
412 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
413 /* Okay, here's where it gets weird. If newstack is non-zero,
414 then we increase the stack increment, but setjmp is not going
415 to return until longjmp is called -- when the application
416 exec'd is finished running. */
419 if (c->stack != stack + 1)
420 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
421 else if (c->app[c->stack])
422 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
427 ast_cdr_setapp(c->cdr, app->name, data);
429 // save channel values
430 saved_c_appl= c->appl;
431 saved_c_data= c->data;
435 res = execute(c, data);
436 // restore channel values
437 c->appl= saved_c_appl;
438 c->data= saved_c_data;
440 /* Any application that returns, we longjmp back, just in case. */
441 if (c->stack != stack + 1)
442 ast_log(LOG_WARNING, "Stack is not at expected value\n");
443 longjmp(c->jmp[stack+1], res);
449 /* Go no deeper than this through includes (not counting loops) */
450 #define AST_PBX_MAX_STACK 64
452 #define HELPER_EXISTS 0
453 #define HELPER_SPAWN 1
454 #define HELPER_EXEC 2
455 #define HELPER_CANMATCH 3
456 #define HELPER_MATCHMORE 4
458 struct ast_app *pbx_findapp(char *app)
461 if (ast_mutex_lock(&applock)) {
462 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
467 if (!strcasecmp(tmp->name, app))
471 ast_mutex_unlock(&applock);
475 static struct ast_switch *pbx_findswitch(char *sw)
477 struct ast_switch *asw;
478 if (ast_mutex_lock(&switchlock)) {
479 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
484 if (!strcasecmp(asw->name, sw))
488 ast_mutex_unlock(&switchlock);
492 static inline int include_valid(struct ast_include *i)
501 /* If it's not the right month, return */
502 if (!(i->monthmask & (1 << tm.tm_mon))) {
506 /* If it's not that time of the month.... */
507 /* Warning, tm_mday has range 1..31! */
508 if (!(i->daymask & (1 << (tm.tm_mday-1))))
511 /* If it's not the right day of the week */
512 if (!(i->dowmask & (1 << tm.tm_wday)))
515 /* Sanity check the hour just to be safe */
516 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
517 ast_log(LOG_WARNING, "Insane time...\n");
521 /* Now the tough part, we calculate if it fits
522 in the right time based on min/hour */
523 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
526 /* If we got this far, then we're good */
530 static void pbx_destroy(struct ast_pbx *p)
535 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
536 /* All patterns begin with _ */\
537 if (pattern[0] != '_') \
539 /* Start optimistic */\
542 while(match && *data && *pattern && (*pattern != '/')) {\
543 switch(toupper(*pattern)) {\
550 where=strchr(pattern,']');\
552 border=(int)(where-pattern);\
553 if (!where || border > strlen(pattern)) {\
554 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
557 for (i=0; i<border; i++) {\
560 if (pattern[i+1]=='-') {\
561 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
568 if (res==1 || *data==pattern[i]) {\
577 if ((*data < '2') || (*data > '9'))\
581 if ((*data < '0') || (*data > '9'))\
585 if ((*data < '1') || (*data > '9'))\
593 /* Ignore these characters */\
597 if (*data != *pattern)\
605 int ast_extension_match(char *pattern, char *data)
608 /* If they're the same return */
609 if (!strcmp(pattern, data))
611 EXTENSION_MATCH_CORE(data,pattern,match);
612 /* Must be at the end of both */
613 if (*data || (*pattern && (*pattern != '/')))
618 static int extension_close(char *pattern, char *data, int needmore)
621 /* If "data" is longer, it can'be a subset of pattern unless
622 pattern is a pattern match */
623 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
626 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
627 (!needmore || (strlen(pattern) > strlen(data)))) {
630 EXTENSION_MATCH_CORE(data,pattern,match);
631 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
632 if (!needmore || *pattern) {
638 struct ast_context *ast_context_find(char *name)
640 struct ast_context *tmp;
641 ast_mutex_lock(&conlock);
645 if (!strcasecmp(name, tmp->name))
651 ast_mutex_unlock(&conlock);
655 #define STATUS_NO_CONTEXT 1
656 #define STATUS_NO_EXTENSION 2
657 #define STATUS_NO_PRIORITY 3
658 #define STATUS_SUCCESS 4
660 static int matchcid(char *cidpattern, char *callerid)
662 char tmp[AST_MAX_EXTENSION];
666 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
667 failing to get a number should count as a match, otherwise not */
670 if (!ast_strlen_zero(cidpattern))
678 /* Copy original Caller*ID */
679 strncpy(tmp, callerid, sizeof(tmp)-1);
681 if (ast_callerid_parse(tmp, &name, &num))
685 ast_shrink_phone_number(num);
686 return ast_extension_match(cidpattern, num);
689 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)
692 struct ast_context *tmp;
693 struct ast_exten *e, *eroot;
694 struct ast_include *i;
696 struct ast_switch *asw;
697 /* Initialize status if appropriate */
699 *status = STATUS_NO_CONTEXT;
703 /* Check for stack overflow */
704 if (*stacklen >= AST_PBX_MAX_STACK) {
705 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
708 /* Check first to see if we've already been checked */
709 for (x=0;x<*stacklen;x++) {
710 if (!strcasecmp(incstack[x], context))
716 if (!strcmp(tmp->name, context)) {
717 if (*status < STATUS_NO_EXTENSION)
718 *status = STATUS_NO_EXTENSION;
721 /* Match extension */
722 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
723 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
724 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
725 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
727 if (*status < STATUS_NO_PRIORITY)
728 *status = STATUS_NO_PRIORITY;
731 if (e->priority == priority) {
732 *status = STATUS_SUCCESS;
740 /* Check alternative switches */
743 if ((asw = pbx_findswitch(sw->name))) {
744 if (action == HELPER_CANMATCH)
745 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
746 else if (action == HELPER_MATCHMORE)
747 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
749 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
757 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
761 /* Setup the stack */
762 incstack[*stacklen] = tmp->name;
764 /* Now try any includes we have in this context */
767 if (include_valid(i)) {
768 if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
781 static void pbx_substitute_variables_temp(struct ast_channel *c,const char *var,char **ret, char *workspace, int workspacelen)
784 char tmpvar[80] = "";
786 struct tm brokentime;
788 struct ast_var_t *variables;
789 char *name, *num; /* for callerid name + num variables */
790 struct varshead *headp=NULL;
795 /* Now we have the variable name on cp3 */
796 if (!strncasecmp(var,"LEN(",4)) {
799 if (strrchr(var,')')) {
801 strncpy(cp3, var, sizeof(cp3) - 1);
802 cp3[len-len_len-1]='\0';
803 sprintf(workspace,"%d",(int)strlen(cp3));
809 } else if ((first=strchr(var,':'))) {
810 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
811 first = strchr(tmpvar, ':');
813 first = tmpvar + strlen(tmpvar);
815 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
817 offset=atoi(first+1);
818 if ((second=strchr(first+1,':'))) {
820 offset2=atoi(second+1);
822 offset2=strlen(*ret)-offset;
823 if (abs(offset)>strlen(*ret)) {
827 offset=-strlen(*ret);
829 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
831 offset2=strlen(*ret)-offset;
833 offset2=strlen(*ret)+offset;
838 *ret+=strlen(*ret)+offset;
839 (*ret)[offset2] = '\0';
840 } else if (c && !strcmp(var, "CALLERIDNUM")) {
842 strncpy(workspace, c->callerid, workspacelen - 1);
843 ast_callerid_parse(workspace, &name, &num);
845 ast_shrink_phone_number(num);
849 } else if (c && !strcmp(var, "CALLERIDNAME")) {
851 strncpy(workspace, c->callerid, workspacelen - 1);
852 ast_callerid_parse(workspace, &name, &num);
857 } else if (c && !strcmp(var, "CALLERID")) {
859 strncpy(workspace, c->callerid, workspacelen - 1);
863 } else if (c && !strcmp(var, "DNID")) {
865 strncpy(workspace, c->dnid, workspacelen - 1);
869 } else if (c && !strcmp(var, "HINT")) {
870 if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
874 } else if (c && !strcmp(var, "EXTEN")) {
875 strncpy(workspace, c->exten, workspacelen - 1);
877 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
878 /* XXX Remove me eventually */
879 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
882 if (offset > strlen(c->exten))
883 offset = strlen(c->exten);
884 strncpy(workspace, c->exten + offset, workspacelen - 1);
886 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
887 } else if (c && !strcmp(var, "RDNIS")) {
889 strncpy(workspace, c->rdnis, workspacelen - 1);
893 } else if (c && !strcmp(var, "CONTEXT")) {
894 strncpy(workspace, c->context, workspacelen - 1);
896 } else if (c && !strcmp(var, "PRIORITY")) {
897 snprintf(workspace, workspacelen, "%d", c->priority);
899 } else if (c && !strcmp(var, "CHANNEL")) {
900 strncpy(workspace, c->name, workspacelen - 1);
902 } else if (c && !strcmp(var, "EPOCH")) {
903 snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
905 } else if (c && !strcmp(var, "DATETIME")) {
907 localtime_r(&thistime, &brokentime);
908 snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
911 brokentime.tm_year+1900,
917 } else if (c && !strcmp(var, "TIMESTAMP")) {
919 localtime_r(&thistime, &brokentime);
920 /* 20031130-150612 */
921 snprintf(workspace, workspacelen -1, "%04d%02d%02d-%02d%02d%02d",
922 brokentime.tm_year+1900,
930 } else if (c && !strcmp(var, "UNIQUEID")) {
931 snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
933 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
934 snprintf(workspace, workspacelen -1, "%i", c->hangupcause);
936 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
937 strncpy(workspace, c->accountcode, workspacelen - 1);
939 } else if (c && !strcmp(var, "LANGUAGE")) {
940 strncpy(workspace, c->language, workspacelen - 1);
944 AST_LIST_TRAVERSE(headp,variables,entries) {
946 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
948 if (strcasecmp(ast_var_name(variables),var)==0) {
949 *ret=ast_var_value(variables);
951 strncpy(workspace, *ret, workspacelen - 1);
960 AST_LIST_TRAVERSE(&globals,variables,entries) {
962 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
964 if (strcasecmp(ast_var_name(variables),var)==0) {
965 *ret=ast_var_value(variables);
967 strncpy(workspace, *ret, workspacelen - 1);
975 int len_env=strlen("ENV(");
976 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
978 strncpy(cp3, var, sizeof(cp3) - 1);
980 *ret=getenv(cp3+len_env);
982 strncpy(workspace, *ret, workspacelen - 1);
990 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
993 const char *tmp, *whereweare;
995 char workspace[4096];
996 char ltmp[4096], var[4096];
997 char *nextvar, *nextexp;
999 int pos, brackets, needsub, len;
1001 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1004 while(!ast_strlen_zero(whereweare) && count) {
1005 /* Assume we're copying the whole remaining string */
1006 pos = strlen(whereweare);
1008 /* Look for a variable */
1009 nextvar = strstr(whereweare, "${");
1011 nextexp = strstr(whereweare, "$[");
1013 if (nextvar && nextexp) {
1014 if (nextvar < nextexp)
1020 /* If there is one, we only go that far */
1022 pos = nextvar - whereweare;
1024 pos = nextexp - whereweare;
1026 /* Can't copy more than 'count' bytes */
1030 /* Copy that many bytes */
1031 memcpy(cp2, whereweare, pos);
1038 /* We have a variable. Find the start and end, and determine
1039 if we are going to have to recursively call ourselves on the
1041 vars = vare = nextvar + 2;
1045 /* Find the end of it */
1046 while(brackets && *vare) {
1047 if ((vare[0] == '$') && (vare[1] == '{')) {
1050 } else if (vare[0] == '}') {
1052 } else if ((vare[0] == '$') && (vare[1] == '['))
1057 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1058 len = vare - vars - 1;
1060 /* Skip totally over variable name */
1061 whereweare += ( len + 3);
1063 /* Store variable name (and truncate) */
1064 memset(var, 0, sizeof(var));
1065 strncpy(var, vars, sizeof(var) - 1);
1068 /* Substitute if necessary */
1070 memset(ltmp, 0, sizeof(ltmp));
1071 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1077 /* Retrieve variable value */
1078 strcpy(workspace, "");
1079 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1081 length = strlen(cp4);
1084 memcpy(cp2, cp4, length);
1089 } else if (nextexp) {
1090 /* We have an expression. Find the start and end, and determine
1091 if we are going to have to recursively call ourselves on the
1093 vars = vare = nextexp + 2;
1097 /* Find the end of it */
1098 while(brackets && *vare) {
1099 if ((vare[0] == '$') && (vare[1] == '[')) {
1103 } else if (vare[0] == '[') {
1105 } else if (vare[0] == ']') {
1107 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1114 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1115 len = vare - vars - 1;
1117 /* Skip totally over variable name */
1118 whereweare += ( len + 3);
1120 /* Store variable name (and truncate) */
1121 memset(var, 0, sizeof(var));
1122 strncpy(var, vars, sizeof(var) - 1);
1125 /* Substitute if necessary */
1127 memset(ltmp, 0, sizeof(ltmp));
1128 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1134 /* Evaluate expression */
1135 cp4 = ast_expr(vars);
1137 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1140 length = strlen(cp4);
1143 memcpy(cp2, cp4, length);
1154 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1156 memset(passdata, 0, datalen);
1158 /* No variables or expressions in e->data, so why scan it? */
1159 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1160 strncpy(passdata, e->data, datalen - 1);
1161 passdata[datalen-1] = '\0';
1165 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1168 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1170 struct ast_exten *e;
1171 struct ast_app *app;
1172 struct ast_switch *sw;
1177 char *incstack[AST_PBX_MAX_STACK];
1178 char passdata[EXT_DATA_SIZE];
1182 char tmp3[EXT_DATA_SIZE];
1183 if (ast_mutex_lock(&conlock)) {
1184 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1185 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1190 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1193 case HELPER_CANMATCH:
1194 ast_mutex_unlock(&conlock);
1197 ast_mutex_unlock(&conlock);
1199 case HELPER_MATCHMORE:
1200 ast_mutex_unlock(&conlock);
1206 app = pbx_findapp(e->app);
1207 ast_mutex_unlock(&conlock);
1209 if (c->context != context)
1210 strncpy(c->context, context, sizeof(c->context)-1);
1211 if (c->exten != exten)
1212 strncpy(c->exten, exten, sizeof(c->exten)-1);
1213 c->priority = priority;
1214 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1216 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1217 else if (option_verbose > 2)
1218 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1219 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1220 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1221 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1222 (newstack ? "in new stack" : "in same stack"));
1223 res = pbx_exec(c, app, passdata, newstack);
1226 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1230 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1234 case HELPER_CANMATCH:
1235 ast_mutex_unlock(&conlock);
1238 ast_mutex_unlock(&conlock);
1240 case HELPER_MATCHMORE:
1241 ast_mutex_unlock(&conlock);
1247 ast_mutex_unlock(&conlock);
1249 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1251 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1256 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1260 ast_mutex_unlock(&conlock);
1262 case STATUS_NO_CONTEXT:
1263 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1264 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1266 case STATUS_NO_EXTENSION:
1267 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1268 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1270 case STATUS_NO_PRIORITY:
1271 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1272 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1275 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1277 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1285 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1287 struct ast_exten *e;
1288 struct ast_switch *sw;
1291 char *incstack[AST_PBX_MAX_STACK];
1294 if (ast_mutex_lock(&conlock)) {
1295 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1298 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1299 ast_mutex_unlock(&conlock);
1303 static int ast_extension_state2(struct ast_exten *e)
1305 char hint[AST_MAX_EXTENSION] = "";
1308 int allunavailable = 1, allbusy = 1, allfree = 1;
1311 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1315 rest = strchr(cur, '&');
1321 res = ast_device_state(cur);
1323 case AST_DEVICE_NOT_INUSE:
1327 case AST_DEVICE_INUSE:
1328 return AST_EXTENSION_INUSE;
1329 case AST_DEVICE_BUSY:
1334 case AST_DEVICE_UNAVAILABLE:
1335 case AST_DEVICE_INVALID:
1348 return AST_EXTENSION_NOT_INUSE;
1350 return AST_EXTENSION_BUSY;
1352 return AST_EXTENSION_UNAVAILABLE;
1354 return AST_EXTENSION_INUSE;
1356 return AST_EXTENSION_NOT_INUSE;
1360 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1362 struct ast_exten *e;
1364 e = ast_hint_extension(c, context, exten);
1368 return ast_extension_state2(e);
1371 int ast_device_state_changed(const char *fmt, ...)
1373 struct ast_hint *list;
1374 struct ast_state_cb *cblist;
1375 char hint[AST_MAX_EXTENSION];
1376 char device[AST_MAX_EXTENSION];
1383 vsnprintf(device, sizeof(device)-1, fmt, ap);
1386 rest = strchr(device, '-');
1391 ast_mutex_lock(&hintlock);
1397 strcpy(hint, ast_get_extension_app(list->exten));
1400 rest = strchr(cur, '&');
1406 if (!strcmp(cur, device)) {
1407 // Found extension execute callbacks
1408 state = ast_extension_state2(list->exten);
1409 if ((state != -1) && (state != list->laststate)) {
1410 // For general callbacks
1413 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1414 cblist = cblist->next;
1417 // For extension callbacks
1418 cblist = list->callbacks;
1420 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1421 cblist = cblist->next;
1424 list->laststate = state;
1434 ast_mutex_unlock(&hintlock);
1438 int ast_extension_state_add(char *context, char *exten,
1439 ast_state_cb_type callback, void *data)
1441 struct ast_hint *list;
1442 struct ast_state_cb *cblist;
1443 struct ast_exten *e;
1445 /* No context and extension add callback to statecbs list */
1446 if (!context && !exten) {
1447 ast_mutex_lock(&hintlock);
1451 if (cblist->callback == callback) {
1452 cblist->data = data;
1453 ast_mutex_unlock(&hintlock);
1456 cblist = cblist->next;
1459 /* Now inserts the callback */
1460 cblist = malloc(sizeof(struct ast_state_cb));
1462 ast_mutex_unlock(&hintlock);
1465 memset(cblist, 0, sizeof(struct ast_state_cb));
1467 cblist->callback = callback;
1468 cblist->data = data;
1470 cblist->next = statecbs;
1473 ast_mutex_unlock(&hintlock);
1477 if (!context || !exten)
1480 /* This callback type is for only one hint */
1481 e = ast_hint_extension(NULL, context, exten);
1486 ast_mutex_lock(&hintlock);
1490 if (list->exten == e)
1496 ast_mutex_unlock(&hintlock);
1500 /* Now inserts the callback */
1501 cblist = malloc(sizeof(struct ast_state_cb));
1503 ast_mutex_unlock(&hintlock);
1506 memset(cblist, 0, sizeof(struct ast_state_cb));
1507 cblist->id = stateid++;
1508 cblist->callback = callback;
1509 cblist->data = data;
1511 cblist->next = list->callbacks;
1512 list->callbacks = cblist;
1514 ast_mutex_unlock(&hintlock);
1518 int ast_extension_state_del(int id, ast_state_cb_type callback)
1520 struct ast_hint *list;
1521 struct ast_state_cb *cblist, *cbprev;
1523 if (!id && !callback)
1526 ast_mutex_lock(&hintlock);
1528 /* id is zero is a callback without extension */
1533 if (cblist->callback == callback) {
1535 statecbs = cblist->next;
1537 cbprev->next = cblist->next;
1541 ast_mutex_unlock(&hintlock);
1545 cblist = cblist->next;
1548 ast_mutex_lock(&hintlock);
1552 /* id greater zero is a callback with extension */
1555 cblist = list->callbacks;
1558 if (cblist->id==id) {
1560 list->callbacks = cblist->next;
1562 cbprev->next = cblist->next;
1566 ast_mutex_unlock(&hintlock);
1570 cblist = cblist->next;
1575 ast_mutex_unlock(&hintlock);
1579 static int ast_add_hint(struct ast_exten *e)
1581 struct ast_hint *list;
1585 ast_mutex_lock(&hintlock);
1588 /* Search if hint exists, do nothing */
1590 if (list->exten == e) {
1591 ast_mutex_unlock(&hintlock);
1597 list = malloc(sizeof(struct ast_hint));
1599 ast_mutex_unlock(&hintlock);
1602 /* Initialize and insert new item */
1603 memset(list, 0, sizeof(struct ast_hint));
1605 list->laststate = ast_extension_state2(e);
1609 ast_mutex_unlock(&hintlock);
1613 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1615 struct ast_hint *list;
1617 ast_mutex_lock(&hintlock);
1622 if (list->exten == oe) {
1624 ast_mutex_unlock(&hintlock);
1629 ast_mutex_unlock(&hintlock);
1634 static int ast_remove_hint(struct ast_exten *e)
1636 /* Cleanup the Notifys if hint is removed */
1637 struct ast_hint *list, *prev = NULL;
1638 struct ast_state_cb *cblist, *cbprev;
1643 ast_mutex_lock(&hintlock);
1647 if (list->exten==e) {
1649 cblist = list->callbacks;
1651 /* Notify with -1 and remove all callbacks */
1653 cblist = cblist->next;
1654 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1657 list->callbacks = NULL;
1662 prev->next = list->next;
1666 ast_mutex_unlock(&hintlock);
1674 ast_mutex_unlock(&hintlock);
1679 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1681 struct ast_exten *e;
1682 e = ast_hint_extension(c, context, exten);
1684 strncpy(hint, ast_get_extension_app(e), maxlen);
1690 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1692 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1695 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1697 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1700 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1702 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1705 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1707 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1710 int ast_pbx_run(struct ast_channel *c)
1719 /* A little initial setup here */
1721 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1722 c->pbx = malloc(sizeof(struct ast_pbx));
1724 ast_log(LOG_ERROR, "Out of memory\n");
1729 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1731 c->cdr = ast_cdr_alloc();
1733 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1737 ast_cdr_init(c->cdr, c);
1740 memset(c->pbx, 0, sizeof(struct ast_pbx));
1741 /* Set reasonable defaults */
1742 c->pbx->rtimeout = 10;
1743 c->pbx->dtimeout = 5;
1745 /* Start by trying whatever the channel is set to */
1746 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1747 /* JK02: If not successfull fall back to 's' */
1748 strncpy(c->exten, "s", sizeof(c->exten)-1);
1749 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1750 /* JK02: And finally back to default if everything else failed */
1751 strncpy(c->context, "default", sizeof(c->context)-1);
1756 ast_cdr_start(c->cdr);
1760 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1761 memset(exten, 0, sizeof(exten));
1762 manager_event(EVENT_FLAG_CALL, "Newexten",
1768 c->name, c->context, c->exten, c->priority, c->uniqueid);
1769 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1770 /* Something bad happened, or a hangup has been requested. */
1771 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1772 (res == '*') || (res == '#')) {
1773 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1774 memset(exten, 0, sizeof(exten));
1776 exten[pos++] = digit = res;
1780 case AST_PBX_KEEPALIVE:
1782 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1783 else if (option_verbose > 1)
1784 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1789 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1790 else if (option_verbose > 1)
1791 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1792 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1797 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1807 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1808 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1809 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1810 c->whentohangup = 0;
1812 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1813 } else if (c->_softhangup) {
1814 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1815 c->exten, c->priority);
1821 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1822 /* It's not a valid extension anymore */
1823 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1824 if (option_verbose > 2)
1825 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1826 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1827 strncpy(c->exten, "i", sizeof(c->exten)-1);
1830 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1831 c->name, c->exten, c->context);
1834 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1835 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1838 /* Done, wait for an extension */
1840 waittime = c->pbx->dtimeout;
1842 waittime = c->pbx->rtimeout;
1843 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1844 /* As long as we're willing to wait, and as long as it's not defined,
1845 keep reading digits until we can't possibly get a right answer anymore. */
1846 digit = ast_waitfordigit(c, waittime * 1000);
1847 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1854 /* Error, maybe a hangup */
1856 exten[pos++] = digit;
1857 waittime = c->pbx->dtimeout;
1860 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1861 /* Prepare the next cycle */
1862 strncpy(c->exten, exten, sizeof(c->exten)-1);
1865 /* No such extension */
1866 if (!ast_strlen_zero(exten)) {
1867 /* An invalid extension */
1868 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1869 if (option_verbose > 2)
1870 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1871 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1872 strncpy(c->exten, "i", sizeof(c->exten)-1);
1875 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1879 /* A simple timeout */
1880 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1881 if (option_verbose > 2)
1882 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1883 strncpy(c->exten, "t", sizeof(c->exten)-1);
1886 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1892 if (option_verbose > 2)
1893 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1899 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1901 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1902 strcpy(c->exten, "h");
1904 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1905 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1906 /* Something bad happened, or a hangup has been requested. */
1908 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1909 else if (option_verbose > 1)
1910 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1917 pbx_destroy(c->pbx);
1919 if (res != AST_PBX_KEEPALIVE)
1924 static void *pbx_thread(void *data)
1926 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1927 answer this channel and get it going. The setjmp stuff is fairly
1928 confusing, but necessary to get smooth transitions between
1929 the execution of different applications (without the use of
1930 additional threads) */
1931 struct ast_channel *c = data;
1937 int ast_pbx_start(struct ast_channel *c)
1940 pthread_attr_t attr;
1942 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1946 /* Start a new thread, and get something handling this channel. */
1947 pthread_attr_init(&attr);
1948 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1949 if (pthread_create(&t, &attr, pbx_thread, c)) {
1950 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1957 * This function locks contexts list by &conlist, search for the rigt context
1958 * structure, leave context list locked and call ast_context_remove_include2
1959 * which removes include, unlock contexts list and return ...
1961 int ast_context_remove_include(char *context, char *include, char *registrar)
1963 struct ast_context *c;
1965 if (ast_lock_contexts()) return -1;
1967 /* walk contexts and search for the right one ...*/
1968 c = ast_walk_contexts(NULL);
1970 /* we found one ... */
1971 if (!strcmp(ast_get_context_name(c), context)) {
1973 /* remove include from this context ... */
1974 ret = ast_context_remove_include2(c, include, registrar);
1976 ast_unlock_contexts();
1978 /* ... return results */
1981 c = ast_walk_contexts(c);
1984 /* we can't find the right one context */
1985 ast_unlock_contexts();
1990 * When we call this function, &conlock lock must be locked, because when
1991 * we giving *con argument, some process can remove/change this context
1992 * and after that there can be segfault.
1994 * This function locks given context, removes include, unlock context and
1997 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1999 struct ast_include *i, *pi = NULL;
2001 if (ast_mutex_lock(&con->lock)) return -1;
2006 /* find our include */
2007 if (!strcmp(i->name, include) &&
2008 (!strcmp(i->registrar, registrar) || !registrar)) {
2009 /* remove from list */
2013 con->includes = i->next;
2014 /* free include and return */
2016 ast_mutex_unlock(&con->lock);
2023 /* we can't find the right include */
2024 ast_mutex_unlock(&con->lock);
2029 * This function locks contexts list by &conlist, search for the rigt context
2030 * structure, leave context list locked and call ast_context_remove_switch2
2031 * which removes switch, unlock contexts list and return ...
2033 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
2035 struct ast_context *c;
2037 if (ast_lock_contexts()) return -1;
2039 /* walk contexts and search for the right one ...*/
2040 c = ast_walk_contexts(NULL);
2042 /* we found one ... */
2043 if (!strcmp(ast_get_context_name(c), context)) {
2045 /* remove switch from this context ... */
2046 ret = ast_context_remove_switch2(c, sw, data, registrar);
2048 ast_unlock_contexts();
2050 /* ... return results */
2053 c = ast_walk_contexts(c);
2056 /* we can't find the right one context */
2057 ast_unlock_contexts();
2062 * When we call this function, &conlock lock must be locked, because when
2063 * we giving *con argument, some process can remove/change this context
2064 * and after that there can be segfault.
2066 * This function locks given context, removes switch, unlock context and
2069 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2071 struct ast_sw *i, *pi = NULL;
2073 if (ast_mutex_lock(&con->lock)) return -1;
2078 /* find our switch */
2079 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2080 (!strcmp(i->registrar, registrar) || !registrar)) {
2081 /* remove from list */
2085 con->alts = i->next;
2086 /* free switch and return */
2088 ast_mutex_unlock(&con->lock);
2095 /* we can't find the right switch */
2096 ast_mutex_unlock(&con->lock);
2101 * This functions lock contexts list, search for the right context,
2102 * call ast_context_remove_extension2, unlock contexts list and return.
2103 * In this function we are using
2105 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2107 struct ast_context *c;
2109 if (ast_lock_contexts()) return -1;
2111 /* walk contexts ... */
2112 c = ast_walk_contexts(NULL);
2114 /* ... search for the right one ... */
2115 if (!strcmp(ast_get_context_name(c), context)) {
2116 /* ... remove extension ... */
2117 int ret = ast_context_remove_extension2(c, extension, priority,
2119 /* ... unlock contexts list and return */
2120 ast_unlock_contexts();
2123 c = ast_walk_contexts(c);
2126 /* we can't find the right context */
2127 ast_unlock_contexts();
2132 * When do you want to call this function, make sure that &conlock is locked,
2133 * because some process can handle with your *con context before you lock
2136 * This functionc locks given context, search for the right extension and
2137 * fires out all peer in this extensions with given priority. If priority
2138 * is set to 0, all peers are removed. After that, unlock context and
2141 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2143 struct ast_exten *exten, *prev_exten = NULL;
2145 if (ast_mutex_lock(&con->lock)) return -1;
2147 /* go through all extensions in context and search the right one ... */
2151 /* look for right extension */
2152 if (!strcmp(exten->exten, extension) &&
2153 (!strcmp(exten->registrar, registrar) || !registrar)) {
2154 struct ast_exten *peer;
2156 /* should we free all peers in this extension? (priority == 0)? */
2157 if (priority == 0) {
2158 /* remove this extension from context list */
2160 prev_exten->next = exten->next;
2162 con->root = exten->next;
2164 /* fire out all peers */
2169 if (!peer->priority==PRIORITY_HINT)
2170 ast_remove_hint(peer);
2172 peer->datad(peer->data);
2178 ast_mutex_unlock(&con->lock);
2181 /* remove only extension with exten->priority == priority */
2182 struct ast_exten *previous_peer = NULL;
2186 /* is this our extension? */
2187 if (peer->priority == priority &&
2188 (!strcmp(peer->registrar, registrar) || !registrar)) {
2189 /* we are first priority extension? */
2190 if (!previous_peer) {
2191 /* exists previous extension here? */
2193 /* yes, so we must change next pointer in
2194 * previous connection to next peer
2197 prev_exten->next = peer->peer;
2198 peer->peer->next = exten->next;
2200 prev_exten->next = exten->next;
2202 /* no previous extension, we are first
2203 * extension, so change con->root ...
2206 con->root = peer->peer;
2208 con->root = exten->next;
2211 /* we are not first priority in extension */
2212 previous_peer->peer = peer->peer;
2215 /* now, free whole priority extension */
2216 if (peer->priority==PRIORITY_HINT)
2217 ast_remove_hint(peer);
2218 peer->datad(peer->data);
2221 ast_mutex_unlock(&con->lock);
2224 /* this is not right extension, skip to next peer */
2225 previous_peer = peer;
2230 ast_mutex_unlock(&con->lock);
2236 exten = exten->next;
2239 /* we can't find right extension */
2240 ast_mutex_unlock(&con->lock);
2245 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2247 struct ast_app *tmp, *prev, *cur;
2249 if (ast_mutex_lock(&applock)) {
2250 ast_log(LOG_ERROR, "Unable to lock application list\n");
2255 if (!strcasecmp(app, tmp->name)) {
2256 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2257 ast_mutex_unlock(&applock);
2262 tmp = malloc(sizeof(struct ast_app));
2264 memset(tmp, 0, sizeof(struct ast_app));
2265 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2266 tmp->execute = execute;
2267 tmp->synopsis = synopsis;
2268 tmp->description = description;
2269 /* Store in alphabetical order */
2273 if (strcasecmp(tmp->name, cur->name) < 0)
2279 tmp->next = prev->next;
2286 ast_log(LOG_ERROR, "Out of memory\n");
2287 ast_mutex_unlock(&applock);
2290 if (option_verbose > 1)
2291 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2292 ast_mutex_unlock(&applock);
2296 int ast_register_switch(struct ast_switch *sw)
2298 struct ast_switch *tmp, *prev=NULL;
2299 if (ast_mutex_lock(&switchlock)) {
2300 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2305 if (!strcasecmp(tmp->name, sw->name))
2311 ast_mutex_unlock(&switchlock);
2312 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2320 ast_mutex_unlock(&switchlock);
2324 void ast_unregister_switch(struct ast_switch *sw)
2326 struct ast_switch *tmp, *prev=NULL;
2327 if (ast_mutex_lock(&switchlock)) {
2328 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2335 prev->next = tmp->next;
2337 switches = tmp->next;
2344 ast_mutex_unlock(&switchlock);
2348 * Help for CLI commands ...
2350 static char show_application_help[] =
2351 "Usage: show application <application> [<application> [<application> [...]]]\n"
2352 " Describes a particular application.\n";
2354 static char show_applications_help[] =
2355 "Usage: show applications\n"
2356 " List applications which are currently available.\n";
2358 static char show_dialplan_help[] =
2359 "Usage: show dialplan [exten@][context]\n"
2362 static char show_switches_help[] =
2363 "Usage: show switches\n"
2364 " Show registered switches\n";
2367 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2372 * 'show application' CLI command implementation functions ...
2376 * There is a possibility to show informations about more than one
2377 * application at one time. You can type 'show application Dial Echo' and
2378 * you will see informations about these two applications ...
2380 static char *complete_show_application(char *line, char *word,
2386 /* try to lock applications list ... */
2387 if (ast_mutex_lock(&applock)) {
2388 ast_log(LOG_ERROR, "Unable to lock application list\n");
2392 /* ... walk all applications ... */
2395 /* ... check if word matches this application ... */
2396 if (!strncasecmp(word, a->name, strlen(word))) {
2397 /* ... if this is right app serve it ... */
2398 if (++which > state) {
2399 char *ret = strdup(a->name);
2400 ast_mutex_unlock(&applock);
2407 /* no application match */
2408 ast_mutex_unlock(&applock);
2412 static int handle_show_application(int fd, int argc, char *argv[])
2415 int app, no_registered_app = 1;
2417 if (argc < 3) return RESULT_SHOWUSAGE;
2419 /* try to lock applications list ... */
2420 if (ast_mutex_lock(&applock)) {
2421 ast_log(LOG_ERROR, "Unable to lock application list\n");
2425 /* ... go through all applications ... */
2428 /* ... compare this application name with all arguments given
2429 * to 'show application' command ... */
2430 for (app = 2; app < argc; app++) {
2431 if (!strcasecmp(a->name, argv[app])) {
2432 /* Maximum number of characters added by terminal coloring is 22 */
2433 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2434 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2435 int synopsis_size, description_size;
2437 no_registered_app = 0;
2440 synopsis_size = strlen(a->synopsis) + 23;
2442 synopsis_size = strlen("Not available") + 23;
2443 synopsis = alloca(synopsis_size);
2446 description_size = strlen(a->description) + 23;
2448 description_size = strlen("Not available") + 23;
2449 description = alloca(description_size);
2451 if (synopsis && description) {
2452 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2453 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2454 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2455 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2456 term_color(synopsis,
2457 a->synopsis ? a->synopsis : "Not available",
2458 COLOR_CYAN, 0, synopsis_size);
2459 term_color(description,
2460 a->description ? a->description : "Not available",
2461 COLOR_CYAN, 0, description_size);
2463 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2465 /* ... one of our applications, show info ...*/
2466 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2467 "[Synopsis]:\n %s\n\n"
2468 "[Description]:\n%s\n",
2470 a->synopsis ? a->synopsis : "Not available",
2471 a->description ? a->description : "Not available");
2478 ast_mutex_unlock(&applock);
2480 /* we found at least one app? no? */
2481 if (no_registered_app) {
2482 ast_cli(fd, "Your application(s) is (are) not registered\n");
2483 return RESULT_FAILURE;
2486 return RESULT_SUCCESS;
2489 static int handle_show_switches(int fd, int argc, char *argv[])
2491 struct ast_switch *sw;
2493 ast_cli(fd, "There are no registered alternative switches\n");
2494 return RESULT_SUCCESS;
2496 /* ... we have applications ... */
2497 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2498 if (ast_mutex_lock(&switchlock)) {
2499 ast_log(LOG_ERROR, "Unable to lock switches\n");
2504 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2507 ast_mutex_unlock(&switchlock);
2508 return RESULT_SUCCESS;
2512 * 'show applications' CLI command implementation functions ...
2514 static int handle_show_applications(int fd, int argc, char *argv[])
2518 /* try to lock applications list ... */
2519 if (ast_mutex_lock(&applock)) {
2520 ast_log(LOG_ERROR, "Unable to lock application list\n");
2524 /* ... go to first application ... */
2527 /* ... have we got at least one application (first)? no? */
2529 ast_cli(fd, "There is no registered applications\n");
2530 ast_mutex_unlock(&applock);
2534 /* ... we have applications ... */
2535 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2537 /* ... go through all applications ... */
2539 /* ... show informations about applications ... */
2540 ast_cli(fd," %20s: %s\n",
2542 a->synopsis ? a->synopsis : "<Synopsis not available>");
2546 /* ... unlock and return */
2547 ast_mutex_unlock(&applock);
2549 return RESULT_SUCCESS;
2553 * 'show dialplan' CLI command implementation functions ...
2555 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2558 struct ast_context *c;
2561 /* we are do completion of [exten@]context on second position only */
2562 if (pos != 2) return NULL;
2564 /* try to lock contexts list ... */
2565 if (ast_lock_contexts()) {
2566 ast_log(LOG_ERROR, "Unable to lock context list\n");
2570 /* ... walk through all contexts ... */
2571 c = ast_walk_contexts(NULL);
2573 /* ... word matches context name? yes? ... */
2574 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2575 /* ... for serve? ... */
2576 if (++which > state) {
2577 /* ... yes, serve this context name ... */
2578 char *ret = strdup(ast_get_context_name(c));
2579 ast_unlock_contexts();
2583 c = ast_walk_contexts(c);
2586 /* ... unlock and return */
2587 ast_unlock_contexts();
2591 static int handle_show_dialplan(int fd, int argc, char *argv[])
2593 struct ast_context *c;
2594 char *exten = NULL, *context = NULL;
2595 int context_existence = 0, extension_existence = 0;
2597 if (argc != 3 && argc != 2) return -1;
2599 /* we obtain [exten@]context? if yes, split them ... */
2601 char *splitter = argv[2];
2602 /* is there a '@' character? */
2603 if (strchr(argv[2], '@')) {
2604 /* yes, split into exten & context ... */
2605 exten = strsep(&splitter, "@");
2608 /* check for length and change to NULL if ast_strlen_zero() */
2609 if (ast_strlen_zero(exten)) exten = NULL;
2610 if (ast_strlen_zero(context)) context = NULL;
2613 /* no '@' char, only context given */
2615 if (ast_strlen_zero(context)) context = NULL;
2619 /* try to lock contexts */
2620 if (ast_lock_contexts()) {
2621 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2622 return RESULT_FAILURE;
2625 /* walk all contexts ... */
2626 c = ast_walk_contexts(NULL);
2628 /* show this context? */
2630 !strcmp(ast_get_context_name(c), context)) {
2631 context_existence = 1;
2633 /* try to lock context before walking in ... */
2634 if (!ast_lock_context(c)) {
2635 struct ast_exten *e;
2636 struct ast_include *i;
2637 struct ast_ignorepat *ip;
2639 char buf[256], buf2[256];
2640 int context_info_printed = 0;
2642 /* are we looking for exten too? if yes, we print context
2643 * if we our extension only
2646 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2647 ast_get_context_name(c), ast_get_context_registrar(c));
2648 context_info_printed = 1;
2651 /* walk extensions ... */
2652 e = ast_walk_context_extensions(c, NULL);
2654 struct ast_exten *p;
2656 /* looking for extension? is this our extension? */
2658 strcmp(ast_get_extension_name(e), exten))
2660 /* we are looking for extension and it's not our
2661 * extension, so skip to next extension */
2662 e = ast_walk_context_extensions(c, e);
2666 extension_existence = 1;
2668 /* may we print context info? */
2669 if (!context_info_printed) {
2670 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2671 ast_get_context_name(c),
2672 ast_get_context_registrar(c));
2673 context_info_printed = 1;
2676 /* write extension name and first peer */
2677 bzero(buf, sizeof(buf));
2678 snprintf(buf, sizeof(buf), "'%s' =>",
2679 ast_get_extension_name(e));
2681 snprintf(buf2, sizeof(buf2),
2683 ast_get_extension_priority(e),
2684 ast_get_extension_app(e),
2685 (char *)ast_get_extension_app_data(e));
2687 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2688 ast_get_extension_registrar(e));
2690 /* walk next extension peers */
2691 p = ast_walk_extension_priorities(e, e);
2693 bzero((void *)buf2, sizeof(buf2));
2695 snprintf(buf2, sizeof(buf2),
2697 ast_get_extension_priority(p),
2698 ast_get_extension_app(p),
2699 (char *)ast_get_extension_app_data(p));
2701 ast_cli(fd," %-17s %-45s [%s]\n",
2703 ast_get_extension_registrar(p));
2705 p = ast_walk_extension_priorities(e, p);
2707 e = ast_walk_context_extensions(c, e);
2710 /* include & ignorepat we all printing if we are not
2711 * looking for exact extension
2714 if (ast_walk_context_extensions(c, NULL))
2717 /* walk included and write info ... */
2718 i = ast_walk_context_includes(c, NULL);
2720 bzero(buf, sizeof(buf));
2721 snprintf(buf, sizeof(buf), "'%s'",
2722 ast_get_include_name(i));
2723 ast_cli(fd, " Include => %-45s [%s]\n",
2724 buf, ast_get_include_registrar(i));
2725 i = ast_walk_context_includes(c, i);
2728 /* walk ignore patterns and write info ... */
2729 ip = ast_walk_context_ignorepats(c, NULL);
2731 bzero(buf, sizeof(buf));
2732 snprintf(buf, sizeof(buf), "'%s'",
2733 ast_get_ignorepat_name(ip));
2734 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2735 buf, ast_get_ignorepat_registrar(ip));
2736 ip = ast_walk_context_ignorepats(c, ip);
2738 sw = ast_walk_context_switches(c, NULL);
2740 bzero(buf, sizeof(buf));
2741 snprintf(buf, sizeof(buf), "'%s/%s'",
2742 ast_get_switch_name(sw),
2743 ast_get_switch_data(sw));
2744 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2745 buf, ast_get_switch_registrar(sw));
2746 sw = ast_walk_context_switches(c, sw);
2750 ast_unlock_context(c);
2752 /* if we print something in context, make an empty line */
2753 if (context_info_printed) ast_cli(fd, "\n");
2756 c = ast_walk_contexts(c);
2758 ast_unlock_contexts();
2760 /* check for input failure and throw some error messages */
2761 if (context && !context_existence) {
2762 ast_cli(fd, "There is no existence of '%s' context\n",
2764 return RESULT_FAILURE;
2767 if (exten && !extension_existence) {
2769 ast_cli(fd, "There is no existence of %s@%s extension\n",
2773 "There is no existence of '%s' extension in all contexts\n",
2775 return RESULT_FAILURE;
2779 return RESULT_SUCCESS;
2783 * CLI entries for upper commands ...
2785 static struct ast_cli_entry show_applications_cli =
2786 { { "show", "applications", NULL },
2787 handle_show_applications, "Shows registered applications",
2788 show_applications_help };
2790 static struct ast_cli_entry show_application_cli =
2791 { { "show", "application", NULL },
2792 handle_show_application, "Describe a specific application",
2793 show_application_help, complete_show_application };
2795 static struct ast_cli_entry show_dialplan_cli =
2796 { { "show", "dialplan", NULL },
2797 handle_show_dialplan, "Show dialplan",
2798 show_dialplan_help, complete_show_dialplan_context };
2800 static struct ast_cli_entry show_switches_cli =
2801 { { "show", "switches", NULL },
2802 handle_show_switches, "Show alternative switches",
2803 show_switches_help, NULL };
2805 int ast_unregister_application(char *app) {
2806 struct ast_app *tmp, *tmpl = NULL;
2807 if (ast_mutex_lock(&applock)) {
2808 ast_log(LOG_ERROR, "Unable to lock application list\n");
2813 if (!strcasecmp(app, tmp->name)) {
2815 tmpl->next = tmp->next;
2818 if (option_verbose > 1)
2819 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2820 ast_mutex_unlock(&applock);
2826 ast_mutex_unlock(&applock);
2830 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2832 struct ast_context *tmp, **local_contexts;
2834 local_contexts = &contexts;
2835 ast_mutex_lock(&conlock);
2837 local_contexts = extcontexts;
2839 tmp = *local_contexts;
2841 if (!strcasecmp(tmp->name, name)) {
2842 ast_mutex_unlock(&conlock);
2843 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2845 ast_mutex_unlock(&conlock);
2850 tmp = malloc(sizeof(struct ast_context));
2852 memset(tmp, 0, sizeof(struct ast_context));
2853 ast_mutex_init(&tmp->lock);
2854 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2856 tmp->registrar = registrar;
2857 tmp->next = *local_contexts;
2858 tmp->includes = NULL;
2859 tmp->ignorepats = NULL;
2860 *local_contexts = tmp;
2862 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2863 else if (option_verbose > 2)
2864 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2866 ast_log(LOG_ERROR, "Out of memory\n");
2869 ast_mutex_unlock(&conlock);
2873 void __ast_context_destroy(struct ast_context *con, char *registrar);
2875 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2876 struct ast_context *tmp, *lasttmp = NULL;
2878 ast_mutex_lock(&conlock);
2880 __ast_context_destroy(NULL,registrar);
2887 __ast_context_destroy(tmp,tmp->registrar);
2893 lasttmp->next = contexts;
2894 contexts = *extcontexts;
2895 *extcontexts = NULL;
2897 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2898 ast_mutex_unlock(&conlock);
2904 * EBUSY - can't lock
2905 * ENOENT - no existence of context
2907 int ast_context_add_include(char *context, char *include, char *registrar)
2909 struct ast_context *c;
2911 if (ast_lock_contexts()) {
2916 /* walk contexts ... */
2917 c = ast_walk_contexts(NULL);
2919 /* ... search for the right one ... */
2920 if (!strcmp(ast_get_context_name(c), context)) {
2921 int ret = ast_context_add_include2(c, include, registrar);
2922 /* ... unlock contexts list and return */
2923 ast_unlock_contexts();
2926 c = ast_walk_contexts(c);
2929 /* we can't find the right context */
2930 ast_unlock_contexts();
2938 while(*c && (*c != '|')) c++; \
2939 if (*c) { *c = '\0'; c++; } else c = NULL; \
2942 static void get_timerange(struct ast_include *i, char *times)
2951 //start disabling all times, fill the fields with 0's, as they may contain garbage
2952 memset(i->minmask, 0, sizeof(i->minmask));
2954 /* Star is all times */
2955 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
2957 i->minmask[x] = (1 << 30) - 1;
2960 /* Otherwise expect a range */
2961 e = strchr(times, '-');
2963 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
2968 while(*e && !isdigit(*e)) e++;
2970 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
2973 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2974 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
2977 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2978 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
2983 s1 = s1 * 30 + s2/2;
2984 if ((s1 < 0) || (s1 >= 24*30)) {
2985 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2988 e1 = e1 * 30 + e2/2;
2989 if ((e1 < 0) || (e1 >= 24*30)) {
2990 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
2993 /* Go through the time and enable each appropriate bit */
2994 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2995 i->minmask[x/30] |= (1 << (x % 30));
2997 /* Do the last one */
2998 i->minmask[x/30] |= (1 << (x % 30));
3000 for (cth=0;cth<24;cth++) {
3001 /* Initialize masks to blank */
3002 i->minmask[cth] = 0;
3003 for (ctm=0;ctm<30;ctm++) {
3005 /* First hour with more than one hour */
3006 (((cth == s1) && (ctm >= s2)) &&
3009 || (((cth == s1) && (ctm >= s2)) &&
3010 ((cth == e1) && (ctm <= e2)))
3011 /* In between first and last hours (more than 2 hours) */
3014 /* Last hour with more than one hour */
3016 ((cth == e1) && (ctm <= e2)))
3018 i->minmask[cth] |= (1 << (ctm / 2));
3026 static char *days[] =
3037 static unsigned int get_dow(char *dow)
3040 /* The following line is coincidence, really! */
3043 /* Check for all days */
3044 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3045 return (1 << 7) - 1;
3046 /* Get start and ending days */
3047 c = strchr(dow, '-');
3053 /* Find the start */
3055 while((s < 7) && strcasecmp(dow, days[s])) s++;
3057 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3062 while((e < 7) && strcasecmp(c, days[e])) e++;
3064 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3070 for (x=s;x!=e;x = (x + 1) % 7) {
3078 static unsigned int get_day(char *day)
3081 /* The following line is coincidence, really! */
3084 /* Check for all days */
3085 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3086 mask = (1 << 30) + ((1 << 30) - 1);
3089 /* Get start and ending days */
3090 c = strchr(day, '-');
3095 /* Find the start */
3096 if (sscanf(day, "%d", &s) != 1) {
3097 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);