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);
1803 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1805 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1806 strcpy(c->exten, "h");
1808 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1809 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1810 /* Something bad happened, or a hangup has been requested. */
1812 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1813 else if (option_verbose > 1)
1814 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1821 pbx_destroy(c->pbx);
1823 if (res != AST_PBX_KEEPALIVE)
1828 static void *pbx_thread(void *data)
1830 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1831 answer this channel and get it going. The setjmp stuff is fairly
1832 confusing, but necessary to get smooth transitions between
1833 the execution of different applications (without the use of
1834 additional threads) */
1835 struct ast_channel *c = data;
1841 int ast_pbx_start(struct ast_channel *c)
1844 pthread_attr_t attr;
1846 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1850 /* Start a new thread, and get something handling this channel. */
1851 pthread_attr_init(&attr);
1852 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1853 if (pthread_create(&t, &attr, pbx_thread, c)) {
1854 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1861 * This function locks contexts list by &conlist, search for the rigt context
1862 * structure, leave context list locked and call ast_context_remove_include2
1863 * which removes include, unlock contexts list and return ...
1865 int ast_context_remove_include(char *context, char *include, char *registrar)
1867 struct ast_context *c;
1869 if (ast_lock_contexts()) return -1;
1871 /* walk contexts and search for the right one ...*/
1872 c = ast_walk_contexts(NULL);
1874 /* we found one ... */
1875 if (!strcmp(ast_get_context_name(c), context)) {
1877 /* remove include from this context ... */
1878 ret = ast_context_remove_include2(c, include, registrar);
1880 ast_unlock_contexts();
1882 /* ... return results */
1885 c = ast_walk_contexts(c);
1888 /* we can't find the right one context */
1889 ast_unlock_contexts();
1894 * When we call this function, &conlock lock must be locked, because when
1895 * we giving *con argument, some process can remove/change this context
1896 * and after that there can be segfault.
1898 * This function locks given context, removes include, unlock context and
1901 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1903 struct ast_include *i, *pi = NULL;
1905 if (ast_mutex_lock(&con->lock)) return -1;
1910 /* find our include */
1911 if (!strcmp(i->name, include) &&
1912 (!strcmp(i->registrar, registrar) || !registrar)) {
1913 /* remove from list */
1917 con->includes = i->next;
1918 /* free include and return */
1920 ast_mutex_unlock(&con->lock);
1927 /* we can't find the right include */
1928 ast_mutex_unlock(&con->lock);
1933 * This function locks contexts list by &conlist, search for the rigt context
1934 * structure, leave context list locked and call ast_context_remove_switch2
1935 * which removes switch, unlock contexts list and return ...
1937 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1939 struct ast_context *c;
1941 if (ast_lock_contexts()) return -1;
1943 /* walk contexts and search for the right one ...*/
1944 c = ast_walk_contexts(NULL);
1946 /* we found one ... */
1947 if (!strcmp(ast_get_context_name(c), context)) {
1949 /* remove switch from this context ... */
1950 ret = ast_context_remove_switch2(c, sw, data, registrar);
1952 ast_unlock_contexts();
1954 /* ... return results */
1957 c = ast_walk_contexts(c);
1960 /* we can't find the right one context */
1961 ast_unlock_contexts();
1966 * When we call this function, &conlock lock must be locked, because when
1967 * we giving *con argument, some process can remove/change this context
1968 * and after that there can be segfault.
1970 * This function locks given context, removes switch, unlock context and
1973 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
1975 struct ast_sw *i, *pi = NULL;
1977 if (ast_mutex_lock(&con->lock)) return -1;
1982 /* find our switch */
1983 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
1984 (!strcmp(i->registrar, registrar) || !registrar)) {
1985 /* remove from list */
1989 con->alts = i->next;
1990 /* free switch and return */
1992 ast_mutex_unlock(&con->lock);
1999 /* we can't find the right switch */
2000 ast_mutex_unlock(&con->lock);
2005 * This functions lock contexts list, search for the right context,
2006 * call ast_context_remove_extension2, unlock contexts list and return.
2007 * In this function we are using
2009 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2011 struct ast_context *c;
2013 if (ast_lock_contexts()) return -1;
2015 /* walk contexts ... */
2016 c = ast_walk_contexts(NULL);
2018 /* ... search for the right one ... */
2019 if (!strcmp(ast_get_context_name(c), context)) {
2020 /* ... remove extension ... */
2021 int ret = ast_context_remove_extension2(c, extension, priority,
2023 /* ... unlock contexts list and return */
2024 ast_unlock_contexts();
2027 c = ast_walk_contexts(c);
2030 /* we can't find the right context */
2031 ast_unlock_contexts();
2036 * When do you want to call this function, make sure that &conlock is locked,
2037 * because some process can handle with your *con context before you lock
2040 * This functionc locks given context, search for the right extension and
2041 * fires out all peer in this extensions with given priority. If priority
2042 * is set to 0, all peers are removed. After that, unlock context and
2045 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2047 struct ast_exten *exten, *prev_exten = NULL;
2049 if (ast_mutex_lock(&con->lock)) return -1;
2051 /* go through all extensions in context and search the right one ... */
2055 /* look for right extension */
2056 if (!strcmp(exten->exten, extension) &&
2057 (!strcmp(exten->registrar, registrar) || !registrar)) {
2058 struct ast_exten *peer;
2060 /* should we free all peers in this extension? (priority == 0)? */
2061 if (priority == 0) {
2062 /* remove this extension from context list */
2064 prev_exten->next = exten->next;
2066 con->root = exten->next;
2068 /* fire out all peers */
2073 if (!peer->priority==PRIORITY_HINT)
2074 ast_remove_hint(peer);
2076 peer->datad(peer->data);
2082 ast_mutex_unlock(&con->lock);
2085 /* remove only extension with exten->priority == priority */
2086 struct ast_exten *previous_peer = NULL;
2090 /* is this our extension? */
2091 if (peer->priority == priority &&
2092 (!strcmp(peer->registrar, registrar) || !registrar)) {
2093 /* we are first priority extension? */
2094 if (!previous_peer) {
2095 /* exists previous extension here? */
2097 /* yes, so we must change next pointer in
2098 * previous connection to next peer
2101 prev_exten->next = peer->peer;
2102 peer->peer->next = exten->next;
2104 prev_exten->next = exten->next;
2106 /* no previous extension, we are first
2107 * extension, so change con->root ...
2110 con->root = peer->peer;
2112 con->root = exten->next;
2115 /* we are not first priority in extension */
2116 previous_peer->peer = peer->peer;
2119 /* now, free whole priority extension */
2120 if (peer->priority==PRIORITY_HINT)
2121 ast_remove_hint(peer);
2122 peer->datad(peer->data);
2125 ast_mutex_unlock(&con->lock);
2128 /* this is not right extension, skip to next peer */
2129 previous_peer = peer;
2134 ast_mutex_unlock(&con->lock);
2140 exten = exten->next;
2143 /* we can't find right extension */
2144 ast_mutex_unlock(&con->lock);
2149 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2151 struct ast_app *tmp, *prev, *cur;
2153 if (ast_mutex_lock(&applock)) {
2154 ast_log(LOG_ERROR, "Unable to lock application list\n");
2159 if (!strcasecmp(app, tmp->name)) {
2160 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2161 ast_mutex_unlock(&applock);
2166 tmp = malloc(sizeof(struct ast_app));
2168 memset(tmp, 0, sizeof(struct ast_app));
2169 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2170 tmp->execute = execute;
2171 tmp->synopsis = synopsis;
2172 tmp->description = description;
2173 /* Store in alphabetical order */
2177 if (strcasecmp(tmp->name, cur->name) < 0)
2183 tmp->next = prev->next;
2190 ast_log(LOG_WARNING, "Out of memory\n");
2191 ast_mutex_unlock(&applock);
2194 if (option_verbose > 1)
2195 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2196 ast_mutex_unlock(&applock);
2200 int ast_register_switch(struct ast_switch *sw)
2202 struct ast_switch *tmp, *prev=NULL;
2203 if (ast_mutex_lock(&switchlock)) {
2204 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2209 if (!strcasecmp(tmp->name, sw->name))
2215 ast_mutex_unlock(&switchlock);
2216 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2224 ast_mutex_unlock(&switchlock);
2228 void ast_unregister_switch(struct ast_switch *sw)
2230 struct ast_switch *tmp, *prev=NULL;
2231 if (ast_mutex_lock(&switchlock)) {
2232 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2239 prev->next = tmp->next;
2241 switches = tmp->next;
2248 ast_mutex_unlock(&switchlock);
2252 * Help for CLI commands ...
2254 static char show_application_help[] =
2255 "Usage: show application <application> [<application> [<application> [...]]]\n"
2256 " Describes a particular application.\n";
2258 static char show_applications_help[] =
2259 "Usage: show applications\n"
2260 " List applications which are currently available.\n";
2262 static char show_dialplan_help[] =
2263 "Usage: show dialplan [exten@][context]\n"
2266 static char show_switches_help[] =
2267 "Usage: show switches\n"
2268 " Show registered switches\n";
2271 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2276 * 'show application' CLI command implementation functions ...
2280 * There is a possibility to show informations about more than one
2281 * application at one time. You can type 'show application Dial Echo' and
2282 * you will see informations about these two applications ...
2284 static char *complete_show_application(char *line, char *word,
2290 /* try to lock applications list ... */
2291 if (ast_mutex_lock(&applock)) {
2292 ast_log(LOG_ERROR, "Unable to lock application list\n");
2296 /* ... walk all applications ... */
2299 /* ... check if word matches this application ... */
2300 if (!strncasecmp(word, a->name, strlen(word))) {
2301 /* ... if this is right app serve it ... */
2302 if (++which > state) {
2303 char *ret = strdup(a->name);
2304 ast_mutex_unlock(&applock);
2311 /* no application match */
2312 ast_mutex_unlock(&applock);
2316 static int handle_show_application(int fd, int argc, char *argv[])
2320 int app, no_registered_app = 1;
2322 if (argc < 3) return RESULT_SHOWUSAGE;
2324 /* try to lock applications list ... */
2325 if (ast_mutex_lock(&applock)) {
2326 ast_log(LOG_ERROR, "Unable to lock application list\n");
2330 /* ... go through all applications ... */
2333 /* ... compare this application name with all arguments given
2334 * to 'show application' command ... */
2335 for (app = 2; app < argc; app++) {
2336 if (!strcasecmp(a->name, argv[app])) {
2337 no_registered_app = 0;
2339 /* ... one of our applications, show info ...*/
2340 snprintf(buf, sizeof(buf),
2341 "\n -= Info about application '%s' =- \n\n"
2342 "[Synopsis]:\n %s\n\n"
2343 "[Description]:\n%s\n",
2345 a->synopsis ? a->synopsis : "Not available",
2346 a->description ? a-> description : "Not available");
2353 ast_mutex_unlock(&applock);
2355 /* we found at least one app? no? */
2356 if (no_registered_app) {
2357 ast_cli(fd, "Your application(s) is (are) not registered\n");
2358 return RESULT_FAILURE;
2361 return RESULT_SUCCESS;
2364 static int handle_show_switches(int fd, int argc, char *argv[])
2366 struct ast_switch *sw;
2368 ast_cli(fd, "There are no registered alternative switches\n");
2369 return RESULT_SUCCESS;
2371 /* ... we have applications ... */
2372 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2373 if (ast_mutex_lock(&switchlock)) {
2374 ast_log(LOG_ERROR, "Unable to lock switches\n");
2379 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2382 ast_mutex_unlock(&switchlock);
2383 return RESULT_SUCCESS;
2387 * 'show applications' CLI command implementation functions ...
2389 static int handle_show_applications(int fd, int argc, char *argv[])
2393 /* try to lock applications list ... */
2394 if (ast_mutex_lock(&applock)) {
2395 ast_log(LOG_ERROR, "Unable to lock application list\n");
2399 /* ... go to first application ... */
2402 /* ... have we got at least one application (first)? no? */
2404 ast_cli(fd, "There is no registered applications\n");
2405 ast_mutex_unlock(&applock);
2409 /* ... we have applications ... */
2410 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2412 /* ... go through all applications ... */
2414 /* ... show informations about applications ... */
2415 ast_cli(fd," %15s: %s\n",
2417 a->synopsis ? a->synopsis : "<Synopsis not available>");
2421 /* ... unlock and return */
2422 ast_mutex_unlock(&applock);
2424 return RESULT_SUCCESS;
2428 * 'show dialplan' CLI command implementation functions ...
2430 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2433 struct ast_context *c;
2436 /* we are do completion of [exten@]context on second position only */
2437 if (pos != 2) return NULL;
2439 /* try to lock contexts list ... */
2440 if (ast_lock_contexts()) {
2441 ast_log(LOG_ERROR, "Unable to lock context list\n");
2445 /* ... walk through all contexts ... */
2446 c = ast_walk_contexts(NULL);
2448 /* ... word matches context name? yes? ... */
2449 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2450 /* ... for serve? ... */
2451 if (++which > state) {
2452 /* ... yes, serve this context name ... */
2453 char *ret = strdup(ast_get_context_name(c));
2454 ast_unlock_contexts();
2458 c = ast_walk_contexts(c);
2461 /* ... unlock and return */
2462 ast_unlock_contexts();
2466 static int handle_show_dialplan(int fd, int argc, char *argv[])
2468 struct ast_context *c;
2469 char *exten = NULL, *context = NULL;
2470 int context_existence = 0, extension_existence = 0;
2472 if (argc != 3 && argc != 2) return -1;
2474 /* we obtain [exten@]context? if yes, split them ... */
2476 char *splitter = argv[2];
2477 /* is there a '@' character? */
2478 if (strchr(argv[2], '@')) {
2479 /* yes, split into exten & context ... */
2480 exten = strsep(&splitter, "@");
2483 /* check for length and change to NULL if !strlen() */
2484 if (!strlen(exten)) exten = NULL;
2485 if (!strlen(context)) context = NULL;
2488 /* no '@' char, only context given */
2490 if (!strlen(context)) context = NULL;
2494 /* try to lock contexts */
2495 if (ast_lock_contexts()) {
2496 ast_cli(LOG_WARNING, "Failed to lock contexts list\n");
2497 return RESULT_FAILURE;
2500 /* walk all contexts ... */
2501 c = ast_walk_contexts(NULL);
2503 /* show this context? */
2505 !strcmp(ast_get_context_name(c), context)) {
2506 context_existence = 1;
2508 /* try to lock context before walking in ... */
2509 if (!ast_lock_context(c)) {
2510 struct ast_exten *e;
2511 struct ast_include *i;
2512 struct ast_ignorepat *ip;
2514 char buf[256], buf2[256];
2515 int context_info_printed = 0;
2517 /* are we looking for exten too? if yes, we print context
2518 * if we our extension only
2521 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2522 ast_get_context_name(c), ast_get_context_registrar(c));
2523 context_info_printed = 1;
2526 /* walk extensions ... */
2527 e = ast_walk_context_extensions(c, NULL);
2529 struct ast_exten *p;
2531 /* looking for extension? is this our extension? */
2533 strcmp(ast_get_extension_name(e), exten))
2535 /* we are looking for extension and it's not our
2536 * extension, so skip to next extension */
2537 e = ast_walk_context_extensions(c, e);
2541 extension_existence = 1;
2543 /* may we print context info? */
2544 if (!context_info_printed) {
2545 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2546 ast_get_context_name(c),
2547 ast_get_context_registrar(c));
2548 context_info_printed = 1;
2551 /* write extension name and first peer */
2552 bzero(buf, sizeof(buf));
2553 snprintf(buf, sizeof(buf), "'%s' =>",
2554 ast_get_extension_name(e));
2556 snprintf(buf2, sizeof(buf2),
2558 ast_get_extension_priority(e),
2559 ast_get_extension_app(e),
2560 (char *)ast_get_extension_app_data(e));
2562 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2563 ast_get_extension_registrar(e));
2565 /* walk next extension peers */
2566 p = ast_walk_extension_priorities(e, e);
2568 bzero((void *)buf2, sizeof(buf2));
2570 snprintf(buf2, sizeof(buf2),
2572 ast_get_extension_priority(p),
2573 ast_get_extension_app(p),
2574 (char *)ast_get_extension_app_data(p));
2576 ast_cli(fd," %-17s %-45s [%s]\n",
2578 ast_get_extension_registrar(p));
2580 p = ast_walk_extension_priorities(e, p);
2582 e = ast_walk_context_extensions(c, e);
2585 /* include & ignorepat we all printing if we are not
2586 * looking for exact extension
2589 if (ast_walk_context_extensions(c, NULL))
2592 /* walk included and write info ... */
2593 i = ast_walk_context_includes(c, NULL);
2595 bzero(buf, sizeof(buf));
2596 snprintf(buf, sizeof(buf), "'%s'",
2597 ast_get_include_name(i));
2598 ast_cli(fd, " Include => %-45s [%s]\n",
2599 buf, ast_get_include_registrar(i));
2600 i = ast_walk_context_includes(c, i);
2603 /* walk ignore patterns and write info ... */
2604 ip = ast_walk_context_ignorepats(c, NULL);
2606 bzero(buf, sizeof(buf));
2607 snprintf(buf, sizeof(buf), "'%s'",
2608 ast_get_ignorepat_name(ip));
2609 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2610 buf, ast_get_ignorepat_registrar(ip));
2611 ip = ast_walk_context_ignorepats(c, ip);
2613 sw = ast_walk_context_switches(c, NULL);
2615 bzero(buf, sizeof(buf));
2616 snprintf(buf, sizeof(buf), "'%s/%s'",
2617 ast_get_switch_name(sw),
2618 ast_get_switch_data(sw));
2619 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2620 buf, ast_get_switch_registrar(sw));
2621 sw = ast_walk_context_switches(c, sw);
2625 ast_unlock_context(c);
2627 /* if we print something in context, make an empty line */
2628 if (context_info_printed) ast_cli(fd, "\n");
2631 c = ast_walk_contexts(c);
2633 ast_unlock_contexts();
2635 /* check for input failure and throw some error messages */
2636 if (context && !context_existence) {
2637 ast_cli(fd, "There is no existence of '%s' context\n",
2639 return RESULT_FAILURE;
2642 if (exten && !extension_existence) {
2644 ast_cli(fd, "There is no existence of %s@%s extension\n",
2648 "There is no existence of '%s' extension in all contexts\n",
2650 return RESULT_FAILURE;
2654 return RESULT_SUCCESS;
2658 * CLI entries for upper commands ...
2660 static struct ast_cli_entry show_applications_cli =
2661 { { "show", "applications", NULL },
2662 handle_show_applications, "Shows registered applications",
2663 show_applications_help };
2665 static struct ast_cli_entry show_application_cli =
2666 { { "show", "application", NULL },
2667 handle_show_application, "Describe a specific application",
2668 show_application_help, complete_show_application };
2670 static struct ast_cli_entry show_dialplan_cli =
2671 { { "show", "dialplan", NULL },
2672 handle_show_dialplan, "Show dialplan",
2673 show_dialplan_help, complete_show_dialplan_context };
2675 static struct ast_cli_entry show_switches_cli =
2676 { { "show", "switches", NULL },
2677 handle_show_switches, "Show alternative switches",
2678 show_switches_help, NULL };
2680 int ast_unregister_application(char *app) {
2681 struct ast_app *tmp, *tmpl = NULL;
2682 if (ast_mutex_lock(&applock)) {
2683 ast_log(LOG_ERROR, "Unable to lock application list\n");
2688 if (!strcasecmp(app, tmp->name)) {
2690 tmpl->next = tmp->next;
2693 if (option_verbose > 1)
2694 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2695 ast_mutex_unlock(&applock);
2701 ast_mutex_unlock(&applock);
2705 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2707 struct ast_context *tmp, **local_contexts;
2709 local_contexts = &contexts;
2710 ast_mutex_lock(&conlock);
2712 local_contexts = extcontexts;
2714 tmp = *local_contexts;
2716 if (!strcasecmp(tmp->name, name)) {
2717 ast_mutex_unlock(&conlock);
2718 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2720 ast_mutex_unlock(&conlock);
2725 tmp = malloc(sizeof(struct ast_context));
2727 memset(tmp, 0, sizeof(struct ast_context));
2728 ast_mutex_init(&tmp->lock);
2729 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2731 tmp->registrar = registrar;
2732 tmp->next = *local_contexts;
2733 tmp->includes = NULL;
2734 tmp->ignorepats = NULL;
2735 *local_contexts = tmp;
2737 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2738 else if (option_verbose > 2)
2739 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2741 ast_log(LOG_WARNING, "Out of memory\n");
2744 ast_mutex_unlock(&conlock);
2748 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
2750 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2751 struct ast_context *tmp, *lasttmp = NULL;
2753 ast_mutex_lock(&conlock);
2755 __ast_context_destroy(NULL,registrar,0);
2762 __ast_context_destroy(tmp,tmp->registrar,0);
2768 lasttmp->next = contexts;
2769 contexts = *extcontexts;
2770 *extcontexts = NULL;
2772 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2773 ast_mutex_unlock(&conlock);
2779 * EBUSY - can't lock
2780 * ENOENT - no existence of context
2782 int ast_context_add_include(char *context, char *include, char *registrar)
2784 struct ast_context *c;
2786 if (ast_lock_contexts()) {
2791 /* walk contexts ... */
2792 c = ast_walk_contexts(NULL);
2794 /* ... search for the right one ... */
2795 if (!strcmp(ast_get_context_name(c), context)) {
2796 int ret = ast_context_add_include2(c, include, registrar);
2797 /* ... unlock contexts list and return */
2798 ast_unlock_contexts();
2801 c = ast_walk_contexts(c);
2804 /* we can't find the right context */
2805 ast_unlock_contexts();
2813 while(*c && (*c != '|')) c++; \
2814 if (*c) { *c = '\0'; c++; } else c = NULL; \
2817 static void get_timerange(struct ast_include *i, char *times)
2825 //start disabling all times, fill the fields with 0's, as they may contain garbage
2826 memset(i->minmask, 0, sizeof(i->minmask));
2828 /* Star is all times */
2829 if (!strlen(times) || !strcmp(times, "*")) {
2831 i->minmask[x] = (1 << 30) - 1;
2834 /* Otherwise expect a range */
2835 e = strchr(times, '-');
2837 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2842 while(*e && !isdigit(*e)) e++;
2844 ast_log(LOG_WARNING, "Invalid time range. Assuming no time.\n");
2847 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2848 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", times);
2851 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2852 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", e);
2855 s1 = s1 * 30 + s2/2;
2856 if ((s1 < 0) || (s1 >= 24*30)) {
2857 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2860 e1 = e1 * 30 + e2/2;
2861 if ((e1 < 0) || (e2 >= 24*30)) {
2862 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2865 /* Go through the time and enable each appropriate bit */
2866 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2867 i->minmask[x/30] |= (1 << (x % 30));
2869 /* Do the last one */
2870 i->minmask[x/30] |= (1 << (x % 30));
2875 static char *days[] =
2886 static unsigned int get_dow(char *dow)
2889 /* The following line is coincidence, really! */
2892 /* Check for all days */
2893 if (!strlen(dow) || !strcmp(dow, "*"))
2894 return (1 << 7) - 1;
2895 /* Get start and ending days */
2896 c = strchr(dow, '-');
2902 /* Find the start */
2904 while((s < 7) && strcasecmp(dow, days[s])) s++;
2906 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2911 while((e < 7) && strcasecmp(c, days[e])) e++;
2913 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2919 for (x=s;x!=e;x = (x + 1) % 7) {
2927 static unsigned int get_day(char *day)
2930 /* The following line is coincidence, really! */
2933 /* Check for all days */
2934 if (!strlen(day) || !strcmp(day, "*")) {
2935 mask = (1 << 30) + ((1 << 30) - 1);
2938 /* Get start and ending days */
2939 c = strchr(day, '-');
2944 /* Find the start */
2945 if (sscanf(day, "%d", &s) != 1) {
2946 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2949 if ((s < 1) || (s > 31)) {
2950 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2955 if (sscanf(c, "%d", &e) != 1) {
2956 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2959 if ((e < 1) || (e > 31)) {
2960 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2967 for (x=s;x!=e;x = (x + 1) % 31) {
2974 static char *months[] =
2990 static unsigned int get_month(char *mon)
2993 /* The following line is coincidence, really! */
2996 /* Check for all days */
2997 if (!strlen(mon) || !strcmp(mon, "*"))
2998 return (1 << 12) - 1;
2999 /* Get start and ending days */
3000 c = strchr(mon, '-');
3005 /* Find the start */
3007 while((s < 12) && strcasecmp(mon, months[s])) s++;
3009 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3014 while((e < 12) && strcasecmp(mon, months[e])) e++;
3016 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3022 for (x=s;x!=e;x = (x + 1) % 12) {
3030 static void build_timing(struct ast_include *i, char *info)
3033 /* Check for empty just in case */
3037 /* Assume everything except time */
3038 i->monthmask = (1 << 12) - 1;
3039 i->daymask = (1 << 30) - 1 + (1 << 30);
3040 i->dowmask = (1 << 7) - 1;
3041 /* Avoid using str tok */
3043 /* Info has the time range, start with that */
3044 get_timerange(i, info);
3049 /* Now check for day of week */
3050 i->dowmask = get_dow(info);
3056 /* Now check for the day of the month */
3057 i->daymask = get_day(info);
3062 /* And finally go for the month */
3063 i->monthmask = get_month(info);
3068 * ENOMEM - out of memory
3069 * EBUSY - can't lock
3070 * EEXIST - already included
3071 * EINVAL - there is no existence of context for inclusion
3073 int ast_context_add_include2(struct ast_context *con, char *value,
3076 struct ast_include *new_include;
3078 struct ast_include *i, *il = NULL; /* include, include_last */
3080 /* allocate new include structure ... */
3081 if (!(new_include = malloc(sizeof(struct ast_include)))) {
3082 ast_log(LOG_WARNING, "Out of memory\n");
3087 /* ... fill in this structure ... */
3088 memset(new_include, 0, sizeof(struct ast_include));
3089 strncpy(new_include->name, value, sizeof(new_include->name)-1);
3090 strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
3091 c = new_include->rname;
3092 /* Strip off timing info */
3093 while(*c && (*c != '|')) c++;
3094 /* Process if it's there */
3096 build_timing(new_include, c+1);
3099 new_include->next = NULL;
3100 new_include->registrar = registrar;
3102 /* ... try to lock this context ... */
3103 if (ast_mutex_lock(&con->lock)) {
3109 /* ... go to last include and check if context is already included too... */
3112 if (!strcasecmp(i->name, new_include->name)) {
3114 ast_mutex_unlock(&con->lock);
3122 /* ... include new context into context list, unlock, return */
3124 il->next = new_include;
3126 con->includes = new_include;
3127 if (option_verbose > 2)
3128 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3129 ast_mutex_unlock(&con->lock);
3136 * EBUSY - can't lock
3137 * ENOENT - no existence of context
3139 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
3141 struct ast_context *c;
3143 if (ast_lock_contexts()) {
3148 /* walk contexts ... */
3149 c = ast_walk_contexts(NULL);
3151 /* ... search for the right one ... */
3152 if (!strcmp(ast_get_context_name(c), context)) {
3153 int ret = ast_context_add_switch2(c, sw, data, registrar);
3154 /* ... unlock contexts list and return */
3155 ast_unlock_contexts();
3158 c = ast_walk_contexts(c);
3161 /* we can't find the right context */
3162 ast_unlock_contexts();
3169 * ENOMEM - out of memory
3170 * EBUSY - can't lock
3171 * EEXIST - already included
3172 * EINVAL - there is no existence of context for inclusion
3174 int ast_context_add_switch2(struct ast_context *con, char *value,
3175 char *data, char *registrar)
3177 struct ast_sw *new_sw;
3178 struct ast_sw *i, *il = NULL; /* sw, sw_last */
3180 /* allocate new sw structure ... */
3181 if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
3182 ast_log(LOG_WARNING, "Out of memory\n");
3187 /* ... fill in this structure ... */
3188 memset(new_sw, 0, sizeof(struct ast_sw));
3189 strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
3191 strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
3193 strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
3194 new_sw->next = NULL;
3195 new_sw->registrar = registrar;
3197 /* ... try to lock this context ... */
3198 if (ast_mutex_lock(&con->lock)) {
3204 /* ... go to last sw and check if context is already swd too... */
3207 if (!strcasecmp(i->name, new_sw->name)) {
3209 ast_mutex_unlock(&con->lock);
3217 /* ... sw new context into context list, unlock, return */
3222 if (option_verbose > 2)
3223 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
3224 ast_mutex_unlock(&con->lock);
3230 * EBUSY - can't lock
3231 * ENOENT - there is not context existence
3233 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
3235 struct ast_context *c;
3237 if (ast_lock_contexts()) {
3242 c = ast_walk_contexts(NULL);
3244 if (!strcmp(ast_get_context_name(c), context)) {
3245 int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
3246 ast_unlock_contexts();
3249 c = ast_walk_contexts(c);
3252 ast_unlock_contexts();
3257 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
3259 struct ast_ignorepat *ip, *ipl = NULL;
3261 if (ast_mutex_lock(&con->lock)) {
3266 ip = con->ignorepats;
3268 if (!strcmp(ip->pattern, ignorepat) &&
3269 (registrar == ip->registrar || !registrar)) {
3271 ipl->next = ip->next;
3274 con->ignorepats = ip->next;
3277 ast_mutex_unlock(&con->lock);
3280 ipl = ip; ip = ip->next;
3283 ast_mutex_unlock(&con->lock);
3289 * EBUSY - can't lock
3290 * ENOENT - there is no existence of context
3292 int ast_context_add_ignorepat(char *con, char *value, char *registrar)
3294 struct ast_context *c;
3296 if (ast_lock_contexts()) {
3301 c = ast_walk_contexts(NULL);
3303 if (!strcmp(ast_get_context_name(c), con)) {
3304 int ret = ast_context_add_ignorepat2(c, value, registrar);
3305 ast_unlock_contexts();
3308 c = ast_walk_contexts(c);
3311 ast_unlock_contexts();
3316 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
3318 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
3319 ignorepat = malloc(sizeof(struct ast_ignorepat));
3321 ast_log(LOG_WARNING, "Out of memory\n");
3325 memset(ignorepat, 0, sizeof(struct ast_ignorepat));
3326 strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
3327 ignorepat->next = NULL;
3328 ignorepat->registrar = registrar;
3329 ast_mutex_lock(&con->lock);
3330 ignorepatc = con->ignorepats;
3332 ignorepatl = ignorepatc;
3333 if (!strcasecmp(ignorepatc->pattern, value)) {
3335 ast_mutex_unlock(&con->lock);
3339 ignorepatc = ignorepatc->next;
3342 ignorepatl->next = ignorepat;
3344 con->ignorepats = ignorepat;
3345 ast_mutex_unlock(&con->lock);
3350 int ast_ignore_pattern(char *context, char *pattern)
3352 struct ast_context *con;
3353 struct ast_ignorepat *pat;
3354 con = ast_context_find(context);
3356 pat = con->ignorepats;
3358 if (ast_extension_match(pat->pattern, pattern))
3367 * EBUSY - can't lock
3368 * ENOENT - no existence of context
3371 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
3372 char *application, void *data, void (*datad)(void *), char *registrar)
3374 struct ast_context *c;
3376 if (ast_lock_contexts()) {
3381 c = ast_walk_contexts(NULL);
3383 if (!strcmp(context, ast_get_context_name(c))) {
3384 int ret = ast_add_extension2(c, replace, extension, priority, callerid,
3385 application, data, datad, registrar);
3386 ast_unlock_contexts();
3389 c = ast_walk_contexts(c);
3392 ast_unlock_contexts();
3397 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority, int needlock)
3401 ast_mutex_lock(&chan->lock);
3403 /* This channel is currently in the PBX */
3404 if (context && strlen(context))
3405 strncpy(chan->context, context, sizeof(chan->context) - 1);
3406 if (exten && strlen(exten))
3407 strncpy(chan->exten, exten, sizeof(chan->context) - 1);
3409 chan->priority = priority - 1;
3410 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
3412 ast_mutex_unlock(&chan->lock);
3414 /* In order to do it when the channel doesn't really exist within
3415 the PBX, we have to make a new channel, masquerade, and start the PBX
3416 at the new location */
3417 struct ast_channel *tmpchan;
3418 struct ast_frame *f;
3419 tmpchan = ast_channel_alloc(0);
3421 snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
3422 ast_setstate(tmpchan, chan->_state);
3423 /* Make formats okay */
3424 tmpchan->readformat = chan->readformat;
3425 tmpchan->writeformat = chan->writeformat;
3426 /* Setup proper location */
3427 if (context && strlen(context))
3428 strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
3430 strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
3431 if (exten && strlen(exten))
3432 strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
3434 strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
3436 tmpchan->priority = priority;
3438 tmpchan->priority = chan->priority;
3440 ast_mutex_unlock(&chan->lock);
3442 /* Masquerade into temp channel */
3443 ast_channel_masquerade(tmpchan, chan);
3445 /* Make the masquerade happen by reading a frame from the tmp channel */
3446 f = ast_read(tmpchan);
3449 /* Start the PBX going on our stolen channel */
3450 if (ast_pbx_start(tmpchan)) {
3451 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
3452 ast_hangup(tmpchan);
3458 ast_mutex_unlock(&chan->lock);
3464 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
3466 struct ast_channel *chan;
3467 chan = ast_channel_walk(NULL);
3469 if (!strcasecmp(channame, chan->name))
3471 chan = ast_channel_walk(chan);
3474 return ast_async_goto(chan, context, exten, priority, 1);
3478 static void ext_strncpy(char *dst, char *src, int len)
3481 while(*src && (count < len - 1)) {
3484 //otherwise exten => [a-b],1,... doesn't work
3499 * EBUSY - can't lock
3500 * EEXIST - extension with the same priority exist and no replace is set
3503 int ast_add_extension2(struct ast_context *con,
3504 int replace, char *extension, int priority, char *callerid,
3505 char *application, void *data, void (*datad)(void *),
3509 #define LOG do { if (option_debug) {\
3510 if (tmp->matchcid) { \
3511 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
3513 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
3515 } else if (option_verbose > 2) { \
3516 if (tmp->matchcid) { \
3517 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
3519 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
3524 * This is a fairly complex routine. Different extensions are kept
3525 * in order by the extension number. Then, extensions of different
3526 * priorities (same extension) are kept in a list, according to the
3529 struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
3531 /* Be optimistic: Build the extension structure first */
3532 tmp = malloc(sizeof(struct ast_exten));
3534 memset(tmp, 0, sizeof(struct ast_exten));
3535 ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
3536 tmp->priority = priority;
3538 ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
3541 strcpy(tmp->cidmatch, "");
3544 strncpy(tmp->app, application, sizeof(tmp->app)-1);
3548 tmp->registrar = registrar;
3552 ast_log(LOG_WARNING, "Out of memory\n");
3556 if (ast_mutex_lock(&con->lock)) {
3558 /* And properly destroy the data */
3560 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
3566 res= strcasecmp(e->exten, extension);
3568 if (!e->matchcid && !tmp->matchcid)
3570 else if (tmp->matchcid && !e->matchcid)
3572 else if (e->matchcid && !tmp->matchcid)
3575 res = strcasecmp(e->cidmatch, tmp->cidmatch);
3578 /* We have an exact match, now we find where we are
3579 and be sure there's no duplicates */
3581 if (e->priority == tmp->priority) {
3582 /* Can't have something exactly the same. Is this a
3583 replacement? If so, replace, otherwise, bonk. */
3586 /* We're in the peer list, insert ourselves */
3588 tmp->peer = e->peer;
3590 /* We're the first extension. Take over e's functions */
3592 tmp->next = e->next;
3593 tmp->peer = e->peer;
3595 /* We're the very first extension. */
3597 tmp->next = e->next;
3598 tmp->peer = e->peer;
3600 if (tmp->priority == PRIORITY_HINT)
3601 ast_change_hint(e,tmp);
3602 /* Destroy the old one */
3605 ast_mutex_unlock(&con->lock);
3606 if (tmp->priority == PRIORITY_HINT)
3607 ast_change_hint(e, tmp);
3608 /* And immediately return success. */