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/term.h>
24 #include <asterisk/manager.h>
25 #include <asterisk/ast_expr.h>
26 #include <asterisk/channel_pvt.h>
27 #include <asterisk/linkedlists.h>
28 #include <asterisk/say.h>
43 * The speed of extension handling will likely be among the most important
44 * aspects of this PBX. The switching scheme as it exists right now isn't
45 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
46 * of priorities, but a constant search time here would be great ;-)
55 char exten[AST_MAX_EXTENSION];
57 char cidmatch[AST_MAX_EXTENSION];
60 struct ast_context *parent;
61 /* Application to execute */
62 char app[AST_MAX_EXTENSION];
66 void (*datad)(void *);
67 /* Next higher priority with our extension */
68 struct ast_exten *peer;
71 /* Extension with a greater ID */
72 struct ast_exten *next;
76 char name[AST_MAX_EXTENSION];
77 char rname[AST_MAX_EXTENSION];
80 unsigned int monthmask;
83 unsigned int minmask[24];
84 struct ast_include *next;
88 char name[AST_MAX_EXTENSION];
90 char data[AST_MAX_EXTENSION];
94 struct ast_ignorepat {
95 char pattern[AST_MAX_EXTENSION];
97 struct ast_ignorepat *next;
100 /* An extension context */
102 /* Name of the context */
103 char name[AST_MAX_EXTENSION];
104 /* A lock to prevent multiple threads from clobbering the context */
106 /* The root of the list of extensions */
107 struct ast_exten *root;
108 /* Link them together */
109 struct ast_context *next;
110 /* Include other contexts */
111 struct ast_include *includes;
112 /* Patterns for which to continue playing dialtone */
113 struct ast_ignorepat *ignorepats;
116 /* Alternative switches */
123 /* Name of the application */
124 char name[AST_MAX_APP];
125 int (*execute)(struct ast_channel *chan, void *data);
128 struct ast_app *next;
131 /* An extension state notify */
132 struct ast_state_cb {
135 ast_state_cb_type callback;
136 struct ast_state_cb *next;
140 struct ast_exten *exten;
142 struct ast_state_cb *callbacks;
143 struct ast_hint *next;
147 static int pbx_builtin_prefix(struct ast_channel *, void *);
148 static int pbx_builtin_suffix(struct ast_channel *, void *);
149 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
150 static int pbx_builtin_answer(struct ast_channel *, void *);
151 static int pbx_builtin_goto(struct ast_channel *, void *);
152 static int pbx_builtin_hangup(struct ast_channel *, void *);
153 static int pbx_builtin_background(struct ast_channel *, void *);
154 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
155 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
156 static int pbx_builtin_atimeout(struct ast_channel *, void *);
157 static int pbx_builtin_wait(struct ast_channel *, void *);
158 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
159 static int pbx_builtin_setaccount(struct ast_channel *, void *);
160 static int pbx_builtin_ringing(struct ast_channel *, void *);
161 static int pbx_builtin_congestion(struct ast_channel *, void *);
162 static int pbx_builtin_busy(struct ast_channel *, void *);
163 static int pbx_builtin_setvar(struct ast_channel *, void *);
164 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
165 static int pbx_builtin_noop(struct ast_channel *, void *);
166 static int pbx_builtin_gotoif(struct ast_channel *, void *);
167 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
168 static int pbx_builtin_saynumber(struct ast_channel *, void *);
169 static int pbx_builtin_saydigits(struct ast_channel *, void *);
170 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
171 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
173 static struct varshead globals = AST_LIST_HEAD_INITIALIZER(varshead);
175 static struct pbx_builtin {
176 char name[AST_MAX_APP];
177 int (*execute)(struct ast_channel *chan, void *data);
182 /* These applications are built into the PBX core and do not
183 need separate modules
187 { "AbsoluteTimeout", pbx_builtin_atimeout,
188 "Set absolute maximum time of call",
189 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
190 "for a call. A setting of 0 disables the timeout. Always returns 0.\n" },
192 { "Answer", pbx_builtin_answer,
193 "Answer a channel if ringing",
194 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
195 "Returns 0 unless it tries to answer the channel and fails.\n" },
197 { "BackGround", pbx_builtin_background,
198 "Play a file while awaiting extension",
199 " Background(filename): Plays a given file, while simultaneously waiting for\n"
200 "the user to begin typing an extension. The timeouts do not count until the\n"
201 "last BackGround application as ended. Always returns 0.\n" },
203 { "Busy", pbx_builtin_busy,
204 "Indicate busy condition and stop",
205 " Busy(): Requests that the channel indicate busy condition and then waits\n"
206 "for the user to hang up. Always returns -1." },
208 { "Congestion", pbx_builtin_congestion,
209 "Indicate congestion and stop",
210 " Congestion(): Requests that the channel indicate congestion and then\n"
211 "waits for the user to hang up. Always returns -1." },
213 { "DigitTimeout", pbx_builtin_dtimeout,
214 "Set maximum timeout between digits",
215 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
216 "digits when the user is typing in an extension. When this timeout expires,\n"
217 "after the user has started to type in an extension, the extension will be\n"
218 "considered complete, and will be interpreted. Note that if an extension\n"
219 "typed in is valid, it will not have to timeout to be tested, so typically\n"
220 "at the expiry of this timeout, the extension will be considered invalid\n"
221 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
222 "exist the call would be terminated). Always returns 0.\n" },
224 { "Goto", pbx_builtin_goto,
225 "Goto a particular priority, extension, or context",
226 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
227 "value, optionally setting the extension and optionally the context as well.\n"
228 "The extension BYEXTENSION is special in that it uses the current extension,\n"
229 "thus permitting you to go to a different context, without specifying a\n"
230 "specific extension. Always returns 0, even if the given context, extension,\n"
231 "or priority is invalid.\n" },
233 { "GotoIf", pbx_builtin_gotoif,
235 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
236 "true, to label2 if condition is false. Either label1 or label2 may be\n"
237 "omitted (in that case, we just don't take the particular branch) but not\n"
238 "both. Look for the condition syntax in examples or documentation." },
240 { "GotoIfTime", pbx_builtin_gotoiftime,
241 "Conditional goto on current time",
242 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
243 "If the current time matches the specified time, then branch to the specified\n"
244 "extension. Each of the elements may be specified either as '*' (for always)\n"
245 "or as a range. See the include syntax." },
247 { "Hangup", pbx_builtin_hangup,
248 "Unconditional hangup",
249 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
251 { "NoOp", pbx_builtin_noop,
253 " NoOp(): No-operation; Does nothing." },
255 { "Prefix", pbx_builtin_prefix,
256 "Prepend leading digits",
257 " Prefix(digits): Prepends the digit string specified by digits to the\n"
258 "channel's associated extension. For example, the number 1212 when prefixed\n"
259 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
260 "continue processing at the next priority for the *new* extension.\n"
261 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
262 "executed will be priority 4 of 5551212. If you switch into an extension\n"
263 "which has no first step, the PBX will treat it as though the user dialed an\n"
264 "invalid extension.\n" },
266 { "ResponseTimeout", pbx_builtin_rtimeout,
267 "Set maximum timeout awaiting response",
268 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
269 "falling through a series of priorities for a channel in which the user may\n"
270 "begin typing an extension. If the user does not type an extension in this\n"
271 "amount of time, control will pass to the 't' extension if it exists, and\n"
272 "if not the call would be terminated. Always returns 0.\n" },
274 { "Ringing", pbx_builtin_ringing,
275 "Indicate ringing tone",
276 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
277 "Always returns 0.\n" },
279 { "SayNumber", pbx_builtin_saynumber,
281 " SayNumber(digits): Says the passed number\n" },
283 { "SayDigits", pbx_builtin_saydigits,
285 " SayDigits(digits): Says the passed digits\n" },
287 { "SetAccount", pbx_builtin_setaccount,
289 " SetAccount([account]): Set the channel account code for billing\n"
290 "purposes. Always returns 0.\n" },
292 { "SetGlobalVar", pbx_builtin_setglobalvar,
293 "Set variable to value",
294 " Setvar(#n=value): Sets global variable n to value" },
296 { "SetLanguage", pbx_builtin_setlanguage,
297 "Sets user language",
298 " SetLanguage(language): Set the channel language to 'language'. This\n"
299 "information is used for the generation of numbers, and to select a natural\n"
300 "language file when available. For example, if language is set to 'fr' and\n"
301 "the file 'demo-congrats' is requested to be played, if the file 'demo-\n"
302 "congrats-fr' exists, then it will play that file, and if not will play the\n"
303 "normal 'demo-congrats'. Always returns 0.\n" },
305 { "SetVar", pbx_builtin_setvar,
306 "Set variable to value",
307 " Setvar(#n=value): Sets variable n to value" },
309 { "StripMSD", pbx_builtin_stripmsd,
310 "Strip leading digits",
311 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
312 "associated extension. For example, the number 5551212 when stripped with a\n"
313 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
314 "will continue processing at the next priority for the *new* extension.\n"
315 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
316 "executed will be priority 4 of 1212. If you switch into an extension which\n"
317 "has no first step, the PBX will treat it as though the user dialed an\n"
318 "invalid extension.\n" },
320 { "Suffix", pbx_builtin_suffix,
321 "Append trailing digits",
322 " Suffix(digits): Appends the digit string specified by digits to the\n"
323 "channel's associated extension. For example, the number 555 when suffixed\n"
324 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
325 "continue processing at the next priority for the *new* extension.\n"
326 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
327 "executed will be priority 4 of 5551212. If you switch into an extension\n"
328 "which has no first step, the PBX will treat it as though the user dialed an\n"
329 "invalid extension.\n" },
331 { "Wait", pbx_builtin_wait,
332 "Waits for some time",
333 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n" },
337 /* Lock for the application list */
338 static ast_mutex_t applock = AST_MUTEX_INITIALIZER;
339 static struct ast_context *contexts = NULL;
340 /* Lock for the ast_context list */
341 static ast_mutex_t conlock = AST_MUTEX_INITIALIZER;
342 static struct ast_app *apps = NULL;
344 /* Lock for switches */
345 static ast_mutex_t switchlock = AST_MUTEX_INITIALIZER;
346 struct ast_switch *switches = NULL;
348 /* Lock for extension state notifys */
349 static ast_mutex_t hintlock = AST_MUTEX_INITIALIZER;
350 static int stateid = 1;
351 struct ast_hint *hints = NULL;
352 struct ast_state_cb *statecbs = NULL;
354 int pbx_exec(struct ast_channel *c, /* Channel */
356 void *data, /* Data for execution */
357 int newstack) /* Force stack increment */
359 /* This function is special. It saves the stack so that no matter
360 how many times it is called, it returns to the same place */
362 int stack = c->stack;
363 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
364 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
365 /* Don't allow us to go over the max number of stacks we
367 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
370 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
371 /* Okay, here's where it gets weird. If newstack is non-zero,
372 then we increase the stack increment, but setjmp is not going
373 to return until longjmp is called -- when the application
374 exec'd is finished running. */
377 if (c->stack != stack + 1)
378 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
379 else if (c->app[c->stack])
380 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
385 ast_cdr_setapp(c->cdr, app->name, data);
388 res = execute(c, data);
391 /* Any application that returns, we longjmp back, just in case. */
392 if (c->stack != stack + 1)
393 ast_log(LOG_WARNING, "Stack is not at expected value\n");
394 longjmp(c->jmp[stack+1], res);
400 /* Go no deeper than this through includes (not counting loops) */
401 #define AST_PBX_MAX_STACK 64
403 #define HELPER_EXISTS 0
404 #define HELPER_SPAWN 1
405 #define HELPER_EXEC 2
406 #define HELPER_CANMATCH 3
407 #define HELPER_MATCHMORE 4
409 struct ast_app *pbx_findapp(char *app)
412 if (ast_mutex_lock(&applock)) {
413 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
418 if (!strcasecmp(tmp->name, app))
422 ast_mutex_unlock(&applock);
426 static struct ast_switch *pbx_findswitch(char *sw)
428 struct ast_switch *asw;
429 if (ast_mutex_lock(&switchlock)) {
430 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
435 if (!strcasecmp(asw->name, sw))
439 ast_mutex_unlock(&switchlock);
443 static inline int include_valid(struct ast_include *i)
452 /* If it's not the right month, return */
453 if (!(i->monthmask & (1 << tm.tm_mon))) {
457 /* If it's not that time of the month.... */
458 /* Warning, tm_mday has range 1..31! */
459 if (!(i->daymask & (1 << (tm.tm_mday-1))))
462 /* If it's not the right day of the week */
463 if (!(i->dowmask & (1 << tm.tm_wday)))
466 /* Sanity check the hour just to be safe */
467 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
468 ast_log(LOG_WARNING, "Insane time...\n");
472 /* Now the tough part, we calculate if it fits
473 in the right time based on min/hour */
474 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
477 /* If we got this far, then we're good */
481 static void pbx_destroy(struct ast_pbx *p)
486 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
487 /* All patterns begin with _ */\
488 if (pattern[0] != '_') \
490 /* Start optimistic */\
493 while(match && *data && *pattern && (*pattern != '/')) {\
494 switch(toupper(*pattern)) {\
501 where=strchr(pattern,']');\
503 border=(int)(where-pattern);\
504 if (!where || border > strlen(pattern)) {\
505 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
508 for (i=0; i<border; i++) {\
511 if (pattern[i+1]=='-') {\
512 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
519 if (res==1 || *data==pattern[i]) {\
528 if ((*data < '2') || (*data > '9'))\
532 if ((*data < '0') || (*data > '9'))\
536 if ((*data < '1') || (*data > '9'))\
544 /* Ignore these characters */\
548 if (*data != *pattern)\
556 int ast_extension_match(char *pattern, char *data)
559 /* If they're the same return */
560 if (!strcmp(pattern, data))
562 EXTENSION_MATCH_CORE(data,pattern,match);
563 /* Must be at the end of both */
564 if (*data || (*pattern && (*pattern != '/')))
569 static int extension_close(char *pattern, char *data, int needmore)
572 /* If "data" is longer, it can'be a subset of pattern unless
573 pattern is a pattern match */
574 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
577 if ((!strlen((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
578 (!needmore || (strlen(pattern) > strlen(data)))) {
581 EXTENSION_MATCH_CORE(data,pattern,match);
582 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
583 if (!needmore || *pattern) {
589 struct ast_context *ast_context_find(char *name)
591 struct ast_context *tmp;
592 ast_mutex_lock(&conlock);
596 if (!strcasecmp(name, tmp->name))
602 ast_mutex_unlock(&conlock);
606 #define STATUS_NO_CONTEXT 1
607 #define STATUS_NO_EXTENSION 2
608 #define STATUS_NO_PRIORITY 3
609 #define STATUS_SUCCESS 4
611 static int matchcid(char *cidpattern, char *callerid)
613 char tmp[AST_MAX_EXTENSION];
617 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
618 failing to get a number should count as a match, otherwise not */
621 if (strlen(cidpattern))
629 /* Copy original Caller*ID */
630 strncpy(tmp, callerid, sizeof(tmp)-1);
632 if (ast_callerid_parse(tmp, &name, &num))
636 ast_shrink_phone_number(num);
637 return ast_extension_match(cidpattern, num);
640 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)
643 struct ast_context *tmp;
644 struct ast_exten *e, *eroot;
645 struct ast_include *i;
647 struct ast_switch *asw;
648 /* Initialize status if appropriate */
650 *status = STATUS_NO_CONTEXT;
654 /* Check for stack overflow */
655 if (*stacklen >= AST_PBX_MAX_STACK) {
656 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
659 /* Check first to see if we've already been checked */
660 for (x=0;x<*stacklen;x++) {
661 if (!strcasecmp(incstack[x], context))
667 if (!strcmp(tmp->name, context)) {
668 if (*status < STATUS_NO_EXTENSION)
669 *status = STATUS_NO_EXTENSION;
672 /* Match extension */
673 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
674 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
675 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
676 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
678 if (*status < STATUS_NO_PRIORITY)
679 *status = STATUS_NO_PRIORITY;
682 if (e->priority == priority) {
683 *status = STATUS_SUCCESS;
691 /* Check alternative switches */
694 if ((asw = pbx_findswitch(sw->name))) {
695 if (action == HELPER_CANMATCH)
696 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
697 else if (action == HELPER_MATCHMORE)
698 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
700 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
708 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
712 /* Setup the stack */
713 incstack[*stacklen] = tmp->name;
715 /* Now try any includes we have in this context */
718 if (include_valid(i)) {
719 if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
732 static void pbx_substitute_variables_temp(struct ast_channel *c,const char *var,char **ret, char *workspace, int workspacelen)
735 char tmpvar[80] = "";
737 struct tm brokentime;
739 struct ast_var_t *variables;
740 char *name, *num; /* for callerid name + num variables */
741 struct varshead *headp=NULL;
745 /* Now we have the variable name on cp3 */
746 if ((first=strchr(var,':'))) {
747 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
748 first = strchr(tmpvar, ':');
750 first = tmpvar + strlen(tmpvar);
752 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
754 offset=atoi(first+1);
755 if ((second=strchr(first+1,':'))) {
757 offset2=atoi(second+1);
759 offset2=strlen(*ret)-offset;
760 if (abs(offset)>strlen(*ret)) {
764 offset=-strlen(*ret);
766 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
768 offset2=strlen(*ret)-offset;
770 offset2=strlen(*ret)+offset;
775 *ret+=strlen(*ret)+offset;
776 (*ret)[offset2] = '\0';
777 } else if (c && !strcmp(var, "CALLERIDNUM")) {
779 strncpy(workspace, c->callerid, workspacelen - 1);
780 ast_callerid_parse(workspace, &name, &num);
782 ast_shrink_phone_number(num);
786 } else if (c && !strcmp(var, "CALLERIDNAME")) {
788 strncpy(workspace, c->callerid, workspacelen - 1);
789 ast_callerid_parse(workspace, &name, &num);
794 } else if (c && !strcmp(var, "CALLERID")) {
796 strncpy(workspace, c->callerid, workspacelen - 1);
800 } else if (c && !strcmp(var, "HINT")) {
801 if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
805 } else if (c && !strcmp(var, "EXTEN")) {
806 strncpy(workspace, c->exten, workspacelen - 1);
808 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
809 /* XXX Remove me eventually */
810 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
813 if (offset > strlen(c->exten))
814 offset = strlen(c->exten);
815 strncpy(workspace, c->exten + offset, workspacelen - 1);
817 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
818 } else if (c && !strcmp(var, "RDNIS")) {
820 strncpy(workspace, c->rdnis, workspacelen - 1);
824 } else if (c && !strcmp(var, "CONTEXT")) {
825 strncpy(workspace, c->context, workspacelen - 1);
827 } else if (c && !strcmp(var, "PRIORITY")) {
828 snprintf(workspace, workspacelen, "%d", c->priority);
830 } else if (c && !strcmp(var, "CHANNEL")) {
831 strncpy(workspace, c->name, workspacelen - 1);
833 } else if (c && !strcmp(var, "EPOCH")) {
834 snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
836 } else if (c && !strcmp(var, "DATETIME")) {
838 localtime_r(&thistime, &brokentime);
839 snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
842 brokentime.tm_year+1900,
848 } else if (c && !strcmp(var, "UNIQUEID")) {
849 snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
852 AST_LIST_TRAVERSE(headp,variables,entries) {
854 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
856 if (strcasecmp(ast_var_name(variables),var)==0) {
857 *ret=ast_var_value(variables);
859 strncpy(workspace, *ret, workspacelen - 1);
867 AST_LIST_TRAVERSE(&globals,variables,entries) {
869 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
871 if (strcasecmp(ast_var_name(variables),var)==0) {
872 *ret=ast_var_value(variables);
874 strncpy(workspace, *ret, workspacelen - 1);
882 int len_env=strlen("ENV(");
883 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
885 strncpy(cp3, var, sizeof(cp3) - 1);
887 *ret=getenv(cp3+len_env);
889 strncpy(workspace, *ret, workspacelen - 1);
894 if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
897 if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
899 strncpy(cp3, var, sizeof(cp3) - 1);
900 cp3[len-len_len-1]='\0';
901 sprintf(workspace,"%d",strlen(cp3));
903 } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
908 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
911 const char *tmp, *whereweare;
914 char ltmp[256], var[256];
915 char *nextvar, *nextexp;
917 int pos, brackets, needsub, len;
919 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
922 while(strlen(whereweare) && count) {
923 /* Assume we're copying the whole remaining string */
924 pos = strlen(whereweare);
926 /* Look for a variable */
927 nextvar = strstr(whereweare, "${");
929 nextexp = strstr(whereweare, "$[");
931 if (nextvar && nextexp) {
932 if (nextvar < nextexp)
938 /* If there is one, we only go that far */
940 pos = nextvar - whereweare;
942 pos = nextexp - whereweare;
944 /* Can't copy more than 'count' bytes */
948 /* Copy that many bytes */
949 memcpy(cp2, whereweare, pos);
956 /* We have a variable. Find the start and end, and determine
957 if we are going to have to recursively call ourselves on the
959 vars = vare = nextvar + 2;
963 /* Find the end of it */
964 while(brackets && *vare) {
965 if ((vare[0] == '$') && (vare[1] == '{')) {
968 } else if (vare[0] == '}') {
970 } else if ((vare[0] == '$') && (vare[1] == '['))
975 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
976 len = vare - vars - 1;
978 /* Skip totally over variable name */
979 whereweare += ( len + 3);
981 /* Store variable name (and truncate) */
982 memset(var, 0, sizeof(var));
983 strncpy(var, vars, sizeof(var) - 1);
986 /* Substitute if necessary */
988 memset(ltmp, 0, sizeof(ltmp));
989 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
995 /* Retrieve variable value */
996 strcpy(workspace, "");
997 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
999 length = strlen(cp4);
1002 memcpy(cp2, cp4, length);
1007 } else if (nextexp) {
1008 /* We have an expression. Find the start and end, and determine
1009 if we are going to have to recursively call ourselves on the
1011 vars = vare = nextexp + 2;
1015 /* Find the end of it */
1016 while(brackets && *vare) {
1017 if ((vare[0] == '$') && (vare[1] == '[')) {
1020 } else if (vare[0] == ']') {
1022 } else if ((vare[0] == '$') && (vare[1] == '{'))
1027 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1028 len = vare - vars - 1;
1030 /* Skip totally over variable name */
1031 whereweare += ( len + 3);
1033 /* Store variable name (and truncate) */
1034 memset(var, 0, sizeof(var));
1035 strncpy(var, vars, sizeof(var) - 1);
1038 /* Substitute if necessary */
1040 memset(ltmp, 0, sizeof(ltmp));
1041 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1047 /* Evaluate expression */
1048 cp4 = ast_expr(vars);
1050 printf("Expression is '%s'\n", cp4);
1053 length = strlen(cp4);
1056 memcpy(cp2, cp4, length);
1067 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1069 memset(passdata, 0, datalen);
1071 /* No variables or expressions in e->data, so why scan it? */
1072 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1073 strncpy(passdata, e->data, datalen - 1);
1074 passdata[datalen-1] = '\0';
1078 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1081 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1083 struct ast_exten *e;
1084 struct ast_app *app;
1085 struct ast_switch *sw;
1090 char *incstack[AST_PBX_MAX_STACK];
1096 if (ast_mutex_lock(&conlock)) {
1097 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1098 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1103 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1106 case HELPER_CANMATCH:
1107 ast_mutex_unlock(&conlock);
1110 ast_mutex_unlock(&conlock);
1112 case HELPER_MATCHMORE:
1113 ast_mutex_unlock(&conlock);
1119 app = pbx_findapp(e->app);
1120 ast_mutex_unlock(&conlock);
1122 if (c->context != context)
1123 strncpy(c->context, context, sizeof(c->context-1));
1124 if (c->exten != exten)
1125 strncpy(c->exten, exten, sizeof(c->exten)-1);
1126 c->priority = priority;
1127 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1129 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1130 else if (option_verbose > 2)
1131 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1132 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1133 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1134 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1135 (newstack ? "in new stack" : "in same stack"));
1136 res = pbx_exec(c, app, passdata, newstack);
1139 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1143 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1147 case HELPER_CANMATCH:
1148 ast_mutex_unlock(&conlock);
1151 ast_mutex_unlock(&conlock);
1153 case HELPER_MATCHMORE:
1154 ast_mutex_unlock(&conlock);
1160 ast_mutex_unlock(&conlock);
1162 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1164 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1169 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1173 ast_mutex_unlock(&conlock);
1175 case STATUS_NO_CONTEXT:
1176 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1177 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1179 case STATUS_NO_EXTENSION:
1180 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1181 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1183 case STATUS_NO_PRIORITY:
1184 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1185 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1188 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1190 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1198 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1200 struct ast_exten *e;
1201 struct ast_switch *sw;
1204 char *incstack[AST_PBX_MAX_STACK];
1207 if (ast_mutex_lock(&conlock)) {
1208 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1211 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1212 ast_mutex_unlock(&conlock);
1216 static int ast_extension_state2(struct ast_exten *e)
1218 char hint[AST_MAX_EXTENSION] = "";
1221 int allunavailable = 1, allbusy = 1, allfree = 1;
1224 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1228 rest = strchr(cur, '&');
1234 res = ast_device_state(cur);
1236 case AST_DEVICE_NOT_INUSE:
1240 case AST_DEVICE_INUSE:
1241 return AST_EXTENSION_INUSE;
1242 case AST_DEVICE_BUSY:
1247 case AST_DEVICE_UNAVAILABLE:
1248 case AST_DEVICE_INVALID:
1261 return AST_EXTENSION_NOT_INUSE;
1263 return AST_EXTENSION_BUSY;
1265 return AST_EXTENSION_UNAVAILABLE;
1267 return AST_EXTENSION_INUSE;
1269 return AST_EXTENSION_NOT_INUSE;
1273 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1275 struct ast_exten *e;
1277 e = ast_hint_extension(c, context, exten);
1281 return ast_extension_state2(e);
1284 int ast_device_state_changed(const char *fmt, ...)
1286 struct ast_hint *list;
1287 struct ast_state_cb *cblist;
1288 char hint[AST_MAX_EXTENSION];
1289 char device[AST_MAX_EXTENSION];
1296 vsnprintf(device, sizeof(device)-1, fmt, ap);
1299 rest = strchr(device, '-');
1304 ast_mutex_lock(&hintlock);
1310 strcpy(hint, ast_get_extension_app(list->exten));
1313 rest = strchr(cur, '&');
1319 if (!strcmp(cur, device)) {
1320 // Found extension execute callbacks
1321 state = ast_extension_state2(list->exten);
1322 if ((state != -1) && (state != list->laststate)) {
1323 // For general callbacks
1326 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1327 cblist = cblist->next;
1330 // For extension callbacks
1331 cblist = list->callbacks;
1333 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1334 cblist = cblist->next;
1337 list->laststate = state;
1347 ast_mutex_unlock(&hintlock);
1351 int ast_extension_state_add(char *context, char *exten,
1352 ast_state_cb_type callback, void *data)
1354 struct ast_hint *list;
1355 struct ast_state_cb *cblist;
1356 struct ast_exten *e;
1358 /* No context and extension add callback to statecbs list */
1359 if (!context && !exten) {
1360 ast_mutex_lock(&hintlock);
1364 if (cblist->callback == callback) {
1365 cblist->data = data;
1366 ast_mutex_unlock(&hintlock);
1369 cblist = cblist->next;
1372 /* Now inserts the callback */
1373 cblist = malloc(sizeof(struct ast_state_cb));
1375 ast_mutex_unlock(&hintlock);
1378 memset(cblist, 0, sizeof(struct ast_state_cb));
1380 cblist->callback = callback;
1381 cblist->data = data;
1383 cblist->next = statecbs;
1386 ast_mutex_unlock(&hintlock);
1390 if (!context || !exten)
1393 /* This callback type is for only one hint */
1394 e = ast_hint_extension(NULL, context, exten);
1399 ast_mutex_lock(&hintlock);
1403 if (list->exten == e)
1409 ast_mutex_unlock(&hintlock);
1413 /* Now inserts the callback */
1414 cblist = malloc(sizeof(struct ast_state_cb));
1416 ast_mutex_unlock(&hintlock);
1419 memset(cblist, 0, sizeof(struct ast_state_cb));
1420 cblist->id = stateid++;
1421 cblist->callback = callback;
1422 cblist->data = data;
1424 cblist->next = list->callbacks;
1425 list->callbacks = cblist;
1427 ast_mutex_unlock(&hintlock);
1431 int ast_extension_state_del(int id, ast_state_cb_type callback)
1433 struct ast_hint *list;
1434 struct ast_state_cb *cblist, *cbprev;
1436 if (!id && !callback)
1439 ast_mutex_lock(&hintlock);
1441 /* id is zero is a callback without extension */
1446 if (cblist->callback == callback) {
1448 statecbs = cblist->next;
1450 cbprev->next = cblist->next;
1454 ast_mutex_unlock(&hintlock);
1458 cblist = cblist->next;
1461 ast_mutex_lock(&hintlock);
1465 /* id greater zero is a callback with extension */
1468 cblist = list->callbacks;
1471 if (cblist->id==id) {
1473 list->callbacks = cblist->next;
1475 cbprev->next = cblist->next;
1479 ast_mutex_unlock(&hintlock);
1483 cblist = cblist->next;
1488 ast_mutex_unlock(&hintlock);
1492 static int ast_add_hint(struct ast_exten *e)
1494 struct ast_hint *list;
1498 ast_mutex_lock(&hintlock);
1501 /* Search if hint exists, do nothing */
1503 if (list->exten == e) {
1504 ast_mutex_unlock(&hintlock);
1510 list = malloc(sizeof(struct ast_hint));
1512 ast_mutex_unlock(&hintlock);
1515 /* Initialize and insert new item */
1516 memset(list, 0, sizeof(struct ast_hint));
1518 list->laststate = ast_extension_state2(e);
1522 ast_mutex_unlock(&hintlock);
1526 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1528 struct ast_hint *list;
1530 ast_mutex_lock(&hintlock);
1535 if (list->exten == oe) {
1537 ast_mutex_unlock(&hintlock);
1542 ast_mutex_unlock(&hintlock);
1547 static int ast_remove_hint(struct ast_exten *e)
1549 /* Cleanup the Notifys if hint is removed */
1550 struct ast_hint *list, *prev = NULL;
1551 struct ast_state_cb *cblist, *cbprev;
1556 ast_mutex_lock(&hintlock);
1560 if (list->exten==e) {
1562 cblist = list->callbacks;
1564 /* Notify with -1 and remove all callbacks */
1566 cblist = cblist->next;
1567 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1570 list->callbacks = NULL;
1575 prev->next = list->next;
1579 ast_mutex_unlock(&hintlock);
1587 ast_mutex_unlock(&hintlock);
1592 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1594 struct ast_exten *e;
1595 e = ast_hint_extension(c, context, exten);
1597 strncpy(hint, ast_get_extension_app(e), maxlen);
1603 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1605 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1608 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1610 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1613 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1615 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1618 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1620 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1623 int ast_pbx_run(struct ast_channel *c)
1632 /* A little initial setup here */
1634 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1635 c->pbx = malloc(sizeof(struct ast_pbx));
1637 ast_log(LOG_WARNING, "Out of memory\n");
1642 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1644 c->cdr = ast_cdr_alloc();
1646 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1650 ast_cdr_init(c->cdr, c);
1653 memset(c->pbx, 0, sizeof(struct ast_pbx));
1654 /* Set reasonable defaults */
1655 c->pbx->rtimeout = 10;
1656 c->pbx->dtimeout = 5;
1658 /* Start by trying whatever the channel is set to */
1659 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1660 /* JK02: If not successfull fall back to 's' */
1661 strncpy(c->exten, "s", sizeof(c->exten)-1);
1662 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1663 /* JK02: And finally back to default if everything else failed */
1664 strncpy(c->context, "default", sizeof(c->context)-1);
1669 ast_cdr_start(c->cdr);
1673 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1674 memset(exten, 0, sizeof(exten));
1675 manager_event(EVENT_FLAG_CALL, "Newexten",
1681 c->name, c->context, c->exten, c->priority, c->uniqueid);
1682 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1683 /* Something bad happened, or a hangup has been requested. */
1684 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1685 (res == '*') || (res == '#')) {
1686 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1687 memset(exten, 0, sizeof(exten));
1689 exten[pos++] = digit = res;
1693 case AST_PBX_KEEPALIVE:
1695 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1696 else if (option_verbose > 1)
1697 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1702 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1703 else if (option_verbose > 1)
1704 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1705 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1710 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1716 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1717 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1718 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1719 c->whentohangup = 0;
1721 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1722 } else if (c->_softhangup) {
1723 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1724 c->exten, c->priority);
1730 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1731 /* It's not a valid extension anymore */
1732 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1733 if (option_verbose > 2)
1734 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1735 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1736 strncpy(c->exten, "i", sizeof(c->exten)-1);
1739 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1740 c->name, c->exten, c->context);
1743 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1744 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1747 /* Done, wait for an extension */
1749 waittime = c->pbx->dtimeout;
1751 waittime = c->pbx->rtimeout;
1752 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1753 /* As long as we're willing to wait, and as long as it's not defined,
1754 keep reading digits until we can't possibly get a right answer anymore. */
1755 digit = ast_waitfordigit(c, waittime * 1000);
1756 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1763 /* Error, maybe a hangup */
1765 exten[pos++] = digit;
1766 waittime = c->pbx->dtimeout;
1769 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1770 /* Prepare the next cycle */
1771 strncpy(c->exten, exten, sizeof(c->exten)-1);
1774 /* No such extension */
1775 if (strlen(exten)) {
1776 /* An invalid extension */
1777 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1778 if (option_verbose > 2)
1779 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1780 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1781 strncpy(c->exten, "i", sizeof(c->exten)-1);
1784 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1788 /* A simple timeout */
1789 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1790 if (option_verbose > 2)
1791 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1792 strncpy(c->exten, "t", sizeof(c->exten)-1);
1795 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1801 if (option_verbose > 2)
1802 ast_verbose(VERBOSE_PREFIX_2,"CDR updated on %s\n",c->name);
1808 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1810 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1811 strcpy(c->exten, "h");
1813 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1814 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1815 /* Something bad happened, or a hangup has been requested. */
1817 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1818 else if (option_verbose > 1)
1819 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1826 pbx_destroy(c->pbx);
1828 if (res != AST_PBX_KEEPALIVE)
1833 static void *pbx_thread(void *data)
1835 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1836 answer this channel and get it going. The setjmp stuff is fairly
1837 confusing, but necessary to get smooth transitions between
1838 the execution of different applications (without the use of
1839 additional threads) */
1840 struct ast_channel *c = data;
1846 int ast_pbx_start(struct ast_channel *c)
1849 pthread_attr_t attr;
1851 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1855 /* Start a new thread, and get something handling this channel. */
1856 pthread_attr_init(&attr);
1857 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1858 if (pthread_create(&t, &attr, pbx_thread, c)) {
1859 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1866 * This function locks contexts list by &conlist, search for the rigt context
1867 * structure, leave context list locked and call ast_context_remove_include2
1868 * which removes include, unlock contexts list and return ...
1870 int ast_context_remove_include(char *context, char *include, char *registrar)
1872 struct ast_context *c;
1874 if (ast_lock_contexts()) return -1;
1876 /* walk contexts and search for the right one ...*/
1877 c = ast_walk_contexts(NULL);
1879 /* we found one ... */
1880 if (!strcmp(ast_get_context_name(c), context)) {
1882 /* remove include from this context ... */
1883 ret = ast_context_remove_include2(c, include, registrar);
1885 ast_unlock_contexts();
1887 /* ... return results */
1890 c = ast_walk_contexts(c);
1893 /* we can't find the right one context */
1894 ast_unlock_contexts();
1899 * When we call this function, &conlock lock must be locked, because when
1900 * we giving *con argument, some process can remove/change this context
1901 * and after that there can be segfault.
1903 * This function locks given context, removes include, unlock context and
1906 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1908 struct ast_include *i, *pi = NULL;
1910 if (ast_mutex_lock(&con->lock)) return -1;
1915 /* find our include */
1916 if (!strcmp(i->name, include) &&
1917 (!strcmp(i->registrar, registrar) || !registrar)) {
1918 /* remove from list */
1922 con->includes = i->next;
1923 /* free include and return */
1925 ast_mutex_unlock(&con->lock);
1932 /* we can't find the right include */
1933 ast_mutex_unlock(&con->lock);
1938 * This function locks contexts list by &conlist, search for the rigt context
1939 * structure, leave context list locked and call ast_context_remove_switch2
1940 * which removes switch, unlock contexts list and return ...
1942 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1944 struct ast_context *c;
1946 if (ast_lock_contexts()) return -1;
1948 /* walk contexts and search for the right one ...*/
1949 c = ast_walk_contexts(NULL);
1951 /* we found one ... */
1952 if (!strcmp(ast_get_context_name(c), context)) {
1954 /* remove switch from this context ... */
1955 ret = ast_context_remove_switch2(c, sw, data, registrar);
1957 ast_unlock_contexts();
1959 /* ... return results */
1962 c = ast_walk_contexts(c);
1965 /* we can't find the right one context */
1966 ast_unlock_contexts();
1971 * When we call this function, &conlock lock must be locked, because when
1972 * we giving *con argument, some process can remove/change this context
1973 * and after that there can be segfault.
1975 * This function locks given context, removes switch, unlock context and
1978 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
1980 struct ast_sw *i, *pi = NULL;
1982 if (ast_mutex_lock(&con->lock)) return -1;
1987 /* find our switch */
1988 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
1989 (!strcmp(i->registrar, registrar) || !registrar)) {
1990 /* remove from list */
1994 con->alts = i->next;
1995 /* free switch and return */
1997 ast_mutex_unlock(&con->lock);
2004 /* we can't find the right switch */
2005 ast_mutex_unlock(&con->lock);
2010 * This functions lock contexts list, search for the right context,
2011 * call ast_context_remove_extension2, unlock contexts list and return.
2012 * In this function we are using
2014 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2016 struct ast_context *c;
2018 if (ast_lock_contexts()) return -1;
2020 /* walk contexts ... */
2021 c = ast_walk_contexts(NULL);
2023 /* ... search for the right one ... */
2024 if (!strcmp(ast_get_context_name(c), context)) {
2025 /* ... remove extension ... */
2026 int ret = ast_context_remove_extension2(c, extension, priority,
2028 /* ... unlock contexts list and return */
2029 ast_unlock_contexts();
2032 c = ast_walk_contexts(c);
2035 /* we can't find the right context */
2036 ast_unlock_contexts();
2041 * When do you want to call this function, make sure that &conlock is locked,
2042 * because some process can handle with your *con context before you lock
2045 * This functionc locks given context, search for the right extension and
2046 * fires out all peer in this extensions with given priority. If priority
2047 * is set to 0, all peers are removed. After that, unlock context and
2050 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2052 struct ast_exten *exten, *prev_exten = NULL;
2054 if (ast_mutex_lock(&con->lock)) return -1;
2056 /* go through all extensions in context and search the right one ... */
2060 /* look for right extension */
2061 if (!strcmp(exten->exten, extension) &&
2062 (!strcmp(exten->registrar, registrar) || !registrar)) {
2063 struct ast_exten *peer;
2065 /* should we free all peers in this extension? (priority == 0)? */
2066 if (priority == 0) {
2067 /* remove this extension from context list */
2069 prev_exten->next = exten->next;
2071 con->root = exten->next;
2073 /* fire out all peers */
2078 if (!peer->priority==PRIORITY_HINT)
2079 ast_remove_hint(peer);
2081 peer->datad(peer->data);
2087 ast_mutex_unlock(&con->lock);
2090 /* remove only extension with exten->priority == priority */
2091 struct ast_exten *previous_peer = NULL;
2095 /* is this our extension? */
2096 if (peer->priority == priority &&
2097 (!strcmp(peer->registrar, registrar) || !registrar)) {
2098 /* we are first priority extension? */
2099 if (!previous_peer) {
2100 /* exists previous extension here? */
2102 /* yes, so we must change next pointer in
2103 * previous connection to next peer
2106 prev_exten->next = peer->peer;
2107 peer->peer->next = exten->next;
2109 prev_exten->next = exten->next;
2111 /* no previous extension, we are first
2112 * extension, so change con->root ...
2115 con->root = peer->peer;
2117 con->root = exten->next;
2120 /* we are not first priority in extension */
2121 previous_peer->peer = peer->peer;
2124 /* now, free whole priority extension */
2125 if (peer->priority==PRIORITY_HINT)
2126 ast_remove_hint(peer);
2127 peer->datad(peer->data);
2130 ast_mutex_unlock(&con->lock);
2133 /* this is not right extension, skip to next peer */
2134 previous_peer = peer;
2139 ast_mutex_unlock(&con->lock);
2145 exten = exten->next;
2148 /* we can't find right extension */
2149 ast_mutex_unlock(&con->lock);
2154 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2156 struct ast_app *tmp, *prev, *cur;
2158 if (ast_mutex_lock(&applock)) {
2159 ast_log(LOG_ERROR, "Unable to lock application list\n");
2164 if (!strcasecmp(app, tmp->name)) {
2165 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2166 ast_mutex_unlock(&applock);
2171 tmp = malloc(sizeof(struct ast_app));
2173 memset(tmp, 0, sizeof(struct ast_app));
2174 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2175 tmp->execute = execute;
2176 tmp->synopsis = synopsis;
2177 tmp->description = description;
2178 /* Store in alphabetical order */
2182 if (strcasecmp(tmp->name, cur->name) < 0)
2188 tmp->next = prev->next;
2195 ast_log(LOG_WARNING, "Out of memory\n");
2196 ast_mutex_unlock(&applock);
2199 if (option_verbose > 1)
2200 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2201 ast_mutex_unlock(&applock);
2205 int ast_register_switch(struct ast_switch *sw)
2207 struct ast_switch *tmp, *prev=NULL;
2208 if (ast_mutex_lock(&switchlock)) {
2209 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2214 if (!strcasecmp(tmp->name, sw->name))
2220 ast_mutex_unlock(&switchlock);
2221 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2229 ast_mutex_unlock(&switchlock);
2233 void ast_unregister_switch(struct ast_switch *sw)
2235 struct ast_switch *tmp, *prev=NULL;
2236 if (ast_mutex_lock(&switchlock)) {
2237 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2244 prev->next = tmp->next;
2246 switches = tmp->next;
2253 ast_mutex_unlock(&switchlock);
2257 * Help for CLI commands ...
2259 static char show_application_help[] =
2260 "Usage: show application <application> [<application> [<application> [...]]]\n"
2261 " Describes a particular application.\n";
2263 static char show_applications_help[] =
2264 "Usage: show applications\n"
2265 " List applications which are currently available.\n";
2267 static char show_dialplan_help[] =
2268 "Usage: show dialplan [exten@][context]\n"
2271 static char show_switches_help[] =
2272 "Usage: show switches\n"
2273 " Show registered switches\n";
2276 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2281 * 'show application' CLI command implementation functions ...
2285 * There is a possibility to show informations about more than one
2286 * application at one time. You can type 'show application Dial Echo' and
2287 * you will see informations about these two applications ...
2289 static char *complete_show_application(char *line, char *word,
2295 /* try to lock applications list ... */
2296 if (ast_mutex_lock(&applock)) {
2297 ast_log(LOG_ERROR, "Unable to lock application list\n");
2301 /* ... walk all applications ... */
2304 /* ... check if word matches this application ... */
2305 if (!strncasecmp(word, a->name, strlen(word))) {
2306 /* ... if this is right app serve it ... */
2307 if (++which > state) {
2308 char *ret = strdup(a->name);
2309 ast_mutex_unlock(&applock);
2316 /* no application match */
2317 ast_mutex_unlock(&applock);
2321 static int handle_show_application(int fd, int argc, char *argv[])
2325 int app, no_registered_app = 1;
2327 if (argc < 3) return RESULT_SHOWUSAGE;
2329 /* try to lock applications list ... */
2330 if (ast_mutex_lock(&applock)) {
2331 ast_log(LOG_ERROR, "Unable to lock application list\n");
2335 /* ... go through all applications ... */
2338 /* ... compare this application name with all arguments given
2339 * to 'show application' command ... */
2340 for (app = 2; app < argc; app++) {
2341 if (!strcasecmp(a->name, argv[app])) {
2342 no_registered_app = 0;
2344 /* ... one of our applications, show info ...*/
2345 snprintf(buf, sizeof(buf),
2346 "\n -= Info about application '%s' =- \n\n"
2347 "[Synopsis]:\n %s\n\n"
2348 "[Description]:\n%s\n",
2350 a->synopsis ? a->synopsis : "Not available",
2351 a->description ? a-> description : "Not available");
2358 ast_mutex_unlock(&applock);
2360 /* we found at least one app? no? */
2361 if (no_registered_app) {
2362 ast_cli(fd, "Your application(s) is (are) not registered\n");
2363 return RESULT_FAILURE;
2366 return RESULT_SUCCESS;
2369 static int handle_show_switches(int fd, int argc, char *argv[])
2371 struct ast_switch *sw;
2373 ast_cli(fd, "There are no registered alternative switches\n");
2374 return RESULT_SUCCESS;
2376 /* ... we have applications ... */
2377 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2378 if (ast_mutex_lock(&switchlock)) {
2379 ast_log(LOG_ERROR, "Unable to lock switches\n");
2384 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2387 ast_mutex_unlock(&switchlock);
2388 return RESULT_SUCCESS;
2392 * 'show applications' CLI command implementation functions ...
2394 static int handle_show_applications(int fd, int argc, char *argv[])
2398 /* try to lock applications list ... */
2399 if (ast_mutex_lock(&applock)) {
2400 ast_log(LOG_ERROR, "Unable to lock application list\n");
2404 /* ... go to first application ... */
2407 /* ... have we got at least one application (first)? no? */
2409 ast_cli(fd, "There is no registered applications\n");
2410 ast_mutex_unlock(&applock);
2414 /* ... we have applications ... */
2415 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2417 /* ... go through all applications ... */
2419 /* ... show informations about applications ... */
2420 ast_cli(fd," %15s: %s\n",
2422 a->synopsis ? a->synopsis : "<Synopsis not available>");
2426 /* ... unlock and return */
2427 ast_mutex_unlock(&applock);
2429 return RESULT_SUCCESS;
2433 * 'show dialplan' CLI command implementation functions ...
2435 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2438 struct ast_context *c;
2441 /* we are do completion of [exten@]context on second position only */
2442 if (pos != 2) return NULL;
2444 /* try to lock contexts list ... */
2445 if (ast_lock_contexts()) {
2446 ast_log(LOG_ERROR, "Unable to lock context list\n");
2450 /* ... walk through all contexts ... */
2451 c = ast_walk_contexts(NULL);
2453 /* ... word matches context name? yes? ... */
2454 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2455 /* ... for serve? ... */
2456 if (++which > state) {
2457 /* ... yes, serve this context name ... */
2458 char *ret = strdup(ast_get_context_name(c));
2459 ast_unlock_contexts();
2463 c = ast_walk_contexts(c);
2466 /* ... unlock and return */
2467 ast_unlock_contexts();
2471 static int handle_show_dialplan(int fd, int argc, char *argv[])
2473 struct ast_context *c;
2474 char *exten = NULL, *context = NULL;
2475 int context_existence = 0, extension_existence = 0;
2477 if (argc != 3 && argc != 2) return -1;
2479 /* we obtain [exten@]context? if yes, split them ... */
2481 char *splitter = argv[2];
2482 /* is there a '@' character? */
2483 if (strchr(argv[2], '@')) {
2484 /* yes, split into exten & context ... */
2485 exten = strsep(&splitter, "@");
2488 /* check for length and change to NULL if !strlen() */
2489 if (!strlen(exten)) exten = NULL;
2490 if (!strlen(context)) context = NULL;
2493 /* no '@' char, only context given */
2495 if (!strlen(context)) context = NULL;
2499 /* try to lock contexts */
2500 if (ast_lock_contexts()) {
2501 ast_cli(LOG_WARNING, "Failed to lock contexts list\n");
2502 return RESULT_FAILURE;
2505 /* walk all contexts ... */
2506 c = ast_walk_contexts(NULL);
2508 /* show this context? */
2510 !strcmp(ast_get_context_name(c), context)) {
2511 context_existence = 1;
2513 /* try to lock context before walking in ... */
2514 if (!ast_lock_context(c)) {
2515 struct ast_exten *e;
2516 struct ast_include *i;
2517 struct ast_ignorepat *ip;
2519 char buf[256], buf2[256];
2520 int context_info_printed = 0;
2522 /* are we looking for exten too? if yes, we print context
2523 * if we our extension only
2526 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2527 ast_get_context_name(c), ast_get_context_registrar(c));
2528 context_info_printed = 1;
2531 /* walk extensions ... */
2532 e = ast_walk_context_extensions(c, NULL);
2534 struct ast_exten *p;
2536 /* looking for extension? is this our extension? */
2538 strcmp(ast_get_extension_name(e), exten))
2540 /* we are looking for extension and it's not our
2541 * extension, so skip to next extension */
2542 e = ast_walk_context_extensions(c, e);
2546 extension_existence = 1;
2548 /* may we print context info? */
2549 if (!context_info_printed) {
2550 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2551 ast_get_context_name(c),
2552 ast_get_context_registrar(c));
2553 context_info_printed = 1;
2556 /* write extension name and first peer */
2557 bzero(buf, sizeof(buf));
2558 snprintf(buf, sizeof(buf), "'%s' =>",
2559 ast_get_extension_name(e));
2561 snprintf(buf2, sizeof(buf2),
2563 ast_get_extension_priority(e),
2564 ast_get_extension_app(e),
2565 (char *)ast_get_extension_app_data(e));
2567 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2568 ast_get_extension_registrar(e));
2570 /* walk next extension peers */
2571 p = ast_walk_extension_priorities(e, e);
2573 bzero((void *)buf2, sizeof(buf2));
2575 snprintf(buf2, sizeof(buf2),
2577 ast_get_extension_priority(p),
2578 ast_get_extension_app(p),
2579 (char *)ast_get_extension_app_data(p));
2581 ast_cli(fd," %-17s %-45s [%s]\n",
2583 ast_get_extension_registrar(p));
2585 p = ast_walk_extension_priorities(e, p);
2587 e = ast_walk_context_extensions(c, e);
2590 /* include & ignorepat we all printing if we are not
2591 * looking for exact extension
2594 if (ast_walk_context_extensions(c, NULL))
2597 /* walk included and write info ... */
2598 i = ast_walk_context_includes(c, NULL);
2600 bzero(buf, sizeof(buf));
2601 snprintf(buf, sizeof(buf), "'%s'",
2602 ast_get_include_name(i));
2603 ast_cli(fd, " Include => %-45s [%s]\n",
2604 buf, ast_get_include_registrar(i));
2605 i = ast_walk_context_includes(c, i);
2608 /* walk ignore patterns and write info ... */
2609 ip = ast_walk_context_ignorepats(c, NULL);
2611 bzero(buf, sizeof(buf));
2612 snprintf(buf, sizeof(buf), "'%s'",
2613 ast_get_ignorepat_name(ip));
2614 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2615 buf, ast_get_ignorepat_registrar(ip));
2616 ip = ast_walk_context_ignorepats(c, ip);
2618 sw = ast_walk_context_switches(c, NULL);
2620 bzero(buf, sizeof(buf));
2621 snprintf(buf, sizeof(buf), "'%s/%s'",
2622 ast_get_switch_name(sw),
2623 ast_get_switch_data(sw));
2624 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2625 buf, ast_get_switch_registrar(sw));
2626 sw = ast_walk_context_switches(c, sw);
2630 ast_unlock_context(c);
2632 /* if we print something in context, make an empty line */
2633 if (context_info_printed) ast_cli(fd, "\n");
2636 c = ast_walk_contexts(c);
2638 ast_unlock_contexts();
2640 /* check for input failure and throw some error messages */
2641 if (context && !context_existence) {
2642 ast_cli(fd, "There is no existence of '%s' context\n",
2644 return RESULT_FAILURE;
2647 if (exten && !extension_existence) {
2649 ast_cli(fd, "There is no existence of %s@%s extension\n",
2653 "There is no existence of '%s' extension in all contexts\n",
2655 return RESULT_FAILURE;
2659 return RESULT_SUCCESS;
2663 * CLI entries for upper commands ...
2665 static struct ast_cli_entry show_applications_cli =
2666 { { "show", "applications", NULL },
2667 handle_show_applications, "Shows registered applications",
2668 show_applications_help };
2670 static struct ast_cli_entry show_application_cli =
2671 { { "show", "application", NULL },
2672 handle_show_application, "Describe a specific application",
2673 show_application_help, complete_show_application };
2675 static struct ast_cli_entry show_dialplan_cli =
2676 { { "show", "dialplan", NULL },
2677 handle_show_dialplan, "Show dialplan",
2678 show_dialplan_help, complete_show_dialplan_context };
2680 static struct ast_cli_entry show_switches_cli =
2681 { { "show", "switches", NULL },
2682 handle_show_switches, "Show alternative switches",
2683 show_switches_help, NULL };
2685 int ast_unregister_application(char *app) {
2686 struct ast_app *tmp, *tmpl = NULL;
2687 if (ast_mutex_lock(&applock)) {
2688 ast_log(LOG_ERROR, "Unable to lock application list\n");
2693 if (!strcasecmp(app, tmp->name)) {
2695 tmpl->next = tmp->next;
2698 if (option_verbose > 1)
2699 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2700 ast_mutex_unlock(&applock);
2706 ast_mutex_unlock(&applock);
2710 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2712 struct ast_context *tmp, **local_contexts;
2714 local_contexts = &contexts;
2715 ast_mutex_lock(&conlock);
2717 local_contexts = extcontexts;
2719 tmp = *local_contexts;
2721 if (!strcasecmp(tmp->name, name)) {
2722 ast_mutex_unlock(&conlock);
2723 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2725 ast_mutex_unlock(&conlock);
2730 tmp = malloc(sizeof(struct ast_context));
2732 memset(tmp, 0, sizeof(struct ast_context));
2733 ast_mutex_init(&tmp->lock);
2734 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2736 tmp->registrar = registrar;
2737 tmp->next = *local_contexts;
2738 tmp->includes = NULL;
2739 tmp->ignorepats = NULL;
2740 *local_contexts = tmp;
2742 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2743 else if (option_verbose > 2)
2744 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2746 ast_log(LOG_WARNING, "Out of memory\n");
2749 ast_mutex_unlock(&conlock);
2753 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
2755 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2756 struct ast_context *tmp, *lasttmp = NULL;
2758 ast_mutex_lock(&conlock);
2760 __ast_context_destroy(NULL,registrar,0);
2767 __ast_context_destroy(tmp,tmp->registrar,0);
2773 lasttmp->next = contexts;
2774 contexts = *extcontexts;
2775 *extcontexts = NULL;
2777 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2778 ast_mutex_unlock(&conlock);
2784 * EBUSY - can't lock
2785 * ENOENT - no existence of context
2787 int ast_context_add_include(char *context, char *include, char *registrar)
2789 struct ast_context *c;
2791 if (ast_lock_contexts()) {
2796 /* walk contexts ... */
2797 c = ast_walk_contexts(NULL);
2799 /* ... search for the right one ... */
2800 if (!strcmp(ast_get_context_name(c), context)) {
2801 int ret = ast_context_add_include2(c, include, registrar);
2802 /* ... unlock contexts list and return */
2803 ast_unlock_contexts();
2806 c = ast_walk_contexts(c);
2809 /* we can't find the right context */
2810 ast_unlock_contexts();
2818 while(*c && (*c != '|')) c++; \
2819 if (*c) { *c = '\0'; c++; } else c = NULL; \
2822 static void get_timerange(struct ast_include *i, char *times)
2830 //start disabling all times, fill the fields with 0's, as they may contain garbage
2831 memset(i->minmask, 0, sizeof(i->minmask));
2833 /* Star is all times */
2834 if (!strlen(times) || !strcmp(times, "*")) {
2836 i->minmask[x] = (1 << 30) - 1;
2839 /* Otherwise expect a range */
2840 e = strchr(times, '-');
2842 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2847 while(*e && !isdigit(*e)) e++;
2849 ast_log(LOG_WARNING, "Invalid time range. Assuming no time.\n");
2852 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2853 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", times);
2856 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2857 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", e);
2860 s1 = s1 * 30 + s2/2;
2861 if ((s1 < 0) || (s1 >= 24*30)) {
2862 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2865 e1 = e1 * 30 + e2/2;
2866 if ((e1 < 0) || (e2 >= 24*30)) {
2867 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2870 /* Go through the time and enable each appropriate bit */
2871 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2872 i->minmask[x/30] |= (1 << (x % 30));
2874 /* Do the last one */
2875 i->minmask[x/30] |= (1 << (x % 30));
2880 static char *days[] =
2891 static unsigned int get_dow(char *dow)
2894 /* The following line is coincidence, really! */
2897 /* Check for all days */
2898 if (!strlen(dow) || !strcmp(dow, "*"))
2899 return (1 << 7) - 1;
2900 /* Get start and ending days */
2901 c = strchr(dow, '-');
2907 /* Find the start */
2909 while((s < 7) && strcasecmp(dow, days[s])) s++;
2911 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2916 while((e < 7) && strcasecmp(c, days[e])) e++;
2918 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2924 for (x=s;x!=e;x = (x + 1) % 7) {
2932 static unsigned int get_day(char *day)
2935 /* The following line is coincidence, really! */
2938 /* Check for all days */
2939 if (!strlen(day) || !strcmp(day, "*")) {
2940 mask = (1 << 30) + ((1 << 30) - 1);
2943 /* Get start and ending days */
2944 c = strchr(day, '-');
2949 /* Find the start */
2950 if (sscanf(day, "%d", &s) != 1) {
2951 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2954 if ((s < 1) || (s > 31)) {
2955 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2960 if (sscanf(c, "%d", &e) != 1) {
2961 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2964 if ((e < 1) || (e > 31)) {
2965 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2972 for (x=s;x!=e;x = (x + 1) % 31) {
2979 static char *months[] =
2995 static unsigned int get_month(char *mon)
2998 /* The following line is coincidence, really! */
3001 /* Check for all days */
3002 if (!strlen(mon) || !strcmp(mon, "*"))
3003 return (1 << 12) - 1;
3004 /* Get start and ending days */
3005 c = strchr(mon, '-');
3010 /* Find the start */
3012 while((s < 12) && strcasecmp(mon, months[s])) s++;
3014 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3019 while((e < 12) && strcasecmp(mon, months[e])) e++;
3021 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3027 for (x=s;x!=e;x = (x + 1) % 12) {
3035 static void build_timing(struct ast_include *i, char *info)
3038 /* Check for empty just in case */
3042 /* Assume everything except time */
3043 i->monthmask = (1 << 12) - 1;
3044 i->daymask = (1 << 30) - 1 + (1 << 30);
3045 i->dowmask = (1 << 7) - 1;
3046 /* Avoid using str tok */
3048 /* Info has the time range, start with that */
3049 get_timerange(i, info);
3054 /* Now check for day of week */
3055 i->dowmask = get_dow(info);
3061 /* Now check for the day of the month */
3062 i->daymask = get_day(info);
3067 /* And finally go for the month */
3068 i->monthmask = get_month(info);
3073 * ENOMEM - out of memory
3074 * EBUSY - can't lock
3075 * EEXIST - already included
3076 * EINVAL - there is no existence of context for inclusion
3078 int ast_context_add_include2(struct ast_context *con, char *value,
3081 struct ast_include *new_include;
3083 struct ast_include *i, *il = NULL; /* include, include_last */
3085 /* allocate new include structure ... */
3086 if (!(new_include = malloc(sizeof(struct ast_include)))) {
3087 ast_log(LOG_WARNING, "Out of memory\n");
3092 /* ... fill in this structure ... */
3093 memset(new_include, 0, sizeof(struct ast_include));
3094 strncpy(new_include->name, value, sizeof(new_include->name)-1);
3095 strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
3096 c = new_include->rname;
3097 /* Strip off timing info */
3098 while(*c && (*c != '|')) c++;
3099 /* Process if it's there */
3101 build_timing(new_include, c+1);
3104 new_include->next = NULL;
3105 new_include->registrar = registrar;
3107 /* ... try to lock this context ... */
3108 if (ast_mutex_lock(&con->lock)) {
3114 /* ... go to last include and check if context is already included too... */
3117 if (!strcasecmp(i->name, new_include->name)) {
3119 ast_mutex_unlock(&con->lock);
3127 /* ... include new context into context list, unlock, return */
3129 il->next = new_include;